Fix PathExpressionParser predicate path handling
[yangtools.git] / yang / yang-parser-rfc7950 / src / test / java / org / opendaylight / yangtools / yang / parser / rfc7950 / stmt / path / PathExpressionParserTest.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o.  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.rfc7950.stmt.path;
9
10 import static org.hamcrest.Matchers.containsString;
11 import static org.hamcrest.Matchers.isA;
12 import static org.hamcrest.Matchers.startsWith;
13 import static org.junit.Assert.assertEquals;
14 import static org.junit.Assert.assertSame;
15 import static org.junit.Assert.assertThat;
16 import static org.junit.Assert.assertTrue;
17 import static org.junit.Assert.fail;
18 import static org.mockito.Mockito.doReturn;
19
20 import com.google.common.collect.ImmutableList;
21 import com.google.common.collect.ImmutableSet;
22 import org.junit.Before;
23 import org.junit.Test;
24 import org.junit.runner.RunWith;
25 import org.mockito.Mock;
26 import org.mockito.junit.MockitoJUnitRunner;
27 import org.opendaylight.yangtools.yang.common.UnqualifiedQName;
28 import org.opendaylight.yangtools.yang.model.api.PathExpression;
29 import org.opendaylight.yangtools.yang.model.api.PathExpression.DerefSteps;
30 import org.opendaylight.yangtools.yang.model.api.PathExpression.LocationPathSteps;
31 import org.opendaylight.yangtools.yang.model.api.PathExpression.Steps;
32 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
33 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
34 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
35 import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
36 import org.opendaylight.yangtools.yang.xpath.api.YangFunction;
37 import org.opendaylight.yangtools.yang.xpath.api.YangFunctionCallExpr;
38 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath;
39 import org.opendaylight.yangtools.yang.xpath.api.YangLocationPath.Relative;
40 import org.opendaylight.yangtools.yang.xpath.api.YangPathExpr;
41 import org.opendaylight.yangtools.yang.xpath.api.YangQNameExpr;
42 import org.opendaylight.yangtools.yang.xpath.api.YangXPathAxis;
43
44 @RunWith(MockitoJUnitRunner.StrictStubs.class)
45 public class PathExpressionParserTest {
46     @Mock
47     private StmtContext<?, ?, ?> ctx;
48     @Mock
49     private StatementSourceReference ref;
50     private final PathExpressionParser parser = new PathExpressionParser();
51
52     @Before
53     public void before() {
54         doReturn(ref).when(ctx).getStatementSourceReference();
55     }
56
57     @Test
58     public void testDerefPath() {
59         // deref() is not valid as per RFC7950, but we tolarate it.
60         final PathExpression deref = parser.parseExpression(ctx, "deref(../id)/../type");
61
62         final Steps steps = deref.getSteps();
63         assertThat(steps, isA(DerefSteps.class));
64
65         final DerefSteps derefSteps = (DerefSteps) steps;
66         assertEquals(YangLocationPath.relative(YangXPathAxis.PARENT.asStep(),
67             YangXPathAxis.CHILD.asStep(UnqualifiedQName.of("type"))), derefSteps.getRelativePath());
68         assertEquals(YangLocationPath.relative(YangXPathAxis.PARENT.asStep(),
69             YangXPathAxis.CHILD.asStep(UnqualifiedQName.of("id"))), derefSteps.getDerefArgument());
70     }
71
72     @Test
73     public void testInvalidLeftParent() {
74         try {
75             parser.parseExpression(ctx, "foo(");
76             fail("SourceException should have been thrown");
77         } catch (SourceException e) {
78             assertSame(ref, e.getSourceReference());
79             assertThat(e.getMessage(), startsWith("extraneous input '(' expecting "));
80             assertThat(e.getMessage(), containsString(" at 1:3 [at "));
81         }
82     }
83
84     @Test
85     public void testInvalidRightParent() {
86         try {
87             parser.parseExpression(ctx, "foo)");
88             fail("SourceException should have been thrown");
89         } catch (SourceException e) {
90             assertSame(ref, e.getSourceReference());
91             assertThat(e.getMessage(), startsWith("extraneous input ')' expecting "));
92             assertThat(e.getMessage(), containsString(" at 1:3 [at "));
93         }
94     }
95
96     @Test
97     public void testInvalidIdentifier() {
98         try {
99             parser.parseExpression(ctx, "foo%");
100             fail("SourceException should have been thrown");
101         } catch (SourceException e) {
102             assertSame(ref, e.getSourceReference());
103             assertThat(e.getMessage(), startsWith("token recognition error at: '%' at 1:3 [at "));
104         }
105     }
106
107     @Test
108     public void testCurrentPredicateParsing() {
109         final YangLocationPath path = ((LocationPathSteps) parser.parseExpression(ctx,
110             "/device_types/device_type[type = current()/../type_text]/desc").getSteps()).getLocationPath();
111         assertTrue(path.isAbsolute());
112
113         path.getSteps();
114         assertEquals(ImmutableList.of(
115             YangXPathAxis.CHILD.asStep(UnqualifiedQName.of("device_types")),
116             YangXPathAxis.CHILD.asStep(UnqualifiedQName.of("device_type"),
117                 ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(
118                     YangQNameExpr.of(UnqualifiedQName.of("type")),
119                     YangPathExpr.of(YangFunctionCallExpr.of(YangFunction.CURRENT.getIdentifier()), Relative.relative(
120                         YangXPathAxis.PARENT.asStep(),
121                         YangXPathAxis.CHILD.asStep(UnqualifiedQName.of("type_text"))))))),
122             YangXPathAxis.CHILD.asStep(UnqualifiedQName.of("desc"))), path.getSteps());
123     }
124 }