| // Copyright (c) 2020, 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 com.android.tools.r8.utils.structural; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertTrue; |
| |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.TestParametersCollection; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| |
| @RunWith(Parameterized.class) |
| public class StructuralItemsTest extends TestBase { |
| |
| @Parameterized.Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return getTestParameters().withNoneRuntime().build(); |
| } |
| |
| public StructuralItemsTest(TestParameters parameters) { |
| parameters.assertNoneRuntime(); |
| } |
| |
| final B b1 = new B(1); |
| final B b2 = new B(2); |
| final B b2_copy = new B(2); |
| |
| final A a1b1 = new A(1, b1); |
| final A a2b1 = new A(2, b1); |
| final A a1b2 = new A(1, b2); |
| final A a2b2 = new A(2, b2); |
| final A a1b2_copy = new A(1, b2_copy); |
| final A a2b2_copy = new A(2, b2_copy); |
| |
| @Test |
| public void testOrder() { |
| assertTrue(b1.isLessThan(b2)); |
| assertTrue(b2.isEqualTo(b2_copy)); |
| assertFalse(b2.isLessThan(b1)); |
| |
| assertTrue(a1b1.isLessThan(a1b2)); |
| assertTrue(a1b2.isLessThan(a2b1)); |
| assertFalse(a2b1.isLessThan(a1b2_copy)); |
| |
| assertEquals(b1, Ordered.minIgnoreNull(null, b1)); |
| assertEquals(b1, Ordered.minIgnoreNull(b1, null)); |
| assertEquals(b1, Ordered.maxIgnoreNull(null, b1)); |
| assertEquals(b1, Ordered.maxIgnoreNull(b1, null)); |
| } |
| |
| @Test |
| public void testEquals() { |
| assertFalse(b1.isEqualTo(b2)); |
| assertTrue(b2.isEqualTo(b2_copy)); |
| assertEquals(b2, b2_copy); |
| |
| assertFalse(a2b2.isEqualTo(a2b1)); |
| assertTrue(a1b2.isEqualTo(a1b2_copy)); |
| assertEquals(a2b2, a2b2_copy); |
| |
| // Type incompatible check should still work. |
| assertNotEquals(b1, a1b1); |
| } |
| |
| @Test |
| public void testHashCode() { |
| assertEquals(b2.hashCode(), b2_copy.hashCode()); |
| assertEquals(b2, b2_copy); |
| Set<B> bs = new HashSet<>(ImmutableList.of(b1, b2, b2_copy)); |
| assertEquals(ImmutableSet.of(b1, b2), bs); |
| |
| Set<A> as = new HashSet<>(ImmutableList.of(a1b1, a1b2, a2b1, a2b2, a1b2_copy, a2b2_copy)); |
| assertEquals(ImmutableSet.of(a1b1, a1b2, a2b1, a2b2), as); |
| |
| // If these collide it is a poor hashing algorithm... |
| assertNotEquals(b1.hashCode(), b2.hashCode()); |
| } |
| |
| private String getHash(StructuralItem<?> item) { |
| return item.hashForTesting(); |
| } |
| |
| @Test |
| public void testHashing() { |
| assertEquals(getHash(b2), getHash(b2_copy)); |
| assertEquals(getHash(b2), getHash(b2_copy)); |
| Set<String> bs = new HashSet<>(ImmutableList.of(getHash(b1), getHash(b2), getHash(b2_copy))); |
| assertEquals(ImmutableSet.of(getHash(b1), getHash(b2)), bs); |
| |
| Set<String> as = |
| ImmutableList.of(a1b1, a1b2, a2b1, a2b2, a1b2_copy, a2b2_copy).stream() |
| .map(this::getHash) |
| .collect(Collectors.toSet()); |
| assertEquals( |
| ImmutableSet.of(a1b1, a1b2, a2b1, a2b2).stream() |
| .map(this::getHash) |
| .collect(Collectors.toSet()), |
| as); |
| |
| // If these collide it is a poor hashing algorithm... |
| assertNotEquals(getHash(b1), getHash(b2)); |
| } |
| |
| private static class A implements StructuralItem<A> { |
| |
| private final int x; |
| private final B b; |
| |
| private static void specify(StructuralSpecification<A, ?> spec) { |
| spec.withInt(a -> a.x).withItem(a -> a.b); |
| } |
| |
| public A(int x, B b) { |
| this.x = x; |
| this.b = b; |
| } |
| |
| @Override |
| public StructuralMapping<A> getStructuralMapping() { |
| return A::specify; |
| } |
| |
| @Override |
| public A self() { |
| return this; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| return Equatable.equalsImpl(this, other); |
| } |
| |
| @Override |
| public int hashCode() { |
| return HashCodeVisitor.run(this, A::specify); |
| } |
| } |
| |
| private static class B implements StructuralItem<B> { |
| |
| private final int y; |
| |
| private static void specify(StructuralSpecification<B, ?> spec) { |
| spec.withInt(b -> b.y); |
| } |
| |
| public B(int y) { |
| this.y = y; |
| } |
| |
| @Override |
| public StructuralMapping<B> getStructuralMapping() { |
| return B::specify; |
| } |
| |
| @Override |
| public B self() { |
| return this; |
| } |
| |
| @Override |
| public boolean equals(Object other) { |
| return Equatable.equalsImpl(this, other); |
| } |
| |
| @Override |
| public int hashCode() { |
| return HashCodeVisitor.run(this, B::specify); |
| } |
| } |
| } |