OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library constant_expression_test; |
| 6 |
| 7 import 'dart:async'; |
| 8 import 'package:async_helper/async_helper.dart'; |
| 9 import 'package:expect/expect.dart'; |
| 10 import 'package:compiler/src/constants/expressions.dart'; |
| 11 import 'package:compiler/src/dart2jslib.dart'; |
| 12 import 'package:compiler/src/elements/elements.dart'; |
| 13 import 'memory_compiler.dart'; |
| 14 |
| 15 class TestData { |
| 16 /// Declarations needed for the [constants]. |
| 17 final String declarations; |
| 18 /// Tested constants. |
| 19 final List constants; |
| 20 |
| 21 const TestData(this.declarations, this.constants); |
| 22 } |
| 23 |
| 24 class ConstantData { |
| 25 /// Source code for the constant expression. |
| 26 final String code; |
| 27 /// The expected constant expression kind. |
| 28 final ConstantExpressionKind kind; |
| 29 /// ConstantExpression.getText() result if different from [code]. |
| 30 final String text; |
| 31 /// The expected instance type for ConstructedConstantExpression. |
| 32 final String type; |
| 33 /// The expected instance fields for ConstructedConstantExpression. |
| 34 final Map<String, String> fields; |
| 35 |
| 36 const ConstantData(String code, |
| 37 this.kind, |
| 38 {String text, |
| 39 this.type, |
| 40 this.fields}) |
| 41 : this.code = code, |
| 42 this.text = text != null ? text : code; |
| 43 } |
| 44 |
| 45 const List<TestData> DATA = const [ |
| 46 const TestData('', const [ |
| 47 const ConstantData('null', ConstantExpressionKind.NULL), |
| 48 const ConstantData('false', ConstantExpressionKind.BOOL), |
| 49 const ConstantData('true', ConstantExpressionKind.BOOL), |
| 50 const ConstantData('0', ConstantExpressionKind.INT), |
| 51 const ConstantData('0.0', ConstantExpressionKind.DOUBLE), |
| 52 const ConstantData('"foo"', ConstantExpressionKind.STRING), |
| 53 const ConstantData('1 + 2', ConstantExpressionKind.BINARY), |
| 54 const ConstantData('-(1)', ConstantExpressionKind.UNARY, text: '-1'), |
| 55 const ConstantData('identical(0, 1)', ConstantExpressionKind.IDENTICAL), |
| 56 const ConstantData('"a" "b"', ConstantExpressionKind.CONCATENATE, |
| 57 text: '"ab"'), |
| 58 const ConstantData('identical', ConstantExpressionKind.FUNCTION), |
| 59 const ConstantData('true ? 0 : 1', ConstantExpressionKind.CONDITIONAL), |
| 60 const ConstantData('proxy', ConstantExpressionKind.VARIABLE), |
| 61 const ConstantData('Object', ConstantExpressionKind.TYPE), |
| 62 const ConstantData('#name', ConstantExpressionKind.SYMBOL), |
| 63 const ConstantData('const [0, 1]', ConstantExpressionKind.LIST), |
| 64 const ConstantData('const <int>[0, 1]', ConstantExpressionKind.LIST), |
| 65 const ConstantData('const {0: 1, 2: 3}', ConstantExpressionKind.MAP), |
| 66 const ConstantData('const <int, int>{0: 1, 2: 3}', |
| 67 ConstantExpressionKind.MAP), |
| 68 const ConstantData( |
| 69 'const bool.fromEnvironment("foo", defaultValue: false)', |
| 70 ConstantExpressionKind.BOOL_FROM_ENVIRONMENT), |
| 71 const ConstantData( |
| 72 'const int.fromEnvironment("foo", defaultValue: 42)', |
| 73 ConstantExpressionKind.INT_FROM_ENVIRONMENT), |
| 74 const ConstantData( |
| 75 'const String.fromEnvironment("foo", defaultValue: "bar")', |
| 76 ConstantExpressionKind.STRING_FROM_ENVIRONMENT), |
| 77 ]), |
| 78 const TestData(''' |
| 79 class A { |
| 80 const A(); |
| 81 } |
| 82 class B { |
| 83 final field1; |
| 84 const B(this.field1); |
| 85 } |
| 86 class C extends B { |
| 87 final field2; |
| 88 const C({field1: 42, this.field2: false}) : super(field1); |
| 89 const C.named([field = false]) : this(field1: field, field2: field); |
| 90 } |
| 91 ''', const [ |
| 92 const ConstantData('const Object()', |
| 93 ConstantExpressionKind.CONSTRUCTED, |
| 94 type: 'Object', fields: const {}), |
| 95 const ConstantData('const A()', |
| 96 ConstantExpressionKind.CONSTRUCTED, |
| 97 type: 'A', fields: const {}), |
| 98 const ConstantData('const B(0)', |
| 99 ConstantExpressionKind.CONSTRUCTED, |
| 100 type: 'B', |
| 101 fields: const {'field(B#field1)': '0'}), |
| 102 const ConstantData('const B(const A())', |
| 103 ConstantExpressionKind.CONSTRUCTED, |
| 104 type: 'B', |
| 105 fields: const {'field(B#field1)': 'const A()'}), |
| 106 const ConstantData('const C()', |
| 107 ConstantExpressionKind.CONSTRUCTED, |
| 108 type: 'C', |
| 109 fields: const { |
| 110 'field(B#field1)': '42', |
| 111 'field(C#field2)': 'false', |
| 112 }), |
| 113 const ConstantData('const C(field1: 87)', |
| 114 ConstantExpressionKind.CONSTRUCTED, |
| 115 type: 'C', |
| 116 fields: const { |
| 117 'field(B#field1)': '87', |
| 118 'field(C#field2)': 'false', |
| 119 }), |
| 120 const ConstantData('const C(field2: true)', |
| 121 ConstantExpressionKind.CONSTRUCTED, |
| 122 type: 'C', |
| 123 fields: const { |
| 124 'field(B#field1)': '42', |
| 125 'field(C#field2)': 'true', |
| 126 }), |
| 127 const ConstantData('const C.named()', |
| 128 ConstantExpressionKind.CONSTRUCTED, |
| 129 type: 'C', |
| 130 fields: const { |
| 131 'field(B#field1)': 'false', |
| 132 'field(C#field2)': 'false', |
| 133 }), |
| 134 const ConstantData('const C.named(87)', |
| 135 ConstantExpressionKind.CONSTRUCTED, |
| 136 type: 'C', |
| 137 fields: const { |
| 138 'field(B#field1)': '87', |
| 139 'field(C#field2)': '87', |
| 140 }), |
| 141 ]), |
| 142 const TestData(''' |
| 143 class A<T> implements B { |
| 144 final field1; |
| 145 const A({this.field1:42}); |
| 146 } |
| 147 class B<S> implements C { |
| 148 const factory B({field1}) = A<B<S>>; |
| 149 // TODO(johnniwinther): Enable this when the constructor evaluator doesn't |
| 150 // crash: |
| 151 /*const factory B.named() = A<S>;*/ |
| 152 } |
| 153 class C<U> { |
| 154 const factory C({field1}) = A<B<double>>; |
| 155 } |
| 156 ''', const [ |
| 157 const ConstantData('const A()', ConstantExpressionKind.CONSTRUCTED, |
| 158 type: 'A<dynamic>', |
| 159 fields: const {'field(A#field1)': '42'}), |
| 160 const ConstantData('const A<int>(field1: 87)', |
| 161 ConstantExpressionKind.CONSTRUCTED, |
| 162 type: 'A<int>', |
| 163 fields: const {'field(A#field1)': '87'}), |
| 164 const ConstantData('const B()', ConstantExpressionKind.CONSTRUCTED, |
| 165 type: 'A<B<dynamic>>', |
| 166 fields: const { |
| 167 'field(A#field1)': '42', |
| 168 }), |
| 169 const ConstantData('const B<int>()', ConstantExpressionKind.CONSTRUCTED, |
| 170 type: 'A<B<int>>', |
| 171 fields: const { |
| 172 'field(A#field1)': '42', |
| 173 }), |
| 174 const ConstantData('const B<int>(field1: 87)', |
| 175 ConstantExpressionKind.CONSTRUCTED, |
| 176 type: 'A<B<int>>', |
| 177 fields: const { |
| 178 'field(A#field1)': '87', |
| 179 }), |
| 180 const ConstantData('const C<int>(field1: 87)', |
| 181 ConstantExpressionKind.CONSTRUCTED, |
| 182 type: 'A<B<double>>', |
| 183 fields: const { |
| 184 'field(A#field1)': '87', |
| 185 }), |
| 186 // TODO(johnniwinther): Enable this when the constructor evaluator doesn't |
| 187 // crash: |
| 188 /*const ConstantData('const B<int>.named()', |
| 189 ConstantExpressionKind.CONSTRUCTED, |
| 190 type: 'A<int>', |
| 191 fields: const { |
| 192 'field(A#field1)': '42', |
| 193 }),*/ |
| 194 ]), |
| 195 ]; |
| 196 |
| 197 main() { |
| 198 asyncTest(() => Future.forEach(DATA, testData)); |
| 199 } |
| 200 |
| 201 Future testData(TestData data) { |
| 202 StringBuffer sb = new StringBuffer(); |
| 203 sb.write('${data.declarations}\n'); |
| 204 Map constants = {}; |
| 205 data.constants.forEach((ConstantData constantData) { |
| 206 String name = 'c${constants.length}'; |
| 207 sb.write('const $name = ${constantData.code};\n'); |
| 208 constants[name] = constantData; |
| 209 }); |
| 210 sb.write('main() {}\n'); |
| 211 String source = sb.toString(); |
| 212 Compiler compiler = compilerFor( |
| 213 {'main.dart': source}, options: ['--analyze-all']); |
| 214 return compiler.runCompiler(Uri.parse('memory:main.dart')).then((_) { |
| 215 var library = compiler.mainApp; |
| 216 constants.forEach((String name, ConstantData data) { |
| 217 FieldElement field = library.localLookup(name); |
| 218 var constant = field.constant; |
| 219 Expect.equals(data.kind, constant.kind, |
| 220 "Unexpected kind '${constant.kind}' for contant " |
| 221 "`${constant.getText()}`, expected '${data.kind}'."); |
| 222 Expect.equals(data.text, constant.getText(), |
| 223 "Unexpected text '${constant.getText()}' for contant, " |
| 224 "expected '${data.text}'."); |
| 225 if (data.type != null) { |
| 226 String instanceType = constant.computeInstanceType().toString(); |
| 227 Expect.equals(data.type, instanceType, |
| 228 "Unexpected type '$instanceType' for contant " |
| 229 "`${constant.getText()}`, expected '${data.type}'."); |
| 230 } |
| 231 if (data.fields != null) { |
| 232 Map instanceFields = constant.computeInstanceFields(); |
| 233 Expect.equals(data.fields.length, instanceFields.length, |
| 234 "Unexpected field count ${instanceFields.length} for contant " |
| 235 "`${constant.getText()}`, expected '${data.fields.length}'."); |
| 236 instanceFields.forEach((field, expression) { |
| 237 String name = '$field'; |
| 238 String expression = instanceFields[field].getText(); |
| 239 String expected = data.fields[name]; |
| 240 Expect.equals(expected, expression, |
| 241 "Unexpected field expression ${expression} for field '$name' in " |
| 242 "contant `${constant.getText()}`, expected '${expected}'."); |
| 243 }); |
| 244 } |
| 245 }); |
| 246 }); |
| 247 } |
OLD | NEW |