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.*;
16 import java.text.SimpleDateFormat;
17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.Date;
20 import java.util.HashSet;
21 import java.util.List;
23 import org.antlr.v4.runtime.Token;
24 import org.antlr.v4.runtime.tree.ParseTree;
25 import org.antlr.v4.runtime.tree.TerminalNode;
26 import org.junit.Before;
27 import org.junit.Test;
28 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Augment_stmtContext;
29 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_add_stmtContext;
30 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviate_delete_stmtContext;
31 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Deviation_stmtContext;
32 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Import_stmtContext;
33 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Include_stmtContext;
34 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Module_stmtContext;
35 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Namespace_stmtContext;
36 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Prefix_stmtContext;
37 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Revision_date_stmtContext;
38 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.Status_argContext;
39 import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.StringContext;
40 import org.opendaylight.yangtools.yang.parser.impl.BasicValidations;
41 import org.opendaylight.yangtools.yang.parser.impl.ValidationUtil;
42 import org.opendaylight.yangtools.yang.parser.impl.YangModelBasicValidationListener;
43 import org.opendaylight.yangtools.yang.parser.util.YangValidationException;
45 import com.google.common.collect.Sets;
47 public class YangModelValidationTest {
49 private YangModelBasicValidationListener valid;
54 valid = new YangModelBasicValidationListener();
58 public void testPrefixes() {
59 Prefix_stmtContext pref = mockStatement(Prefix_stmtContext.class, "unique1");
60 Module_stmtContext module = mockStatement(Module_stmtContext.class, "module1");
61 addChild(module, pref);
63 valid.enterPrefix_stmt(pref);
65 pref = mockStatement(Prefix_stmtContext.class, "unique1");
66 module = mockStatement(Module_stmtContext.class, "module1");
67 addChild(module, pref);
70 valid.enterPrefix_stmt(pref);
71 } catch (Exception e) {
75 fail("Validation Exception should have occured");
79 public void testNamespace() {
81 Namespace_stmtContext namespace = mockStatement(Namespace_stmtContext.class, "http://test.parsing.uri.com");
82 Module_stmtContext module = mockStatement(Module_stmtContext.class, "module1");
83 addChild(module, namespace);
85 valid.enterNamespace_stmt(namespace);
87 namespace = mockStatement(Namespace_stmtContext.class, "invalid uri");
88 module = mockStatement(Module_stmtContext.class, "module1");
89 addChild(module, namespace);
92 valid.enterNamespace_stmt(namespace);
93 } catch (YangValidationException e) {
94 assertThat(e.getMessage(), containsString("Namespace:invalid uri cannot be parsed as URI"));
98 fail("Validation Exception should have occured");
102 public void testImports() {
103 Import_stmtContext impor = mockImport("unique1", "p1");
104 Module_stmtContext mod = mockStatement(Module_stmtContext.class, "module1");
105 addChild(mod, impor);
107 valid.enterImport_stmt(impor);
109 impor = mockImport("unique1", "p2");
110 mod = mockStatement(Module_stmtContext.class, "module1");
111 addChild(mod, impor);
114 valid.enterImport_stmt(impor);
115 } catch (YangValidationException e) {
116 assertThat(e.getMessage(), containsString("Import:unique1 not unique"));
120 fail("Validation Exception should have occured");
124 public void testIncludes() {
125 Include_stmtContext incl = mockInclude("unique1");
126 Module_stmtContext mod = mockStatement(Module_stmtContext.class, "module1");
128 valid.enterInclude_stmt(incl);
130 incl = mockInclude("unique1");
131 mod = mockStatement(Module_stmtContext.class, "module1");
135 valid.enterInclude_stmt(incl);
136 } catch (YangValidationException e) {
137 assertThat(e.getMessage(), containsString("Include:unique1 not unique in (sub)module"));
141 fail("Validation Exception should have occured");
145 public void testIdentifierMatching() {
146 List<String> ids = new ArrayList<String>();
148 ids.add("_ok98-.87.-.8...88-asdAD");
157 for (String id : ids) {
159 Module_stmtContext module = mock(Module_stmtContext.class);
160 Token token = mock(Token.class);
161 when(module.getStart()).thenReturn(token);
162 BasicValidations.checkIdentifierInternal(module, id);
163 } catch (YangValidationException e) {
168 assertThat(thrown, is(3));
171 @Test(expected = YangValidationException.class)
172 public void testAugument() {
173 Augment_stmtContext augument = mockStatement(Augment_stmtContext.class, "/a:*abc/a:augument1");
174 Module_stmtContext mod1 = mockStatement(Module_stmtContext.class, "mod1");
175 addChild(mod1, augument);
177 Token token = mock(Token.class);
178 when(augument.getStart()).thenReturn(token);
181 valid.enterAugment_stmt(augument);
182 } catch (YangValidationException e) {
185 containsString("Schema node id:/a:*abc/a:augument1 not in required format, details:Prefixed id:a:*abc not in required format"));
191 public void testDeviate() {
192 Deviation_stmtContext ctx = mockStatement(Deviation_stmtContext.class, "deviations");
193 Deviate_add_stmtContext add = mockStatement(Deviate_add_stmtContext.class, "add");
194 Deviate_delete_stmtContext del = mockStatement(Deviate_delete_stmtContext.class, "delete");
199 valid.enterDeviation_stmt(ctx);
201 HashSet<Class<? extends ParseTree>> types = Sets.newHashSet();
202 types.add(Deviate_add_stmtContext.class);
203 types.add(Deviate_delete_stmtContext.class);
205 int count = ValidationUtil.countPresentChildrenOfType(ctx, types);
206 assertThat(count, is(2));
209 @Test(expected = YangValidationException.class)
210 public void testStatus() throws Exception {
211 Status_argContext status = mockStatement(Status_argContext.class, "unknown");
213 valid.enterStatus_arg(status);
214 } catch (YangValidationException e) {
215 assertThat(e.getMessage(), containsString("illegal value for Status statement, only permitted:"));
220 private Import_stmtContext mockImport(String name, String prefixName) {
221 Import_stmtContext impor = mockStatement(Import_stmtContext.class, name);
223 Prefix_stmtContext prefix = mockStatement(Prefix_stmtContext.class, prefixName);
224 Revision_date_stmtContext revDate = mockStatement(Revision_date_stmtContext.class, getFormattedDate());
226 addChild(impor, prefix);
227 addChild(impor, revDate);
231 static String getFormattedDate() {
232 return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
235 private Include_stmtContext mockInclude(String name) {
236 Include_stmtContext incl = mockStatement(Include_stmtContext.class, name);
238 Revision_date_stmtContext revDate = mockStatement(Revision_date_stmtContext.class, getFormattedDate());
240 addChild(incl, revDate);
244 static void mockName(ParseTree stmt, String name) {
245 doReturn(1).when(stmt).getChildCount();
247 TerminalNode terminalNode = mock(TerminalNode.class);
248 doReturn(name).when(terminalNode).getText();
250 StringContext nameCtx = mock(StringContext.class);
251 doReturn(nameCtx).when(stmt).getChild(0);
252 doReturn(terminalNode).when(nameCtx).getChild(0);
253 doReturn(name).when(terminalNode).getText();
255 doReturn(Collections.singletonList(terminalNode)).when(nameCtx).STRING();
258 static <T extends ParseTree> T mockStatement(Class<T> stmtType, String name) {
259 T stmt = stmtType.cast(mock(stmtType));
261 doReturn(0).when(stmt).getChildCount();
264 mockName(stmt, name);
268 static void addChild(ParseTree parent, 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();