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