Add Decimal64.scaleTo()
[yangtools.git] / common / yang-common / src / test / java / org / opendaylight / yangtools / yang / common / YT1440Test.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.common;
9
10 import static org.junit.jupiter.api.Assertions.assertEquals;
11 import static org.junit.jupiter.api.Assertions.assertSame;
12 import static org.junit.jupiter.api.Assertions.assertThrows;
13
14 import java.math.RoundingMode;
15 import org.junit.jupiter.api.Test;
16
17 public class YT1440Test {
18     @Test
19     public void testScaleSame() {
20         final var twenty = Decimal64.valueOf(2, 20);
21         assertSame(twenty, twenty.scaleTo(2));
22
23         // Do not tolerate null rounding even for no-op
24         assertThrows(NullPointerException.class, () -> twenty.scaleTo(2, null));
25     }
26
27     @Test
28     public void testScaleZero() {
29         final var two = Decimal64.valueOf(2, 0);
30         final var one = two.scaleTo(1);
31         assertEquals(1, one.scale());
32         assertEquals(0, one.unscaledValue());
33         final var three = two.scaleTo(3);
34         assertEquals(3, three.scale());
35         assertEquals(0, three.unscaledValue());
36     }
37
38     @Test
39     public void testScaleUpNoRemain() {
40         // Template, scale=5
41         final var two = Decimal64.valueOf(2, 20);
42
43         // scale = 5
44         final var five = two.scaleTo(5);
45         assertEquals(5, five.scale());
46         assertEquals(two, five);
47         assertEquals("20.0", five.toString());
48
49         // scale = 18 fails
50         final var ex = assertThrows(ArithmeticException.class, () -> two.scaleTo(18));
51         assertEquals("Increasing scale of 20.0 to 18 would overflow", ex.getMessage());
52     }
53
54     @Test
55     public void testScaleDownNoRemain() {
56         // Template, scale=5
57         final var five = Decimal64.valueOf(5, 20);
58
59         // scale = 2
60         final var two = five.scaleTo(2);
61         assertEquals(2, two.scale());
62         assertEquals(five, two);
63         assertEquals("20.0", two.toString());
64     }
65
66     @Test
67     public void testScaleDownPositive() {
68         final var two = Decimal64.valueOf("0.63");
69         assertEquals(2, two.scale());
70         assertEquals(63, two.unscaledValue());
71
72         // Trim '3'
73         assertScaleDown(7, two, 1, RoundingMode.UP);
74         assertScaleDown(6, two, 1, RoundingMode.DOWN);
75         assertScaleDown(7, two, 1, RoundingMode.CEILING);
76         assertScaleDown(6, two, 1, RoundingMode.FLOOR);
77         assertScaleDown(6, two, 1, RoundingMode.HALF_UP);
78         assertScaleDown(6, two, 1, RoundingMode.HALF_DOWN);
79         assertScaleDown(6, two, 1, RoundingMode.HALF_EVEN);
80
81         final var three = Decimal64.valueOf("0.635");
82         assertEquals(3, three.scale());
83         assertEquals(635, three.unscaledValue());
84
85         // Trim '5'
86         assertScaleDown(64, three, 2, RoundingMode.UP);
87         assertScaleDown(63, three, 2, RoundingMode.DOWN);
88         assertScaleDown(64, three, 2, RoundingMode.CEILING);
89         assertScaleDown(63, three, 2, RoundingMode.FLOOR);
90         assertScaleDown(64, three, 2, RoundingMode.HALF_UP);
91         assertScaleDown(63, three, 2, RoundingMode.HALF_DOWN);
92         assertScaleDown(64, three, 2, RoundingMode.HALF_EVEN);
93
94         // Trim '35'
95         assertScaleDown(7, three, 1, RoundingMode.UP);
96         assertScaleDown(6, three, 1, RoundingMode.DOWN);
97         assertScaleDown(7, three, 1, RoundingMode.CEILING);
98         assertScaleDown(6, three, 1, RoundingMode.FLOOR);
99         assertScaleDown(6, three, 1, RoundingMode.HALF_UP);
100         assertScaleDown(6, three, 1, RoundingMode.HALF_DOWN);
101         assertScaleDown(6, three, 1, RoundingMode.HALF_EVEN);
102
103         final var four = Decimal64.valueOf("0.6355");
104         assertEquals(4, four.scale());
105         assertEquals(6355, four.unscaledValue());
106
107         // Trim 55
108         assertScaleDown(64, four, 2, RoundingMode.UP);
109         assertScaleDown(63, four, 2, RoundingMode.DOWN);
110         assertScaleDown(64, four, 2, RoundingMode.CEILING);
111         assertScaleDown(63, four, 2, RoundingMode.FLOOR);
112         assertScaleDown(64, four, 2, RoundingMode.HALF_UP);
113         assertScaleDown(64, four, 2, RoundingMode.HALF_DOWN);
114         assertScaleDown(64, four, 2, RoundingMode.HALF_EVEN);
115
116         final var five = Decimal64.valueOf("0.635").scaleTo(5);
117         assertEquals(5, five.scale());
118         assertEquals(63500, five.unscaledValue());
119
120         // Trim 500
121         assertScaleDown(64, five, 2, RoundingMode.UP);
122         assertScaleDown(63, five, 2, RoundingMode.DOWN);
123         assertScaleDown(64, five, 2, RoundingMode.CEILING);
124         assertScaleDown(63, five, 2, RoundingMode.FLOOR);
125         assertScaleDown(64, five, 2, RoundingMode.HALF_UP);
126         assertScaleDown(63, five, 2, RoundingMode.HALF_DOWN);
127         assertScaleDown(64, five, 2, RoundingMode.HALF_EVEN);
128     }
129
130     @Test
131     public void testScaleDownNegative() {
132         final var two = Decimal64.valueOf("-0.63");
133         assertEquals(2, two.scale());
134         assertEquals(-63, two.unscaledValue());
135
136         // Trim '3'
137         assertScaleDown(-7, two, 1, RoundingMode.UP);
138         assertScaleDown(-6, two, 1, RoundingMode.DOWN);
139         assertScaleDown(-6, two, 1, RoundingMode.CEILING);
140         assertScaleDown(-7, two, 1, RoundingMode.FLOOR);
141         assertScaleDown(-6, two, 1, RoundingMode.HALF_UP);
142         assertScaleDown(-6, two, 1, RoundingMode.HALF_DOWN);
143         assertScaleDown(-6, two, 1, RoundingMode.HALF_EVEN);
144
145         final var three = Decimal64.valueOf("-0.635");
146         assertEquals(3, three.scale());
147         assertEquals(-635, three.unscaledValue());
148
149         // Trim '5'
150         assertScaleDown(-64, three, 2, RoundingMode.UP);
151         assertScaleDown(-63, three, 2, RoundingMode.DOWN);
152         assertScaleDown(-63, three, 2, RoundingMode.CEILING);
153         assertScaleDown(-64, three, 2, RoundingMode.FLOOR);
154         assertScaleDown(-64, three, 2, RoundingMode.HALF_UP);
155         assertScaleDown(-63, three, 2, RoundingMode.HALF_DOWN);
156         assertScaleDown(-64, three, 2, RoundingMode.HALF_EVEN);
157
158         // Trim '35'
159         assertScaleDown(-7, three, 1, RoundingMode.UP);
160         assertScaleDown(-6, three, 1, RoundingMode.DOWN);
161         assertScaleDown(-6, three, 1, RoundingMode.CEILING);
162         assertScaleDown(-7, three, 1, RoundingMode.FLOOR);
163         assertScaleDown(-6, three, 1, RoundingMode.HALF_UP);
164         assertScaleDown(-6, three, 1, RoundingMode.HALF_DOWN);
165         assertScaleDown(-6, three, 1, RoundingMode.HALF_EVEN);
166
167         final var four = Decimal64.valueOf("-0.6355");
168         assertEquals(4, four.scale());
169         assertEquals(-6355, four.unscaledValue());
170
171         // Trim 55
172         assertScaleDown(-64, four, 2, RoundingMode.UP);
173         assertScaleDown(-63, four, 2, RoundingMode.DOWN);
174         assertScaleDown(-63, four, 2, RoundingMode.CEILING);
175         assertScaleDown(-64, four, 2, RoundingMode.FLOOR);
176         assertScaleDown(-64, four, 2, RoundingMode.HALF_UP);
177         assertScaleDown(-64, four, 2, RoundingMode.HALF_DOWN);
178         assertScaleDown(-64, four, 2, RoundingMode.HALF_EVEN);
179
180         final var five = Decimal64.valueOf("-0.635").scaleTo(5);
181         assertEquals(5, five.scale());
182         assertEquals(-63500, five.unscaledValue());
183
184         // Trim 500
185         assertScaleDown(-64, five, 2, RoundingMode.UP);
186         assertScaleDown(-63, five, 2, RoundingMode.DOWN);
187         assertScaleDown(-63, five, 2, RoundingMode.CEILING);
188         assertScaleDown(-64, five, 2, RoundingMode.FLOOR);
189         assertScaleDown(-64, five, 2, RoundingMode.HALF_UP);
190         assertScaleDown(-63, five, 2, RoundingMode.HALF_DOWN);
191         assertScaleDown(-64, five, 2, RoundingMode.HALF_EVEN);
192     }
193
194     @Test
195     public void testScaleDownTrim() {
196         final var two = Decimal64.valueOf("0.63");
197         final var ex = assertThrows(ArithmeticException.class, () -> two.scaleTo(1));
198         assertEquals("Decreasing scale of 0.63 to 1 requires rounding", ex.getMessage());
199     }
200
201     private static void assertScaleDown(final long expectedUnscaled, final Decimal64 value, final int scale,
202             final RoundingMode mode) {
203         final var scaled = value.scaleTo(scale, mode);
204         assertEquals(scale, scaled.scale());
205         assertEquals(expectedUnscaled, scaled.unscaledValue());
206     }
207 }