335f55a601
This reverts commit 853597a978.
Reason for revert: Breaks google3 (b/186088197)
Original change's description:
> Optimize js_util setProperty calls for non-function value types.
>
> No change in the generated JavaScript for dart2js base on a sample
> foo.dart file and tests/lib/js/js_util/properties_test.dart
>
> Bug: #44533
> Change-Id: Ib6866fa7fca1f13b03c75dd4f1eac904b18811e3
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193838
> Reviewed-by: Sigmund Cherem <sigmund@google.com>
> Commit-Queue: Riley Porter <rileyporter@google.com>
TBR=sigmund@google.com,srujzs@google.com,rileyporter@google.com
Change-Id: I3f08d29e2d6a1a7846b8d67fadc314ad947f54cf
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: #44533
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196484
Reviewed-by: David Morgan <davidmorgan@google.com>
Commit-Queue: David Morgan <davidmorgan@google.com>
391 lines
12 KiB
Dart
391 lines
12 KiB
Dart
// Copyright (c) 2021, the Dart 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.
|
|
|
|
// Tests the functionality of object properties with the js_util library. For
|
|
// js_util tests with HTML objects see tests/lib/html/js_util_test.dart.
|
|
|
|
@JS()
|
|
library js_util_properties_test;
|
|
|
|
import 'package:js/js.dart';
|
|
import 'package:js/js_util.dart' as js_util;
|
|
import 'package:expect/minitest.dart';
|
|
|
|
@JS()
|
|
external String jsFunction();
|
|
|
|
@JS()
|
|
external void eval(String code);
|
|
|
|
@JS('JSON.stringify')
|
|
external String stringify(o);
|
|
|
|
@JS('ArrayBuffer')
|
|
external get JSArrayBufferType;
|
|
|
|
@JS()
|
|
class Foo {
|
|
external Foo(num a);
|
|
|
|
external num get a;
|
|
external num bar();
|
|
external Object get objectProperty;
|
|
external List get list;
|
|
}
|
|
|
|
@JS('Foo')
|
|
external get JSFooType;
|
|
|
|
String dartFunction() {
|
|
return 'Dart Function';
|
|
}
|
|
|
|
@JS()
|
|
@anonymous
|
|
class ExampleTypedLiteral {
|
|
external factory ExampleTypedLiteral({a, b});
|
|
|
|
external get a;
|
|
external get b;
|
|
}
|
|
|
|
String _getBarWithSideEffect() {
|
|
var x = 5;
|
|
expect(x, equals(5));
|
|
return 'bar';
|
|
}
|
|
|
|
main() {
|
|
eval(r"""
|
|
function Foo(a) {
|
|
this.a = a;
|
|
}
|
|
|
|
Foo.b = 38;
|
|
|
|
Foo.prototype.list = [2, 4, 6];
|
|
|
|
Foo.prototype.bar = function() {
|
|
return this.a;
|
|
}
|
|
|
|
Foo.prototype.toString = function() {
|
|
return "I'm a Foo a=" + this.a;
|
|
}
|
|
|
|
Foo.prototype.fnList = [Foo.prototype.bar, Foo.prototype.toString];
|
|
|
|
Foo.prototype.objectProperty = {
|
|
'c': 1,
|
|
'list': [10, 20, 30],
|
|
'functionProperty': function() { return 'Function Property'; }
|
|
}
|
|
|
|
function jsFunction() {
|
|
return "JS Function";
|
|
}
|
|
|
|
Foo.prototype.nestedFunction = function() {
|
|
return function() {
|
|
return 'Nested Function';
|
|
};
|
|
}
|
|
|
|
Foo.prototype.getFirstEl = function(list) {
|
|
return list[0];
|
|
}
|
|
|
|
Foo.prototype.sumFn = function(a, b) {
|
|
return a + b;
|
|
}
|
|
|
|
Foo.prototype.getA = function(obj) {
|
|
return obj.a;
|
|
}
|
|
|
|
Foo.prototype.callFn = function(fn) {
|
|
return fn();
|
|
}
|
|
""");
|
|
|
|
group('newObject', () {
|
|
test('create', () {
|
|
expect(identical(js_util.newObject(), js_util.newObject()), isFalse);
|
|
});
|
|
|
|
test('callMethod', () {
|
|
var o = js_util.newObject();
|
|
expect(js_util.callMethod(o, 'toString', []), equals('[object Object]'));
|
|
expect(stringify(o), equals('{}'));
|
|
});
|
|
|
|
test('properties', () {
|
|
var o = js_util.newObject();
|
|
expect(js_util.hasProperty(o, 'foo bar'), isFalse);
|
|
expect(js_util.hasProperty(o, 'toString'), isTrue);
|
|
expect(js_util.callMethod(o, 'hasOwnProperty', ['toString']), isFalse);
|
|
expect(js_util.callMethod(o, 'hasOwnProperty', ['foo bar']), isFalse);
|
|
js_util.setProperty(o, 'foo bar', 42);
|
|
expect(js_util.callMethod(o, 'hasOwnProperty', ['foo bar']), isTrue);
|
|
expect(js_util.getProperty(o, 'foo bar'), equals(42));
|
|
expect(js_util.hasProperty(o, 'foo bar'), isTrue);
|
|
expect(stringify(o), equals('{"foo bar":42}'));
|
|
});
|
|
|
|
test('nested properties calls', () {
|
|
var o = js_util.newObject();
|
|
var f = new Foo(42);
|
|
js_util.setProperty(o, 'foo', f);
|
|
var foo = js_util.getProperty(o, 'foo');
|
|
expect(foo, equals(f));
|
|
expect(js_util.hasProperty(foo, 'a'), isTrue);
|
|
expect(js_util.getProperty(foo, 'a'), equals(42));
|
|
js_util.setProperty(foo, 'a', 24);
|
|
expect(js_util.getProperty(foo, 'a'), equals(24));
|
|
});
|
|
});
|
|
|
|
group('hasProperty', () {
|
|
test('typed object', () {
|
|
var f = new Foo(42);
|
|
expect(js_util.hasProperty(f, 'a'), isTrue);
|
|
expect(js_util.hasProperty(f, 'bar'), isTrue);
|
|
expect(js_util.hasProperty(f, 'b'), isFalse);
|
|
expect(js_util.hasProperty(f, 'toString'), isTrue);
|
|
js_util.setProperty(f, '__proto__', null);
|
|
expect(js_util.hasProperty(f, 'toString'), isFalse);
|
|
});
|
|
|
|
test('typed literal', () {
|
|
var literal = new ExampleTypedLiteral(a: 'x', b: 42);
|
|
expect(js_util.hasProperty(literal, 'a'), isTrue);
|
|
expect(js_util.hasProperty(literal, 'b'), isTrue);
|
|
expect(js_util.hasProperty(literal, 'anything'), isFalse);
|
|
|
|
literal = new ExampleTypedLiteral(a: null);
|
|
expect(js_util.hasProperty(literal, 'a'), isTrue);
|
|
expect(js_util.hasProperty(literal, 'b'), isFalse);
|
|
expect(js_util.hasProperty(literal, 'anything'), isFalse);
|
|
});
|
|
|
|
test('complex hasProperty calls', () {
|
|
var f = new Foo(42);
|
|
expect(js_util.hasProperty(f.objectProperty, 'c'), isTrue);
|
|
expect(js_util.hasProperty(f.objectProperty, 'nonexistent'), isFalse);
|
|
|
|
// Using a variable for the property name.
|
|
String propertyName = 'bar';
|
|
expect(js_util.hasProperty(f, propertyName), isTrue);
|
|
});
|
|
});
|
|
|
|
group('getProperty', () {
|
|
test('typed object', () {
|
|
var f = new Foo(42);
|
|
expect(js_util.getProperty(f, 'a'), equals(42));
|
|
expect(js_util.getProperty(f, 'b'), isNull);
|
|
expect(js_util.getProperty(f, 'bar') is Function, isTrue);
|
|
expect(js_util.getProperty(f, 'list') is List, isTrue);
|
|
expect(js_util.getProperty(f, 'objectProperty') is Object, isTrue);
|
|
expect(js_util.getProperty(f, 'toString') is Function, isTrue);
|
|
js_util.setProperty(f, '__proto__', null);
|
|
expect(js_util.getProperty(f, 'toString'), isNull);
|
|
});
|
|
|
|
test('typed literal', () {
|
|
var literal = new ExampleTypedLiteral(a: 'x', b: 42);
|
|
expect(js_util.getProperty(literal, 'a'), equals('x'));
|
|
expect(js_util.getProperty(literal, 'b'), equals(42));
|
|
expect(js_util.getProperty(literal, 'anything'), isNull);
|
|
});
|
|
|
|
test('complex getProperty calls', () {
|
|
var f = new Foo(42);
|
|
|
|
// Accessing a method property.
|
|
expect(js_util.getProperty(f, 'bar') is Function, isTrue);
|
|
expect(js_util.callMethod(f, 'bar', []), equals(42));
|
|
|
|
// Accessing list properties.
|
|
expect(js_util.getProperty(f, 'list')[0], equals(2));
|
|
expect(js_util.getProperty(f, 'fnList')[0] is Function, isTrue);
|
|
expect(
|
|
js_util.callMethod(
|
|
js_util.getProperty(f, 'fnList')[0], 'apply', [f, []]),
|
|
equals(42));
|
|
expect(js_util.getProperty(f.list, "0"), equals(2));
|
|
var index = 0;
|
|
expect(js_util.getProperty(f.list, index++), equals(2));
|
|
expect(index, equals(1));
|
|
expect(js_util.getProperty(f.list, index), equals(4));
|
|
|
|
// Accessing nested object properites.
|
|
var objectProperty = js_util.getProperty(f, 'objectProperty');
|
|
expect(js_util.getProperty(objectProperty, 'c'), equals(1));
|
|
expect(js_util.getProperty(objectProperty, 'list') is List, isTrue);
|
|
expect(js_util.getProperty(objectProperty, 'list')[1], equals(20));
|
|
expect(
|
|
js_util.getProperty(objectProperty, 'functionProperty') is Function,
|
|
isTrue);
|
|
// Using nested getProperty calls.
|
|
expect(
|
|
js_util.getProperty(
|
|
js_util.getProperty(
|
|
js_util.getProperty(f, 'objectProperty'), 'list'),
|
|
1),
|
|
equals(20));
|
|
|
|
// Using a variable for the property name.
|
|
String propertyName = 'a';
|
|
expect(js_util.getProperty(f, propertyName), equals(42));
|
|
String bar = _getBarWithSideEffect();
|
|
expect(js_util.getProperty(f, bar) is Function, isTrue);
|
|
expect(js_util.callMethod(f, bar, []), equals(42));
|
|
});
|
|
});
|
|
|
|
group('setProperty', () {
|
|
test('typed object', () {
|
|
var f = new Foo(42);
|
|
expect(js_util.getProperty(f, 'a'), equals(42));
|
|
js_util.setProperty(f, 'a', 100);
|
|
expect(f.a, equals(100));
|
|
expect(js_util.getProperty(f, 'a'), equals(100));
|
|
|
|
expect(js_util.getProperty(f, 'list') is List, isTrue);
|
|
js_util.setProperty(f, 'list', [8]);
|
|
expect(js_util.getProperty(f, 'list') is List, isTrue);
|
|
expect(js_util.getProperty(f, 'list')[0], equals(8));
|
|
|
|
js_util.setProperty(f, 'newProperty', 'new');
|
|
expect(js_util.getProperty(f, 'newProperty'), equals('new'));
|
|
});
|
|
|
|
test('typed literal', () {
|
|
var literal = new ExampleTypedLiteral();
|
|
js_util.setProperty(literal, 'a', 'foo');
|
|
expect(js_util.getProperty(literal, 'a'), equals('foo'));
|
|
expect(literal.a, equals('foo'));
|
|
js_util.setProperty(literal, 'a', literal);
|
|
expect(identical(literal.a, literal), isTrue);
|
|
var list = ['arr'];
|
|
js_util.setProperty(literal, 'a', list);
|
|
expect(identical(literal.a, list), isTrue);
|
|
});
|
|
|
|
test('complex setProperty calls', () {
|
|
var f = new Foo(42);
|
|
|
|
// Set function property to a num.
|
|
expect(js_util.getProperty(f, 'bar') is Function, isTrue);
|
|
js_util.setProperty(f, 'bar', 5);
|
|
expect(js_util.getProperty(f, 'bar') is Function, isFalse);
|
|
expect(js_util.getProperty(f, 'bar'), equals(5));
|
|
|
|
// Set property to a Dart function.
|
|
js_util.setProperty(f, 'bar', allowInterop(dartFunction));
|
|
expect(js_util.getProperty(f, 'bar') is Function, isTrue);
|
|
expect(js_util.callMethod(f, 'bar', []), equals('Dart Function'));
|
|
js_util.setProperty(f, 'bar', allowInterop(() {
|
|
return 'Inline';
|
|
}));
|
|
expect(js_util.callMethod(f, 'bar', []), equals('Inline'));
|
|
|
|
// Set property to a JS function.
|
|
js_util.setProperty(f, 'bar', allowInterop(jsFunction));
|
|
expect(js_util.getProperty(f, 'bar') is Function, isTrue);
|
|
expect(js_util.callMethod(f, 'bar', []), equals('JS Function'));
|
|
|
|
// Set property with nested object properties.
|
|
js_util.setProperty(f.objectProperty, 'c', 'new val');
|
|
expect(js_util.getProperty(f.objectProperty, 'c'), equals('new val'));
|
|
js_util.setProperty(f.objectProperty, 'list', [1, 2, 3]);
|
|
expect(js_util.getProperty(f.objectProperty, 'list')[1], equals(2));
|
|
// Using a nested getProperty call.
|
|
js_util.setProperty(
|
|
js_util.getProperty(f, 'objectProperty'), 'c', 'nested val');
|
|
expect(js_util.getProperty(f.objectProperty, 'c'), equals('nested val'));
|
|
|
|
// Using a variable for the property name.
|
|
String propertyName = 'bar';
|
|
js_util.setProperty(f, propertyName, 'foo');
|
|
expect(js_util.getProperty(f, 'bar'), equals('foo'));
|
|
String bar = _getBarWithSideEffect();
|
|
js_util.setProperty(f, bar, 'baz');
|
|
expect(js_util.getProperty(f, bar), equals('baz'));
|
|
});
|
|
});
|
|
|
|
group('callMethod', () {
|
|
test('typed object', () {
|
|
var f = new Foo(42);
|
|
expect(js_util.callMethod(f, 'bar', []), equals(42));
|
|
});
|
|
|
|
test('complex callMethod calls', () {
|
|
var f = new Foo(42);
|
|
|
|
// Call a method that returns an unbound function.
|
|
expect(js_util.callMethod(f, 'nestedFunction', []) is Function, isTrue);
|
|
expect(js_util.callMethod(f, 'nestedFunction', [])(),
|
|
equals('Nested Function'));
|
|
|
|
// Call method on a nested function property.
|
|
expect(js_util.callMethod(f.objectProperty, 'functionProperty', []),
|
|
equals('Function Property'));
|
|
// Using a nested getProperty call.
|
|
expect(
|
|
js_util.callMethod(
|
|
js_util.getProperty(f, 'objectProperty'), 'functionProperty', []),
|
|
equals('Function Property'));
|
|
|
|
// Call method with different args.
|
|
expect(
|
|
js_util.callMethod(f, 'getFirstEl', [
|
|
[25, 50]
|
|
]),
|
|
equals(25));
|
|
expect(js_util.callMethod(f, 'sumFn', [2, 3]), equals(5));
|
|
expect(js_util.callMethod(f, 'getA', [f]), equals(42));
|
|
expect(js_util.callMethod(f, 'callFn', [allowInterop(jsFunction)]),
|
|
equals("JS Function"));
|
|
expect(js_util.callMethod(f, 'callFn', [allowInterop(dartFunction)]),
|
|
equals("Dart Function"));
|
|
expect(
|
|
js_util.callMethod(f, 'callFn', [
|
|
allowInterop(() {
|
|
return "inline";
|
|
})
|
|
]),
|
|
equals("inline"));
|
|
|
|
// Using a variable for the method name.
|
|
String methodName = 'bar';
|
|
expect(js_util.callMethod(f, methodName, []), equals(42));
|
|
String bar = _getBarWithSideEffect();
|
|
expect(js_util.callMethod(f, bar, []), equals(42));
|
|
});
|
|
});
|
|
|
|
group('instanceof', () {
|
|
test('typed object', () {
|
|
var f = new Foo(42);
|
|
expect(js_util.instanceof(f, JSFooType), isTrue);
|
|
expect(js_util.instanceof(f, JSArrayBufferType), isFalse);
|
|
});
|
|
|
|
test('typed literal', () {
|
|
var literal = new ExampleTypedLiteral();
|
|
expect(js_util.instanceof(literal, JSFooType), isFalse);
|
|
});
|
|
});
|
|
|
|
group('callConstructor', () {
|
|
test('typed object', () {
|
|
Foo f = js_util.callConstructor(JSFooType, [42]);
|
|
expect(f.a, equals(42));
|
|
});
|
|
});
|
|
}
|