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