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.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;
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;
44 public class YangModelValidationTest {
46 private YangModelBasicValidationListener valid;
51 valid = new YangModelBasicValidationListener();
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);
60 valid.enterPrefix_stmt(pref);
62 pref = mockStatement(Prefix_stmtContext.class, "unique1");
63 module = mockStatement(Module_stmtContext.class, "module1");
64 addChild(module, pref);
67 valid.enterPrefix_stmt(pref);
68 } catch (Exception e) {
72 fail("Validation Exception should have occured");
76 public void testNamespace() {
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);
82 valid.enterNamespace_stmt(namespace);
84 namespace = mockStatement(Namespace_stmtContext.class, "invalid uri");
85 module = mockStatement(Module_stmtContext.class, "module1");
86 addChild(module, namespace);
89 valid.enterNamespace_stmt(namespace);
90 } catch (YangValidationException e) {
91 assertThat(e.getMessage(), containsString("Namespace:invalid uri cannot be parsed as URI"));
95 fail("Validation Exception should have occured");
99 public void testImports() {
100 Import_stmtContext impor = mockImport("unique1", "p1");
101 Module_stmtContext mod = mockStatement(Module_stmtContext.class, "module1");
102 addChild(mod, impor);
104 valid.enterImport_stmt(impor);
106 impor = mockImport("unique1", "p2");
107 mod = mockStatement(Module_stmtContext.class, "module1");
108 addChild(mod, impor);
111 valid.enterImport_stmt(impor);
112 } catch (YangValidationException e) {
113 assertThat(e.getMessage(), containsString("Import:unique1 not unique"));
117 fail("Validation Exception should have occured");
121 public void testIncludes() {
122 Include_stmtContext incl = mockInclude("unique1");
123 Module_stmtContext mod = mockStatement(Module_stmtContext.class, "module1");
125 valid.enterInclude_stmt(incl);
127 incl = mockInclude("unique1");
128 mod = mockStatement(Module_stmtContext.class, "module1");
132 valid.enterInclude_stmt(incl);
133 } catch (YangValidationException e) {
134 assertThat(e.getMessage(), containsString("Include:unique1 not unique in (sub)module"));
138 fail("Validation Exception should have occured");
142 public void testIdentifierMatching() {
143 List<String> ids = new ArrayList<String>();
145 ids.add("_ok98-.87.-.8...88-asdAD");
154 for (String id : ids) {
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) {
165 assertThat(thrown, is(3));
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);
174 Token token = mock(Token.class);
175 when(augument.getStart()).thenReturn(token);
178 valid.enterAugment_stmt(augument);
179 } catch (YangValidationException e) {
182 containsString("Schema node id:/a:*abc/a:augument1 not in required format, details:Prefixed id:a:*abc not in required format"));
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");
196 valid.enterDeviation_stmt(ctx);
198 HashSet<Class<? extends ParseTree>> types = Sets.newHashSet();
199 types.add(Deviate_add_stmtContext.class);
200 types.add(Deviate_delete_stmtContext.class);
202 int count = ValidationUtil.countPresentChildrenOfType(ctx, types);
203 assertThat(count, is(2));
206 @Test(expected = YangValidationException.class)
207 public void testStatus() throws Exception {
208 Status_argContext status = mockStatement(Status_argContext.class, "unknown");
210 valid.enterStatus_arg(status);
211 } catch (YangValidationException e) {
212 assertThat(e.getMessage(), containsString("illegal value for Status statement, only permitted:"));
217 private Import_stmtContext mockImport(String name, String prefixName) {
218 Import_stmtContext impor = mockStatement(Import_stmtContext.class, name);
220 Prefix_stmtContext prefix = mockStatement(Prefix_stmtContext.class, prefixName);
221 Revision_date_stmtContext revDate = mockStatement(Revision_date_stmtContext.class, getFormattedDate());
223 addChild(impor, prefix);
224 addChild(impor, revDate);
228 static String getFormattedDate() {
229 return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
232 private Include_stmtContext mockInclude(String name) {
233 Include_stmtContext incl = mockStatement(Include_stmtContext.class, name);
235 Revision_date_stmtContext revDate = mockStatement(Revision_date_stmtContext.class, getFormattedDate());
237 addChild(incl, revDate);
241 static void mockName(ParseTree stmt, String name) {
242 doReturn(1).when(stmt).getChildCount();
244 TerminalNode terminalNode = mock(TerminalNode.class);
245 doReturn(name).when(terminalNode).getText();
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();
252 doReturn(Collections.singletonList(terminalNode)).when(nameCtx).STRING();
255 static <T extends ParseTree> T mockStatement(Class<T> stmtType, String name) {
256 T stmt = stmtType.cast(mock(stmtType));
258 doReturn(0).when(stmt).getChildCount();
261 mockName(stmt, name);
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();