Migrate YANG inputs for yang-data-impl
[yangtools.git] / data / yang-data-impl / src / test / java / org / opendaylight / yangtools / yang / data / impl / codec / YT1442Test.java
1 /*
2  * Copyright (c) 2022 PANTHEON.tech, s.r.o. 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.data.impl.codec;
9
10 import static org.hamcrest.CoreMatchers.instanceOf;
11 import static org.hamcrest.MatcherAssert.assertThat;
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertThrows;
14
15 import java.util.List;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.junit.BeforeClass;
18 import org.junit.Test;
19 import org.opendaylight.yangtools.yang.common.Decimal64;
20 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
21 import org.opendaylight.yangtools.yang.common.ErrorTag;
22 import org.opendaylight.yangtools.yang.common.ErrorType;
23 import org.opendaylight.yangtools.yang.common.QName;
24 import org.opendaylight.yangtools.yang.data.api.codec.YangInvalidValueException;
25 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
26 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
27
28 public class YT1442Test {
29     private static DecimalStringCodec codec;
30
31     @BeforeClass
32     public static void beforeClass() {
33         final var foo = YangParserTestUtils.parseYang("""
34             module yt1442 {
35               namespace yt1442;
36               prefix yt1442;
37
38               leaf foo {
39                 type decimal64 {
40                   fraction-digits 2;
41                   range 10.0..100.0 {
42                     error-app-tag model-defined-app-tag;
43                     error-message model-defined-message;
44                   }
45                 }
46               }
47             }""")
48             .getDataChildByName(QName.create("yt1442", "foo"));
49         assertThat(foo, instanceOf(LeafSchemaNode.class));
50
51         final TypeDefinitionAwareCodec<?, ?> tmp = TypeDefinitionAwareCodec.from(((LeafSchemaNode) foo).getType());
52         assertThat(tmp, instanceOf(DecimalStringCodec.class));
53         codec = (DecimalStringCodec) tmp;
54     }
55
56     @Test
57     public void testTen() {
58         final var ten = codec.deserialize("10.00");
59         assertDecimal(1000, ten);
60         assertEquals("10.0", codec.serialize(ten));
61     }
62
63     @Test
64     public void testFifty() {
65         final var fifty = codec.deserialize("50.00");
66         assertDecimal(5000, fifty);
67         assertEquals("50.0", codec.serialize(fifty));
68     }
69
70     @Test
71     public void testHundred() {
72         final var hundred = codec.deserialize("100.00");
73         assertDecimal(10000, hundred);
74         assertEquals("100.0", codec.serialize(hundred));
75     }
76
77     @Test
78     public void testNegativeOutOfRange() {
79         assertYIVE("Value '-10.0' is not in required ranges [[10.0..100.0]]", "-10.00");
80         assertYIVE("Value '-50.0' is not in required ranges [[10.0..100.0]]", "-50.00");
81         assertYIVE("Value '-100.0' is not in required ranges [[10.0..100.0]]", "-100.00");
82     }
83
84     @Test
85     public void testPositiveOutOfRange() {
86         assertYIVE("Value '9.99' is not in required ranges [[10.0..100.0]]", "9.99");
87         assertYIVE("Value '100.01' is not in required ranges [[10.0..100.0]]", "100.01");
88     }
89
90     @Test
91     public void testTooLargeFractionPart() {
92         final var ex = assertThrows(IllegalArgumentException.class, () -> codec.deserialize("100.001"));
93         assertEquals("Value '100.001' does not match required fraction-digits", ex.getMessage());
94         final var cause = ex.getCause();
95         assertThat(cause, instanceOf(ArithmeticException.class));
96         assertEquals("Decreasing scale of 100.001 to 2 requires rounding", cause.getMessage());
97     }
98
99     @Test
100     public void testTooLargeIntegralPart() {
101         final var ex = assertThrows(IllegalArgumentException.class, () -> codec.deserialize("92233720368547759.0"));
102         assertEquals("Value '92233720368547759.0' does not match required fraction-digits", ex.getMessage());
103         final var cause = ex.getCause();
104         assertThat(cause, instanceOf(ArithmeticException.class));
105         assertEquals("Increasing scale of 92233720368547759.0 to 2 would overflow", cause.getMessage());
106     }
107
108     private static void assertDecimal(final long unscaledValue, final Object obj) {
109         assertThat(obj, instanceOf(Decimal64.class));
110         final var actual = (Decimal64) obj;
111         assertEquals(2, actual.scale());
112         assertEquals(unscaledValue, actual.unscaledValue());
113     }
114
115     private static void assertYIVE(final String expectedMessage, final @NonNull String input) {
116         final var ex = assertThrows(YangInvalidValueException.class, () -> codec.deserialize(input));
117         assertEquals(expectedMessage, ex.getMessage());
118
119         final var errors = ex.getNetconfErrors();
120         assertEquals(1, errors.size());
121         final var error = errors.get(0);
122         assertEquals(ErrorSeverity.ERROR, error.severity());
123         assertEquals(ErrorType.APPLICATION, error.type());
124         assertEquals(ErrorTag.INVALID_VALUE, error.tag());
125         assertEquals("model-defined-app-tag", error.appTag());
126         assertEquals("model-defined-message", error.message());
127         assertEquals(List.of(), error.info());
128     }
129 }