2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.impl;
10 import static org.hamcrest.CoreMatchers.containsString;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertThat;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.mock;
16 import static org.mockito.Mockito.when;
18 import com.google.common.collect.Sets;
20 import java.text.SimpleDateFormat;
21 import java.util.ArrayList;
22 import java.util.Collections;
23 import java.util.Date;
24 import java.util.HashSet;
25 import java.util.List;
27 import org.antlr.v4.runtime.Token;
28 import org.antlr.v4.runtime.tree.ParseTree;
29 import org.antlr.v4.runtime.tree.TerminalNode;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Augment_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviation_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
40 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
41 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
42 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
43 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.StringContext;
44 import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
46 public class YangModelValidationTest {
48 private YangModelBasicValidationListener valid;
53 valid = new YangModelBasicValidationListener();
57 public void testPrefixes() {
58 Prefix_stmtContext pref = mockStatement(Prefix_stmtContext.class, "unique1");
59 Module_stmtContext module = mockStatement(Module_stmtContext.class, "module1");
60 addChild(module, pref);
62 valid.enterPrefix_stmt(pref);
64 pref = mockStatement(Prefix_stmtContext.class, "unique1");
65 module = mockStatement(Module_stmtContext.class, "module1");
66 addChild(module, pref);
69 valid.enterPrefix_stmt(pref);
70 } catch (Exception e) {
74 fail("Validation Exception should have occured");
78 public void testNamespace() {
80 Namespace_stmtContext namespace = mockStatement(Namespace_stmtContext.class, "http://test.parsing.uri.com");
81 Module_stmtContext module = mockStatement(Module_stmtContext.class, "module1");
82 addChild(module, namespace);
84 valid.enterNamespace_stmt(namespace);
86 namespace = mockStatement(Namespace_stmtContext.class, "invalid uri");
87 module = mockStatement(Module_stmtContext.class, "module1");
88 addChild(module, namespace);
91 valid.enterNamespace_stmt(namespace);
92 } catch (YangValidationException e) {
93 assertThat(e.getMessage(), containsString("Namespace:invalid uri cannot be parsed as URI"));
97 fail("Validation Exception should have occured");
101 public void testImports() {
102 Import_stmtContext impor = mockImport("unique1", "p1");
103 Module_stmtContext mod = mockStatement(Module_stmtContext.class, "module1");
104 addChild(mod, impor);
106 valid.enterImport_stmt(impor);
108 impor = mockImport("unique1", "p2");
109 mod = mockStatement(Module_stmtContext.class, "module1");
110 addChild(mod, impor);
113 valid.enterImport_stmt(impor);
114 } catch (YangValidationException e) {
115 assertThat(e.getMessage(), containsString("Import:unique1 not unique"));
119 fail("Validation Exception should have occured");
123 public void testIncludes() {
124 Include_stmtContext incl = mockInclude("unique1");
125 Module_stmtContext mod = mockStatement(Module_stmtContext.class, "module1");
127 valid.enterInclude_stmt(incl);
129 incl = mockInclude("unique1");
130 mod = mockStatement(Module_stmtContext.class, "module1");
134 valid.enterInclude_stmt(incl);
135 } catch (YangValidationException e) {
136 assertThat(e.getMessage(), containsString("Include:unique1 not unique in (sub)module"));
140 fail("Validation Exception should have occured");
144 public void testIdentifierMatching() {
145 List<String> ids = new ArrayList<String>();
147 ids.add("_ok98-.87.-.8...88-asdAD");
156 for (String id : ids) {
158 Module_stmtContext module = mock(Module_stmtContext.class);
159 Token token = mock(Token.class);
160 when(module.getStart()).thenReturn(token);
161 BasicValidations.checkIdentifierInternal(module, id);
162 } catch (YangValidationException e) {
167 assertEquals(3, thrown);
170 @Test(expected = YangValidationException.class)
171 public void testAugument() {
172 Augment_stmtContext augument = mockStatement(Augment_stmtContext.class, "/a:*abc/a:augument1");
173 Module_stmtContext mod1 = mockStatement(Module_stmtContext.class, "mod1");
174 addChild(mod1, augument);
176 Token token = mock(Token.class);
177 when(augument.getStart()).thenReturn(token);
180 valid.enterAugment_stmt(augument);
181 } catch (YangValidationException e) {
184 containsString("Schema node id:/a:*abc/a:augument1 not in required format, details:Prefixed id:a:*abc not in required format"));
190 public void testDeviate() {
191 Deviation_stmtContext ctx = mockStatement(Deviation_stmtContext.class, "deviations");
192 Deviate_add_stmtContext add = mockStatement(Deviate_add_stmtContext.class, "add");
193 Deviate_delete_stmtContext del = mockStatement(Deviate_delete_stmtContext.class, "delete");
198 valid.enterDeviation_stmt(ctx);
200 HashSet<Class<? extends ParseTree>> types = Sets.newHashSet();
201 types.add(Deviate_add_stmtContext.class);
202 types.add(Deviate_delete_stmtContext.class);
204 int count = ValidationUtil.countPresentChildrenOfType(ctx, types);
205 assertEquals(2, count);
208 @Test(expected = YangValidationException.class)
209 public void testStatus() throws Exception {
210 Status_argContext status = mockStatement(Status_argContext.class, "unknown");
212 valid.enterStatus_arg(status);
213 } catch (YangValidationException e) {
214 assertThat(e.getMessage(), containsString("illegal value for Status statement, only permitted:"));
219 private Import_stmtContext mockImport(final String name, final String prefixName) {
220 Import_stmtContext impor = mockStatement(Import_stmtContext.class, name);
222 Prefix_stmtContext prefix = mockStatement(Prefix_stmtContext.class, prefixName);
223 Revision_date_stmtContext revDate = mockStatement(Revision_date_stmtContext.class, getFormattedDate());
225 addChild(impor, prefix);
226 addChild(impor, revDate);
230 static String getFormattedDate() {
231 return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
234 private Include_stmtContext mockInclude(final String name) {
235 Include_stmtContext incl = mockStatement(Include_stmtContext.class, name);
237 Revision_date_stmtContext revDate = mockStatement(Revision_date_stmtContext.class, getFormattedDate());
239 addChild(incl, revDate);
243 static void mockName(final ParseTree stmt, final String name) {
244 doReturn(1).when(stmt).getChildCount();
246 TerminalNode terminalNode = mock(TerminalNode.class);
247 doReturn(name).when(terminalNode).getText();
249 StringContext nameCtx = mock(StringContext.class);
250 doReturn(nameCtx).when(stmt).getChild(0);
251 doReturn(terminalNode).when(nameCtx).getChild(0);
252 doReturn(name).when(terminalNode).getText();
254 doReturn(Collections.singletonList(terminalNode)).when(nameCtx).STRING();
257 static <T extends ParseTree> T mockStatement(final Class<T> stmtType, final String name) {
258 T stmt = stmtType.cast(mock(stmtType));
260 doReturn(0).when(stmt).getChildCount();
263 mockName(stmt, name);
268 static void addChild(final ParseTree parent, final 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();