Yang validation moved to validator package and validation listener refactored.
[controller.git] / opendaylight / sal / yang-prototype / code-generator / yang-model-parser-impl / src / test / java / org / opendaylight / controller / yang / model / validator / 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.controller.yang.model.validator;
9
10 import static org.hamcrest.core.Is.*;
11 import static org.junit.Assert.*;
12 import static org.junit.matchers.JUnitMatchers.*;
13 import static org.mockito.Mockito.*;
14
15 import java.util.ArrayList;
16 import java.util.Date;
17 import java.util.HashSet;
18 import java.util.List;
19
20 import org.antlr.v4.runtime.tree.ParseTree;
21 import org.junit.Before;
22 import org.junit.Test;
23 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Augment_stmtContext;
24 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
25 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
26 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Deviation_stmtContext;
27 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Import_stmtContext;
28 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Include_stmtContext;
29 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Module_stmtContext;
30 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Namespace_stmtContext;
31 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Prefix_stmtContext;
32 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
33 import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext;
34 import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext;
35 import org.opendaylight.controller.yang.model.parser.impl.YangModelParserListenerImpl;
36 import org.opendaylight.controller.yang.model.parser.util.YangValidationException;
37
38 import com.google.common.collect.Sets;
39
40 public class YangModelValidationTest {
41
42     private YangModelBasicValidationListener valid;
43
44     @Before
45     public void setUp() {
46
47         valid = new YangModelBasicValidationListener();
48     }
49
50     @Test
51     public void testPrefixes() {
52         Prefix_stmtContext pref = mockStatement(Prefix_stmtContext.class,
53                 "unique1");
54         Module_stmtContext module = mockStatement(Module_stmtContext.class,
55                 "module1");
56         addChild(module, pref);
57
58         valid.enterPrefix_stmt(pref);
59
60         pref = mockStatement(Prefix_stmtContext.class, "unique1");
61         module = mockStatement(Module_stmtContext.class, "module1");
62         addChild(module, pref);
63
64         try {
65             valid.enterPrefix_stmt(pref);
66         } catch (Exception e) {
67             return;
68         }
69
70         fail("Validation Exception should have occured");
71     }
72
73     @Test
74     public void testNamespace() {
75
76         Namespace_stmtContext namespace = mockStatement(
77                 Namespace_stmtContext.class, "http://test.parsing.uri.com");
78         Module_stmtContext module = mockStatement(Module_stmtContext.class,
79                 "module1");
80         addChild(module, namespace);
81
82         valid.enterNamespace_stmt(namespace);
83
84         namespace = mockStatement(Namespace_stmtContext.class, "invalid uri");
85         module = mockStatement(Module_stmtContext.class, "module1");
86         addChild(module, namespace);
87
88         try {
89             valid.enterNamespace_stmt(namespace);
90         } catch (YangValidationException e) {
91             assertThat(
92                     e.getMessage(),
93                     containsString("Namespace:invalid uri cannot be parsed as URI"));
94             return;
95         }
96
97         fail("Validation Exception should have occured");
98     }
99
100     @Test
101     public void testImports() {
102         Import_stmtContext impor = mockImport("unique1", "p1");
103         Module_stmtContext mod = mockStatement(Module_stmtContext.class,
104                 "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(),
117                     containsString("Import:unique1 not unique"));
118             return;
119         }
120
121         fail("Validation Exception should have occured");
122     }
123
124     @Test
125     public void testIncludes() {
126         Include_stmtContext incl = mockInclude("unique1");
127         Module_stmtContext mod = mockStatement(Module_stmtContext.class,
128                 "module1");
129         addChild(mod, incl);
130         valid.enterInclude_stmt(incl);
131
132         incl = mockInclude("unique1");
133         mod = mockStatement(Module_stmtContext.class, "module1");
134         addChild(mod, incl);
135
136         try {
137             valid.enterInclude_stmt(incl);
138         } catch (YangValidationException e) {
139             assertThat(e.getMessage(),
140                     containsString("Include:unique1 not unique in (sub)module"));
141             return;
142         }
143
144         fail("Validation Exception should have occured");
145     }
146
147     @Test
148     public void testIdentifierMatching() {
149         List<String> ids = new ArrayList<String>();
150         // valid
151         ids.add("_ok98-.87.-.8...88-asdAD");
152         ids.add("AA.bcd");
153         ids.add("a");
154         // invalid
155         ids.add("9aa");
156         ids.add("-");
157         ids.add(".");
158
159         int thrown = 0;
160         for (String id : ids) {
161             try {
162                 BasicValidations.checkIdentifierInternal(
163                         mock(Module_stmtContext.class), id);
164             } catch (YangValidationException e) {
165                 thrown++;
166             }
167         }
168
169         assertThat(thrown, is(3));
170     }
171
172     @Test(expected = YangValidationException.class)
173     public void testAugument() {
174         Augment_stmtContext augument = mockStatement(Augment_stmtContext.class,
175                 "/a:*abc/a:augument1");
176         Module_stmtContext mod1 = mockStatement(Module_stmtContext.class,
177                 "mod1");
178         addChild(mod1, augument);
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,
193                 "deviations");
194         Deviate_add_stmtContext add = mockStatement(
195                 Deviate_add_stmtContext.class, "add");
196         Deviate_delete_stmtContext del = mockStatement(
197                 Deviate_delete_stmtContext.class, "delete");
198
199         addChild(ctx, add);
200         addChild(ctx, del);
201
202         valid.enterDeviation_stmt(ctx);
203
204         HashSet<Class<? extends ParseTree>> types = Sets.newHashSet();
205         types.add(Deviate_add_stmtContext.class);
206         types.add(Deviate_delete_stmtContext.class);
207
208         int count = ValidationUtil.countPresentChildrenOfType(ctx, types);
209         assertThat(count, is(2));
210     }
211
212     @Test(expected = YangValidationException.class)
213     public void testStatus() throws Exception {
214         Status_argContext status = mockStatement(Status_argContext.class,
215                 "unknown");
216         try {
217             valid.enterStatus_arg(status);
218         } catch (YangValidationException e) {
219             assertThat(
220                     e.getMessage(),
221                     containsString("illegal value for Status statement, only permitted:"));
222             throw e;
223         }
224     }
225
226     private Import_stmtContext mockImport(String name, String prefixName) {
227         Import_stmtContext impor = mockStatement(Import_stmtContext.class, name);
228
229         Prefix_stmtContext prefix = mockStatement(Prefix_stmtContext.class,
230                 prefixName);
231         Revision_date_stmtContext revDate = mockStatement(
232                 Revision_date_stmtContext.class, getFormattedDate());
233
234         addChild(impor, prefix);
235         addChild(impor, revDate);
236         return impor;
237     }
238
239     static String getFormattedDate() {
240         return YangModelParserListenerImpl.simpleDateFormat.format(new Date());
241     }
242
243     private Include_stmtContext mockInclude(String name) {
244         Include_stmtContext incl = mockStatement(Include_stmtContext.class,
245                 name);
246
247         Revision_date_stmtContext revDate = mockStatement(
248                 Revision_date_stmtContext.class, getFormattedDate());
249
250         addChild(incl, revDate);
251         return incl;
252     }
253
254     static void mockName(ParseTree stmt, String name) {
255         StringContext nameCtx = mock(StringContext.class);
256         ParseTree internalName = mock(ParseTree.class);
257         doReturn(1).when(stmt).getChildCount();
258         doReturn(name).when(internalName).getText();
259         doReturn(internalName).when(nameCtx).getChild(0);
260         doReturn(nameCtx).when(stmt).getChild(0);
261     }
262
263     static <T extends ParseTree> T mockStatement(Class<T> stmtType, String name) {
264         T stmt = stmtType.cast(mock(stmtType));
265
266         doReturn(0).when(stmt).getChildCount();
267
268         if (name != null)
269             mockName(stmt, name);
270         return stmt;
271     }
272
273     static void addChild(ParseTree parent, ParseTree child) {
274         int childCount = parent.getChildCount() + 1;
275         doReturn(childCount).when(parent).getChildCount();
276         doReturn(child).when(parent).getChild(childCount - 1);
277         doReturn(parent).when(child).getParent();
278     }
279
280 }