| // Copyright (c) 2025, the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| package backport; | |
| import com.android.tools.r8.TestParameters; | |
| import com.android.tools.r8.TestRuntime.CfVm; | |
| import com.android.tools.r8.desugar.backports.AbstractBackportTest; | |
| import com.android.tools.r8.utils.AndroidApiLevel; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.Parameterized; | |
| import org.junit.runners.Parameterized.Parameters; | |
| @RunWith(Parameterized.class) | |
| public final class StrictMathJava21Test extends AbstractBackportTest { | |
| @Parameters(name = "{0}") | |
| public static Iterable<?> data() { | |
| return getTestParameters() | |
| .withDexRuntimes() | |
| .withCfRuntimesStartingFromIncluding(CfVm.JDK21) | |
| .withAllApiLevelsAlsoForCf() | |
| .build(); | |
| } | |
| public StrictMathJava21Test(TestParameters parameters) { | |
| super(parameters, StrictMath.class, Main.class); | |
| registerTarget(AndroidApiLevel.V, 92); | |
| } | |
| static final class Main extends MiniAssert { | |
| public static void main(String[] args) { | |
| testClampInt(); | |
| testClampLong(); | |
| testClampDouble(); | |
| testClampFloat(); | |
| testCeilDivIntInt(); | |
| testCeilDivIntIntExact(); | |
| testCeilDivLongLong(); | |
| testCeilDivLongLongExact(); | |
| testCeilDivLongInt(); | |
| testCeilModIntInt(); | |
| testCeilModLongLong(); | |
| testCeilModLongInt(); | |
| testDivideExactInt(); | |
| testDivideExactLong(); | |
| testFloorDivExactInt(); | |
| testFloorDivExactLong(); | |
| testUnsignedMultiplyHigh(); | |
| } | |
| private static void testClampInt() { | |
| assertEquals(1, StrictMath.clamp(1, 0, 5)); | |
| assertEquals(0, StrictMath.clamp(-1, 0, 5)); | |
| assertEquals(5, StrictMath.clamp(10, 0, 5)); | |
| try { | |
| StrictMath.clamp(1, 10, 5); | |
| fail("Should have thrown"); | |
| } catch (IllegalArgumentException ignored) { | |
| } | |
| } | |
| private static void testClampLong() { | |
| assertEquals(1, StrictMath.clamp(1L, 0L, 5L)); | |
| assertEquals(0, StrictMath.clamp(-1L, 0L, 5L)); | |
| assertEquals(5, StrictMath.clamp(10L, 0L, 5L)); | |
| try { | |
| StrictMath.clamp(1L, 10L, 5L); | |
| fail("Should have thrown"); | |
| } catch (IllegalArgumentException ignored) { | |
| } | |
| } | |
| private static void testClampDouble() { | |
| assertEquals(1.0, StrictMath.clamp(1.0, 0.0, 5.0)); | |
| assertEquals(0.0, StrictMath.clamp(-1.0, 0.0, 5.0)); | |
| assertEquals(5.0, StrictMath.clamp(10.0, 0.0, 5.0)); | |
| try { | |
| StrictMath.clamp(1.0, 10.0, 5.0); | |
| fail("Should have thrown"); | |
| } catch (IllegalArgumentException ignored) { | |
| } | |
| // Check for -/+0.0. | |
| assertEquals(0.0, StrictMath.clamp(-0.0, 0.0, 1.0)); | |
| assertEquals(0.0, StrictMath.clamp(0.0, -0.0, 1.0)); | |
| assertEquals(-0.0, StrictMath.clamp(-0.0, -1.0, 0.0)); | |
| assertEquals(-0.0, StrictMath.clamp(0.0, -1.0, -0.0)); | |
| // Check for NaN. | |
| assertEquals(Double.NaN, StrictMath.clamp(Double.NaN, 0.0, 1.0)); | |
| try { | |
| StrictMath.clamp(1.0, Double.NaN, 5.0); | |
| fail("Should have thrown"); | |
| } catch (IllegalArgumentException ignored) { | |
| } | |
| try { | |
| StrictMath.clamp(1.0, 10.0, Double.NaN); | |
| fail("Should have thrown"); | |
| } catch (IllegalArgumentException ignored) { | |
| } | |
| } | |
| private static void testClampFloat() { | |
| assertEquals(1.0f, StrictMath.clamp(1.0f, 0.0f, 5.0f)); | |
| assertEquals(0.0f, StrictMath.clamp(-1.0f, 0.0f, 5.0f)); | |
| assertEquals(5.0f, StrictMath.clamp(10.0f, 0.0f, 5.0f)); | |
| try { | |
| StrictMath.clamp(1.0f, 10.0f, 5.0f); | |
| fail("Should have thrown"); | |
| } catch (IllegalArgumentException ignored) { | |
| } | |
| // Check for -/+0.0f. | |
| assertEquals(0.0f, StrictMath.clamp(-0.0f, 0.0f, 1.0f)); | |
| assertEquals(0.0f, StrictMath.clamp(0.0f, -0.0f, 1.0f)); | |
| assertEquals(-0.0f, StrictMath.clamp(-0.0f, -1.0f, 0.0f)); | |
| assertEquals(-0.0f, StrictMath.clamp(0.0f, -1.0f, -0.0f)); | |
| // Check for NaN. | |
| assertEquals(Float.NaN, StrictMath.clamp(Float.NaN, 0.0f, 1.0f)); | |
| try { | |
| StrictMath.clamp(1.0f, Float.NaN, 5.0f); | |
| fail("Should have thrown"); | |
| } catch (IllegalArgumentException ignored) { | |
| } | |
| try { | |
| StrictMath.clamp(1.0f, 10.0f, Float.NaN); | |
| fail("Should have thrown"); | |
| } catch (IllegalArgumentException ignored) { | |
| } | |
| } | |
| private static void testCeilDivIntInt() { | |
| assertEquals(1, StrictMath.ceilDiv(7, 7)); | |
| assertEquals(-1, StrictMath.ceilDiv(-7, 7)); | |
| assertEquals(1, StrictMath.ceilDiv(3, 7)); | |
| assertEquals(0, StrictMath.ceilDiv(-3, 7)); | |
| assertEquals(-2147483648, StrictMath.ceilDiv(Integer.MIN_VALUE, -1)); | |
| } | |
| private static void testCeilDivIntIntExact() { | |
| assertEquals(1, StrictMath.ceilDivExact(7, 7)); | |
| assertEquals(-1, StrictMath.ceilDivExact(-7, 7)); | |
| assertEquals(1, StrictMath.ceilDivExact(3, 7)); | |
| assertEquals(0, StrictMath.ceilDivExact(-3, 7)); | |
| try { | |
| StrictMath.ceilDivExact(Integer.MIN_VALUE, -1); | |
| fail("Should have thrown"); | |
| } catch (ArithmeticException ae) { | |
| } | |
| } | |
| private static void testCeilDivLongLong() { | |
| assertEquals(1L, StrictMath.ceilDiv(7L, 7L)); | |
| assertEquals(-1L, StrictMath.ceilDiv(-7L, 7L)); | |
| assertEquals(1L, StrictMath.ceilDiv(3L, 7L)); | |
| assertEquals(0, StrictMath.ceilDiv(-3L, 7L)); | |
| assertEquals(-9223372036854775808L, StrictMath.ceilDiv(Long.MIN_VALUE, -1L)); | |
| } | |
| private static void testCeilDivLongLongExact() { | |
| assertEquals(1L, StrictMath.ceilDivExact(7L, 7L)); | |
| assertEquals(-1L, StrictMath.ceilDivExact(-7L, 7L)); | |
| assertEquals(1L, StrictMath.ceilDivExact(3L, 7L)); | |
| assertEquals(0, StrictMath.ceilDivExact(-3L, 7L)); | |
| try { | |
| StrictMath.ceilDivExact(Long.MIN_VALUE, -1L); | |
| fail("Should have thrown"); | |
| } catch (ArithmeticException ae) { | |
| } | |
| } | |
| private static void testCeilDivLongInt() { | |
| assertEquals(1L, StrictMath.ceilDiv(7L, 7)); | |
| assertEquals(-1L, StrictMath.ceilDiv(-7L, 7)); | |
| assertEquals(1L, StrictMath.ceilDiv(3L, 7)); | |
| assertEquals(0, StrictMath.ceilDiv(-3L, 7)); | |
| assertEquals(-9223372036854775808L, StrictMath.ceilDiv(Long.MIN_VALUE, -1)); | |
| } | |
| private static void testCeilModIntInt() { | |
| assertEquals(0, StrictMath.ceilMod(7, 7)); | |
| assertEquals(0, StrictMath.ceilMod(-7, 7)); | |
| assertEquals(-4, StrictMath.ceilMod(3, 7)); | |
| assertEquals(-3, StrictMath.ceilMod(-3, 7)); | |
| assertEquals(0, StrictMath.ceilMod(Integer.MIN_VALUE, -1)); | |
| } | |
| private static void testCeilModLongLong() { | |
| assertEquals(0L, StrictMath.ceilMod(7L, 7L)); | |
| assertEquals(0L, StrictMath.ceilMod(-7L, 7L)); | |
| assertEquals(-4L, StrictMath.ceilMod(3L, 7L)); | |
| assertEquals(-3L, StrictMath.ceilMod(-3L, 7L)); | |
| assertEquals(0L, StrictMath.ceilMod(Long.MIN_VALUE, -1L)); | |
| } | |
| private static void testCeilModLongInt() { | |
| assertEquals(0L, StrictMath.ceilMod(7L, 7)); | |
| assertEquals(0L, StrictMath.ceilMod(-7L, 7)); | |
| assertEquals(-4L, StrictMath.ceilMod(3L, 7)); | |
| assertEquals(-3L, StrictMath.ceilMod(-3L, 7)); | |
| assertEquals(0L, StrictMath.ceilMod(Long.MIN_VALUE, -1)); | |
| } | |
| private static void testDivideExactInt() { | |
| assertEquals(1, StrictMath.divideExact(7, 7)); | |
| assertEquals(-1, StrictMath.divideExact(-7, 7)); | |
| assertEquals(0, StrictMath.divideExact(3, 7)); | |
| assertEquals(0, StrictMath.divideExact(-3, 7)); | |
| try { | |
| StrictMath.divideExact(Integer.MIN_VALUE, -1); | |
| fail("Should have thrown"); | |
| } catch (ArithmeticException ae) { | |
| } | |
| } | |
| private static void testDivideExactLong() { | |
| assertEquals(1L, StrictMath.divideExact(7L, 7L)); | |
| assertEquals(-1L, StrictMath.divideExact(-7L, 7L)); | |
| assertEquals(0, StrictMath.divideExact(3L, 7L)); | |
| assertEquals(0, StrictMath.divideExact(-3L, 7L)); | |
| try { | |
| StrictMath.divideExact(Long.MIN_VALUE, -1L); | |
| fail("Should have thrown"); | |
| } catch (ArithmeticException ae) { | |
| } | |
| } | |
| private static void testFloorDivExactInt() { | |
| assertEquals(1, StrictMath.floorDivExact(7, 7)); | |
| assertEquals(-1, StrictMath.floorDivExact(-7, 7)); | |
| assertEquals(0, StrictMath.floorDivExact(3, 7)); | |
| assertEquals(-1, StrictMath.floorDivExact(-3, 7)); | |
| try { | |
| StrictMath.floorDivExact(Integer.MIN_VALUE, -1); | |
| fail("Should have thrown"); | |
| } catch (ArithmeticException ae) { | |
| } | |
| } | |
| private static void testFloorDivExactLong() { | |
| assertEquals(1L, StrictMath.floorDivExact(7L, 7L)); | |
| assertEquals(-1L, StrictMath.floorDivExact(-7L, 7L)); | |
| assertEquals(0L, StrictMath.floorDivExact(3L, 7L)); | |
| assertEquals(-1L, StrictMath.floorDivExact(-3L, 7L)); | |
| try { | |
| StrictMath.floorDivExact(Long.MIN_VALUE, -1L); | |
| fail("Should have thrown"); | |
| } catch (ArithmeticException ae) { | |
| } | |
| } | |
| private static void testUnsignedMultiplyHigh() { | |
| assertEquals( | |
| 31696182030193L, StrictMath.unsignedMultiplyHigh(8222222222222222L, 71111111111111111L)); | |
| assertEquals( | |
| 71079414929080917L, | |
| StrictMath.unsignedMultiplyHigh(-8222222222222222L, 71111111111111111L)); | |
| } | |
| } | |
| } |