blob: d672e1ef24a9a9761ff7af44c8b87449758bb65d [file] [log] [blame]
/*
* Copyright 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.core.interop;
import com.google.gwt.junit.client.GWTTestCase;
import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsPackage;
import jsinterop.annotations.JsType;
/**
* Tests JsType object method devirtualization functionality.
*/
@SuppressWarnings("cast")
public class JsTypeObjectMethodsTest extends GWTTestCase {
@Override
public String getModuleName() {
return "com.google.gwt.core.Interop";
}
@JsType(isNative = true)
interface NativeObject {
}
public native NativeObject createWithEqualsAndHashCode(int a, int b) /*-{
return {a : a, b : b, hashCode: function() { return this.b }, equals :
function(other) { return this.a == other.a; } };
}-*/;
public native NativeObject createWithoutEqualsAndHashCode(int a, int b) /*-{
return {a : a, b : b} ;
}-*/;
@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object")
static class NativeClassWithHashCode {
public native int hashCode();
}
static class SubclassNativeClassWithHashCode extends NativeClassWithHashCode {
private int n;
public SubclassNativeClassWithHashCode(int n) {
this.n = n;
}
@JsMethod
public int hashCode() {
return n;
}
}
static class ImplementsNativeObject implements NativeObject {
private int n;
public ImplementsNativeObject(int n) {
this.n = n;
}
@JsMethod
public int hashCode() {
return n;
}
}
public void testHashCode() {
assertEquals(3, createWithEqualsAndHashCode(1, 3).hashCode());
NativeObject o1 = createWithoutEqualsAndHashCode(1, 3);
NativeObject o2 = createWithoutEqualsAndHashCode(1, 3);
assertTrue(o1.hashCode() != o2.hashCode());
assertTrue(((Object) o1).hashCode() != ((Object) o2).hashCode());
assertEquals(8, new SubclassNativeClassWithHashCode(8).hashCode());
assertEquals(8, ((Object) new SubclassNativeClassWithHashCode(8)).hashCode());
assertEquals(9, ((Object) new ImplementsNativeObject(9)).hashCode());
assertEquals(10, callHashCode(new SubclassNativeClassWithHashCode(10)));
}
public void testEquals() {
assertEquals(createWithEqualsAndHashCode(1, 3), createWithEqualsAndHashCode(1, 4));
NativeObject o1 = createWithoutEqualsAndHashCode(1, 3);
NativeObject o2 = createWithoutEqualsAndHashCode(1, 3);
assertTrue(createWithEqualsAndHashCode(1, 3).equals(createWithoutEqualsAndHashCode(1, 4)));
assertTrue(((Object) createWithEqualsAndHashCode(1, 3)).equals(createWithoutEqualsAndHashCode(1, 4)));
assertFalse(createWithoutEqualsAndHashCode(1, 4).equals(createWithEqualsAndHashCode(1, 3)));
assertFalse(((Object) createWithoutEqualsAndHashCode(1, 4)).equals(createWithEqualsAndHashCode(1, 3)));
assertFalse(o1.equals(o2));
assertFalse(((Object) o1).equals(o2));
}
private native int callHashCode(Object obj) /*-{
return obj.hashCode();
}-*/;
// Use an existing class for native subclassing tests to work around the need of injecting a
// JS class before the subclass definitions
@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Error")
private static class MyNativeError {
MyNativeError() { }
MyNativeError(String error) { }
public native int hashCode();
public int myValue;
}
private static class MyNativeErrorSubtype extends MyNativeError {
MyNativeErrorSubtype(int n) {
myValue = n;
}
public String toString() {
return "(Sub)myValue: " + myValue;
}
}
private static MyNativeError createMyNativeError(int n) {
MyNativeError error = new MyNativeError("(Error)myValue: " + n);
error.myValue = n;
return error;
}
public void testJavaLangObjectMethodsOrNativeSubtypes() {
patchErrorWithJavaLangObjectMethods();
assertEquals(createMyNativeError(3), createMyNativeError(3));
assertFalse(createMyNativeError(3).equals(createMyNativeError(4)));
assertEquals(createMyNativeError(6), new MyNativeErrorSubtype(6));
assertTrue(createMyNativeError(6).toString().contains("(Error)myValue: 6"));
assertEquals("(Sub)myValue: 6", new MyNativeErrorSubtype(6).toString());
// Tests that hashcode is actually working through the object trampoline and
// assumes that consecutive hashchodes are different.
assertFalse(createMyNativeError(3).hashCode() == new MyNativeError().hashCode());
}
private static native void patchErrorWithJavaLangObjectMethods() /*-{
$wnd.Error.prototype.equals = function (o) {
return this.myValue == o.myValue;
};
}-*/;
}