Index: tests/compiler/dart2js/constant_expression_test.dart |
diff --git a/tests/compiler/dart2js/constant_expression_test.dart b/tests/compiler/dart2js/constant_expression_test.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c7fdaaf3ea72bbcbc3c231690e20ccce9a5d65e3 |
--- /dev/null |
+++ b/tests/compiler/dart2js/constant_expression_test.dart |
@@ -0,0 +1,247 @@ |
+// Copyright (c) 2015, 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. |
+ |
+library constant_expression_test; |
+ |
+import 'dart:async'; |
+import 'package:async_helper/async_helper.dart'; |
+import 'package:expect/expect.dart'; |
+import 'package:compiler/src/constants/expressions.dart'; |
+import 'package:compiler/src/dart2jslib.dart'; |
+import 'package:compiler/src/elements/elements.dart'; |
+import 'memory_compiler.dart'; |
+ |
+class TestData { |
+ /// Declarations needed for the [constants]. |
+ final String declarations; |
+ /// Tested constants. |
+ final List constants; |
+ |
+ const TestData(this.declarations, this.constants); |
+} |
+ |
+class ConstantData { |
+ /// Source code for the constant expression. |
+ final String code; |
+ /// The expected constant expression kind. |
+ final ConstantExpressionKind kind; |
+ /// ConstantExpression.getText() result if different from [code]. |
+ final String text; |
+ /// The expected instance type for ConstructedConstantExpression. |
+ final String type; |
+ /// The expected instance fields for ConstructedConstantExpression. |
+ final Map<String, String> fields; |
+ |
+ const ConstantData(String code, |
+ this.kind, |
+ {String text, |
+ this.type, |
+ this.fields}) |
+ : this.code = code, |
+ this.text = text != null ? text : code; |
+} |
+ |
+const List<TestData> DATA = const [ |
+ const TestData('', const [ |
+ const ConstantData('null', ConstantExpressionKind.NULL), |
+ const ConstantData('false', ConstantExpressionKind.BOOL), |
+ const ConstantData('true', ConstantExpressionKind.BOOL), |
+ const ConstantData('0', ConstantExpressionKind.INT), |
+ const ConstantData('0.0', ConstantExpressionKind.DOUBLE), |
+ const ConstantData('"foo"', ConstantExpressionKind.STRING), |
+ const ConstantData('1 + 2', ConstantExpressionKind.BINARY), |
+ const ConstantData('-(1)', ConstantExpressionKind.UNARY, text: '-1'), |
+ const ConstantData('identical(0, 1)', ConstantExpressionKind.IDENTICAL), |
+ const ConstantData('"a" "b"', ConstantExpressionKind.CONCATENATE, |
+ text: '"ab"'), |
+ const ConstantData('identical', ConstantExpressionKind.FUNCTION), |
+ const ConstantData('true ? 0 : 1', ConstantExpressionKind.CONDITIONAL), |
+ const ConstantData('proxy', ConstantExpressionKind.VARIABLE), |
+ const ConstantData('Object', ConstantExpressionKind.TYPE), |
+ const ConstantData('#name', ConstantExpressionKind.SYMBOL), |
+ const ConstantData('const [0, 1]', ConstantExpressionKind.LIST), |
+ const ConstantData('const <int>[0, 1]', ConstantExpressionKind.LIST), |
+ const ConstantData('const {0: 1, 2: 3}', ConstantExpressionKind.MAP), |
+ const ConstantData('const <int, int>{0: 1, 2: 3}', |
+ ConstantExpressionKind.MAP), |
+ const ConstantData( |
+ 'const bool.fromEnvironment("foo", defaultValue: false)', |
+ ConstantExpressionKind.BOOL_FROM_ENVIRONMENT), |
+ const ConstantData( |
+ 'const int.fromEnvironment("foo", defaultValue: 42)', |
+ ConstantExpressionKind.INT_FROM_ENVIRONMENT), |
+ const ConstantData( |
+ 'const String.fromEnvironment("foo", defaultValue: "bar")', |
+ ConstantExpressionKind.STRING_FROM_ENVIRONMENT), |
+ ]), |
+ const TestData(''' |
+class A { |
+ const A(); |
+} |
+class B { |
+ final field1; |
+ const B(this.field1); |
+} |
+class C extends B { |
+ final field2; |
+ const C({field1: 42, this.field2: false}) : super(field1); |
+ const C.named([field = false]) : this(field1: field, field2: field); |
+} |
+''', const [ |
+ const ConstantData('const Object()', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'Object', fields: const {}), |
+ const ConstantData('const A()', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'A', fields: const {}), |
+ const ConstantData('const B(0)', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'B', |
+ fields: const {'field(B#field1)': '0'}), |
+ const ConstantData('const B(const A())', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'B', |
+ fields: const {'field(B#field1)': 'const A()'}), |
+ const ConstantData('const C()', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'C', |
+ fields: const { |
+ 'field(B#field1)': '42', |
+ 'field(C#field2)': 'false', |
+ }), |
+ const ConstantData('const C(field1: 87)', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'C', |
+ fields: const { |
+ 'field(B#field1)': '87', |
+ 'field(C#field2)': 'false', |
+ }), |
+ const ConstantData('const C(field2: true)', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'C', |
+ fields: const { |
+ 'field(B#field1)': '42', |
+ 'field(C#field2)': 'true', |
+ }), |
+ const ConstantData('const C.named()', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'C', |
+ fields: const { |
+ 'field(B#field1)': 'false', |
+ 'field(C#field2)': 'false', |
+ }), |
+ const ConstantData('const C.named(87)', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'C', |
+ fields: const { |
+ 'field(B#field1)': '87', |
+ 'field(C#field2)': '87', |
+ }), |
+ ]), |
+ const TestData(''' |
+class A<T> implements B { |
+ final field1; |
+ const A({this.field1:42}); |
+} |
+class B<S> implements C { |
+ const factory B({field1}) = A<B<S>>; |
+ // TODO(johnniwinther): Enable this when the constructor evaluator doesn't |
+ // crash: |
+ /*const factory B.named() = A<S>;*/ |
+} |
+class C<U> { |
+ const factory C({field1}) = A<B<double>>; |
+} |
+''', const [ |
+ const ConstantData('const A()', ConstantExpressionKind.CONSTRUCTED, |
+ type: 'A<dynamic>', |
+ fields: const {'field(A#field1)': '42'}), |
+ const ConstantData('const A<int>(field1: 87)', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'A<int>', |
+ fields: const {'field(A#field1)': '87'}), |
+ const ConstantData('const B()', ConstantExpressionKind.CONSTRUCTED, |
+ type: 'A<B<dynamic>>', |
+ fields: const { |
+ 'field(A#field1)': '42', |
+ }), |
+ const ConstantData('const B<int>()', ConstantExpressionKind.CONSTRUCTED, |
+ type: 'A<B<int>>', |
+ fields: const { |
+ 'field(A#field1)': '42', |
+ }), |
+ const ConstantData('const B<int>(field1: 87)', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'A<B<int>>', |
+ fields: const { |
+ 'field(A#field1)': '87', |
+ }), |
+ const ConstantData('const C<int>(field1: 87)', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'A<B<double>>', |
+ fields: const { |
+ 'field(A#field1)': '87', |
+ }), |
+ // TODO(johnniwinther): Enable this when the constructor evaluator doesn't |
+ // crash: |
+ /*const ConstantData('const B<int>.named()', |
+ ConstantExpressionKind.CONSTRUCTED, |
+ type: 'A<int>', |
+ fields: const { |
+ 'field(A#field1)': '42', |
+ }),*/ |
+ ]), |
+]; |
+ |
+main() { |
+ asyncTest(() => Future.forEach(DATA, testData)); |
+} |
+ |
+Future testData(TestData data) { |
+ StringBuffer sb = new StringBuffer(); |
+ sb.write('${data.declarations}\n'); |
+ Map constants = {}; |
+ data.constants.forEach((ConstantData constantData) { |
+ String name = 'c${constants.length}'; |
+ sb.write('const $name = ${constantData.code};\n'); |
+ constants[name] = constantData; |
+ }); |
+ sb.write('main() {}\n'); |
+ String source = sb.toString(); |
+ Compiler compiler = compilerFor( |
+ {'main.dart': source}, options: ['--analyze-all']); |
+ return compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) { |
+ var library = compiler.mainApp; |
+ constants.forEach((String name, ConstantData data) { |
+ FieldElement field = library.localLookup(name); |
+ var constant = field.constant; |
+ Expect.equals(data.kind, constant.kind, |
+ "Unexpected kind '${constant.kind}' for contant " |
+ "`${constant.getText()}`, expected '${data.kind}'."); |
+ Expect.equals(data.text, constant.getText(), |
+ "Unexpected text '${constant.getText()}' for contant, " |
+ "expected '${data.text}'."); |
+ if (data.type != null) { |
+ String instanceType = constant.computeInstanceType().toString(); |
+ Expect.equals(data.type, instanceType, |
+ "Unexpected type '$instanceType' for contant " |
+ "`${constant.getText()}`, expected '${data.type}'."); |
+ } |
+ if (data.fields != null) { |
+ Map instanceFields = constant.computeInstanceFields(); |
+ Expect.equals(data.fields.length, instanceFields.length, |
+ "Unexpected field count ${instanceFields.length} for contant " |
+ "`${constant.getText()}`, expected '${data.fields.length}'."); |
+ instanceFields.forEach((field, expression) { |
+ String name = '$field'; |
+ String expression = instanceFields[field].getText(); |
+ String expected = data.fields[name]; |
+ Expect.equals(expected, expression, |
+ "Unexpected field expression ${expression} for field '$name' in " |
+ "contant `${constant.getText()}`, expected '${expected}'."); |
+ }); |
+ } |
+ }); |
+ }); |
+} |