Merge "BUG-582: pre-cache Pattern instances"
[yangtools.git] / yang / yang-parser-impl / src / test / java / org / opendaylight / yangtools / yang / parser / impl / YangModelValidationTest.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.impl;
9
10 import static org.hamcrest.core.Is.is;
11 import static org.junit.Assert.assertThat;
12 import static org.junit.Assert.fail;
13 import static org.junit.matchers.JUnitMatchers.containsString;
14 import static org.mockito.Mockito.*;
15
16 import java.text.SimpleDateFormat;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Date;
20 import java.util.HashSet;
21 import java.util.List;
22
23 import org.antlr.v4.runtime.Token;
24 import org.antlr.v4.runtime.tree.ParseTree;
25 import org.antlr.v4.runtime.tree.TerminalNode;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Augment_stmtContext;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
31 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviation_stmtContext;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.StringContext;
40 import org.opendaylight.yangtools.yang.parser.impl.BasicValidations;
41 import org.opendaylight.yangtools.yang.parser.impl.ValidationUtil;
42 import org.opendaylight.yangtools.yang.parser.impl.YangModelBasicValidationListener;
43 import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
44
45 import com.google.common.collect.Sets;
46
47 public class YangModelValidationTest {
48
49     private YangModelBasicValidationListener valid;
50
51     @Before
52     public void setUp() {
53
54         valid = new YangModelBasicValidationListener();
55     }
56
57     @Test
58     public void testPrefixes() {
59         Prefix_stmtContext pref = mockStatement(Prefix_stmtContext.class, "unique1");
60         Module_stmtContext module = mockStatement(Module_stmtContext.class, "module1");
61         addChild(module, pref);
62
63         valid.enterPrefix_stmt(pref);
64
65         pref = mockStatement(Prefix_stmtContext.class, "unique1");
66         module = mockStatement(Module_stmtContext.class, "module1");
67         addChild(module, pref);
68
69         try {
70             valid.enterPrefix_stmt(pref);
71         } catch (Exception e) {
72             return;
73         }
74
75         fail("Validation Exception should have occured");
76     }
77
78     @Test
79     public void testNamespace() {
80
81         Namespace_stmtContext namespace = mockStatement(Namespace_stmtContext.class, "http://test.parsing.uri.com");
82         Module_stmtContext module = mockStatement(Module_stmtContext.class, "module1");
83         addChild(module, namespace);
84
85         valid.enterNamespace_stmt(namespace);
86
87         namespace = mockStatement(Namespace_stmtContext.class, "invalid uri");
88         module = mockStatement(Module_stmtContext.class, "module1");
89         addChild(module, namespace);
90
91         try {
92             valid.enterNamespace_stmt(namespace);
93         } catch (YangValidationException e) {
94             assertThat(e.getMessage(), containsString("Namespace:invalid uri cannot be parsed as URI"));
95             return;
96         }
97
98         fail("Validation Exception should have occured");
99     }
100
101     @Test
102     public void testImports() {
103         Import_stmtContext impor = mockImport("unique1", "p1");
104         Module_stmtContext mod = mockStatement(Module_stmtContext.class, "module1");
105         addChild(mod, impor);
106
107         valid.enterImport_stmt(impor);
108
109         impor = mockImport("unique1", "p2");
110         mod = mockStatement(Module_stmtContext.class, "module1");
111         addChild(mod, impor);
112
113         try {
114             valid.enterImport_stmt(impor);
115         } catch (YangValidationException e) {
116             assertThat(e.getMessage(), containsString("Import:unique1 not unique"));
117             return;
118         }
119
120         fail("Validation Exception should have occured");
121     }
122
123     @Test
124     public void testIncludes() {
125         Include_stmtContext incl = mockInclude("unique1");
126         Module_stmtContext mod = mockStatement(Module_stmtContext.class, "module1");
127         addChild(mod, incl);
128         valid.enterInclude_stmt(incl);
129
130         incl = mockInclude("unique1");
131         mod = mockStatement(Module_stmtContext.class, "module1");
132         addChild(mod, incl);
133
134         try {
135             valid.enterInclude_stmt(incl);
136         } catch (YangValidationException e) {
137             assertThat(e.getMessage(), containsString("Include:unique1 not unique in (sub)module"));
138             return;
139         }
140
141         fail("Validation Exception should have occured");
142     }
143
144     @Test
145     public void testIdentifierMatching() {
146         List<String> ids = new ArrayList<String>();
147         // valid
148         ids.add("_ok98-.87.-.8...88-asdAD");
149         ids.add("AA.bcd");
150         ids.add("a");
151         // invalid
152         ids.add("9aa");
153         ids.add("-");
154         ids.add(".");
155
156         int thrown = 0;
157         for (String id : ids) {
158             try {
159                 Module_stmtContext module = mock(Module_stmtContext.class);
160                 Token token = mock(Token.class);
161                 when(module.getStart()).thenReturn(token);
162                 BasicValidations.checkIdentifierInternal(module, id);
163             } catch (YangValidationException e) {
164                 thrown++;
165             }
166         }
167
168         assertThat(thrown, is(3));
169     }
170
171     @Test(expected = YangValidationException.class)
172     public void testAugument() {
173         Augment_stmtContext augument = mockStatement(Augment_stmtContext.class, "/a:*abc/a:augument1");
174         Module_stmtContext mod1 = mockStatement(Module_stmtContext.class, "mod1");
175         addChild(mod1, augument);
176
177         Token token = mock(Token.class);
178         when(augument.getStart()).thenReturn(token);
179
180         try {
181             valid.enterAugment_stmt(augument);
182         } catch (YangValidationException e) {
183             assertThat(
184                     e.getMessage(),
185                     containsString("Schema node id:/a:*abc/a:augument1 not in required format, details:Prefixed id:a:*abc not in required format"));
186             throw e;
187         }
188     }
189
190     @Test
191     public void testDeviate() {
192         Deviation_stmtContext ctx = mockStatement(Deviation_stmtContext.class, "deviations");
193         Deviate_add_stmtContext add = mockStatement(Deviate_add_stmtContext.class, "add");
194         Deviate_delete_stmtContext del = mockStatement(Deviate_delete_stmtContext.class, "delete");
195
196         addChild(ctx, add);
197         addChild(ctx, del);
198
199         valid.enterDeviation_stmt(ctx);
200
201         HashSet<Class<? extends ParseTree>> types = Sets.newHashSet();
202         types.add(Deviate_add_stmtContext.class);
203         types.add(Deviate_delete_stmtContext.class);
204
205         int count = ValidationUtil.countPresentChildrenOfType(ctx, types);
206         assertThat(count, is(2));
207     }
208
209     @Test(expected = YangValidationException.class)
210     public void testStatus() throws Exception {
211         Status_argContext status = mockStatement(Status_argContext.class, "unknown");
212         try {
213             valid.enterStatus_arg(status);
214         } catch (YangValidationException e) {
215             assertThat(e.getMessage(), containsString("illegal value for Status statement, only permitted:"));
216             throw e;
217         }
218     }
219
220     private Import_stmtContext mockImport(String name, String prefixName) {
221         Import_stmtContext impor = mockStatement(Import_stmtContext.class, name);
222
223         Prefix_stmtContext prefix = mockStatement(Prefix_stmtContext.class, prefixName);
224         Revision_date_stmtContext revDate = mockStatement(Revision_date_stmtContext.class, getFormattedDate());
225
226         addChild(impor, prefix);
227         addChild(impor, revDate);
228         return impor;
229     }
230
231     static String getFormattedDate() {
232         return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
233     }
234
235     private Include_stmtContext mockInclude(String name) {
236         Include_stmtContext incl = mockStatement(Include_stmtContext.class, name);
237
238         Revision_date_stmtContext revDate = mockStatement(Revision_date_stmtContext.class, getFormattedDate());
239
240         addChild(incl, revDate);
241         return incl;
242     }
243
244     static void mockName(ParseTree stmt, String name) {
245         doReturn(1).when(stmt).getChildCount();
246
247         TerminalNode terminalNode = mock(TerminalNode.class);
248         doReturn(name).when(terminalNode).getText();
249
250         StringContext nameCtx = mock(StringContext.class);
251         doReturn(nameCtx).when(stmt).getChild(0);
252         doReturn(terminalNode).when(nameCtx).getChild(0);
253         doReturn(name).when(terminalNode).getText();
254
255         doReturn(Collections.singletonList(terminalNode)).when(nameCtx).STRING();
256     }
257
258     static <T extends ParseTree> T mockStatement(Class<T> stmtType, String name) {
259         T stmt = stmtType.cast(mock(stmtType));
260
261         doReturn(0).when(stmt).getChildCount();
262
263         if (name != null)
264             mockName(stmt, name);
265         return stmt;
266     }
267
268     static void addChild(ParseTree parent, ParseTree child) {
269         int childCount = parent.getChildCount() + 1;
270         doReturn(childCount).when(parent).getChildCount();
271         doReturn(child).when(parent).getChild(childCount - 1);
272         doReturn(parent).when(child).getParent();
273     }
274
275 }