1 /*
   2  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @summary test MethodHandle/VarHandle on value types
  27  * @compile -XDallowWithFieldOperator Point.java Line.java Value.java MutablePath.java MixedValues.java
  28  * @run testng/othervm -XX:+EnableValhalla SubstitutabilityTest
  29  */
  30 
  31 import java.lang.invoke.ValueBootstrapMethods;
  32 import java.util.List;
  33 
  34 import org.testng.annotations.DataProvider;
  35 import org.testng.annotations.Test;
  36 import static org.testng.Assert.*;
  37 
  38 public class SubstitutabilityTest {
  39     @DataProvider(name="substitutable")
  40     Object[][] substitutableCases() {
  41         Point p1 = Point.makePoint(10, 10);
  42         Point p2 = Point.makePoint(20, 20);
  43         Point? box1 = p1;
  44         Point? box2 = p2;
  45         Line l1 = Line.makeLine(p1, p2);
  46         var mpath = MutablePath.makePath(10, 20, 30, 40);
  47         var mixedValues = new MixedValues(p1, l1, mpath, "value");
  48         var number = Value.Number.intValue(99);
  49         var list = List.of("list");
  50         return new Object[][] {
  51             new Object[] { p1, Point.makePoint(10, 10) },
  52             new Object[] { l1, Line.makeLine(10,10, 20,20) },
  53             new Object[] { box1, Point.makePoint(10, 10) },
  54             new Object[] { mpath, mpath},
  55             new Object[] { mixedValues, mixedValues},
  56             new Object[] { valueBuilder().setPoint(p1).build(),
  57                            valueBuilder().setPoint(Point.makePoint(10, 10)).build() },
  58             new Object[] { valueBuilder().setFloat(Float.NaN).setDouble(Double.NaN).setPoint(p1).build(),
  59                            valueBuilder().setFloat(Float.NaN).setDouble(Double.NaN).setPoint(l1.p1).build() },
  60             new Object[] { valueBuilder().setFloat(Float.NaN).setDouble(Double.NaN).setNumber(number).build(),
  61                            valueBuilder().setFloat(Float.NaN).setDouble(Double.NaN).setNumber(Value.Number.intValue(99)).build() },
  62             new Object[] { valueBuilder().setFloat(+0.0f).setDouble(+0.0).setReference(list).build(),
  63                            valueBuilder().setFloat(+0.0f).setDouble(+0.0).setReference(list).build() },
  64             new Object[] { valueBuilder().setNumber(Value.Number.intValue(100)).build(),
  65                            valueBuilder().setNumber(Value.Number.intValue(100)).build() },
  66             new Object[] { valueBuilder().setReference(list).build(),
  67                            valueBuilder().setReference(list).build() },
  68         };
  69     }
  70 
  71     @Test(dataProvider="substitutable")
  72     public void substitutableTest(Object a, Object b) {
  73         assertTrue(ValueBootstrapMethods.isSubstitutable(a, b));
  74     }
  75 
  76     @DataProvider(name="notSubstitutable")
  77     Object[][] notSubstitutableCases() {
  78         var point = Point.makePoint(10, 10);
  79         var mpath = MutablePath.makePath(10, 20, 30, 40);
  80         var number = Value.Number.intValue(99);
  81         return new Object[][] {
  82             new Object[] { Point.makePoint(10, 10), Point.makePoint(10, 20)},
  83             new Object[] { mpath, MutablePath.makePath(10, 20, 30, 40)},
  84             new Object[] { point, mpath},
  85             new Object[] { valueBuilder().setFloat(+0.0f).setDouble(+0.0).build(),
  86                            valueBuilder().setFloat(-0.0f).setDouble(+0.0).build() },
  87             new Object[] { valueBuilder().setFloat(+0.0f).setDouble(+0.0).build(),
  88                            valueBuilder().setFloat(+0.0f).setDouble(-0.0).build() },
  89             new Object[] { valueBuilder().setPoint(point).build(),
  90                            valueBuilder().setPoint(Point.makePoint(20, 20)).build() },
  91             new Object[] { valueBuilder().setNumber(number).build(),
  92                            valueBuilder().setNumber(new Value.IntNumber(99)).build() },
  93             new Object[] { valueBuilder().setNumber(Value.Number.intValue(1)).build(),
  94                            valueBuilder().setNumber(Value.Number.shortValue((short)1)).build() },
  95             new Object[] { valueBuilder().setNumber(new Value.IntNumber(99)).build(),
  96                            valueBuilder().setNumber(new Value.IntNumber(99)).build() },
  97             new Object[] { valueBuilder().setReference(List.of("list")).build(),
  98                            valueBuilder().setReference(List.of("list")).build() },
  99         };
 100     }
 101     @Test(dataProvider="notSubstitutable")
 102     public void notSubstitutableTest(Object a, Object b) {
 103         assertFalse(ValueBootstrapMethods.isSubstitutable(a, b));
 104     }
 105     private static Value.Builder valueBuilder() {
 106         Value.Builder builder = new Value.Builder();
 107         return builder.setChar('a')
 108                        .setBoolean(true)
 109                        .setByte((byte)0x1)
 110                        .setShort((short)3)
 111                        .setLong(4L);
 112     }
 113 }