| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013, 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 import 'dart:async'; | |
| 6 import 'package:barback/barback.dart'; | |
| 7 import 'package:observe/transform.dart'; | |
| 8 import 'package:unittest/compact_vm_config.dart'; | |
| 9 import 'package:unittest/unittest.dart'; | |
| 10 | |
| 11 main() { | |
| 12 useCompactVMConfiguration(); | |
| 13 | |
| 14 group('replaces Observable for ChangeNotifier', () { | |
| 15 _testClause('extends Observable', 'extends ChangeNotifier'); | |
| 16 _testClause('extends Base with Observable', | |
| 17 'extends Base with ChangeNotifier'); | |
| 18 _testClause('extends Base<T> with Observable', | |
| 19 'extends Base<T> with ChangeNotifier'); | |
| 20 _testClause('extends Base with Mixin, Observable', | |
| 21 'extends Base with Mixin, ChangeNotifier'); | |
| 22 _testClause('extends Base with Observable, Mixin', | |
| 23 'extends Base with ChangeNotifier, Mixin'); | |
| 24 _testClause('extends Base with Mixin<T>, Observable', | |
| 25 'extends Base with Mixin<T>, ChangeNotifier'); | |
| 26 _testClause('extends Base with Mixin, Observable, Mixin2', | |
| 27 'extends Base with Mixin, ChangeNotifier, Mixin2'); | |
| 28 _testClause('extends Observable implements Interface', | |
| 29 'extends ChangeNotifier implements Interface'); | |
| 30 _testClause('extends Observable implements Interface<T>', | |
| 31 'extends ChangeNotifier implements Interface<T>'); | |
| 32 _testClause('extends Base with Observable implements Interface', | |
| 33 'extends Base with ChangeNotifier implements Interface'); | |
| 34 _testClause( | |
| 35 'extends Base with Mixin, Observable implements I1, I2', | |
| 36 'extends Base with Mixin, ChangeNotifier implements I1, I2'); | |
| 37 }); | |
| 38 | |
| 39 group('adds "with ChangeNotifier" given', () { | |
| 40 _testClause('', 'extends ChangeNotifier'); | |
| 41 _testClause('extends Base', 'extends Base with ChangeNotifier'); | |
| 42 _testClause('extends Base<T>', 'extends Base<T> with ChangeNotifier'); | |
| 43 _testClause('extends Base with Mixin', | |
| 44 'extends Base with Mixin, ChangeNotifier'); | |
| 45 _testClause('extends Base with Mixin<T>', | |
| 46 'extends Base with Mixin<T>, ChangeNotifier'); | |
| 47 _testClause('extends Base with Mixin, Mixin2', | |
| 48 'extends Base with Mixin, Mixin2, ChangeNotifier'); | |
| 49 _testClause('implements Interface', | |
| 50 'extends ChangeNotifier implements Interface'); | |
| 51 _testClause('implements Interface<T>', | |
| 52 'extends ChangeNotifier implements Interface<T>'); | |
| 53 _testClause('extends Base implements Interface', | |
| 54 'extends Base with ChangeNotifier implements Interface'); | |
| 55 _testClause('extends Base with Mixin implements I1, I2', | |
| 56 'extends Base with Mixin, ChangeNotifier implements I1, I2'); | |
| 57 }); | |
| 58 | |
| 59 group('fixes contructor calls ', () { | |
| 60 _testInitializers('this.a', '(a) : __\$a = a'); | |
| 61 _testInitializers('{this.a}', '({a}) : __\$a = a'); | |
| 62 _testInitializers('[this.a]', '([a]) : __\$a = a'); | |
| 63 _testInitializers('this.a, this.b', '(a, b) : __\$a = a, __\$b = b'); | |
| 64 _testInitializers('{this.a, this.b}', '({a, b}) : __\$a = a, __\$b = b'); | |
| 65 _testInitializers('[this.a, this.b]', '([a, b]) : __\$a = a, __\$b = b'); | |
| 66 _testInitializers('this.a, [this.b]', '(a, [b]) : __\$a = a, __\$b = b'); | |
| 67 _testInitializers('this.a, {this.b}', '(a, {b}) : __\$a = a, __\$b = b'); | |
| 68 }); | |
| 69 | |
| 70 for (var annotation in ['observable', 'published']) { | |
| 71 group('@$annotation full text', () { | |
| 72 test('with changes', () { | |
| 73 return _transform(_sampleObservable(annotation)).then( | |
| 74 (out) => expect(out, _sampleObservableOutput(annotation))); | |
| 75 }); | |
| 76 | |
| 77 test('complex with changes', () { | |
| 78 return _transform(_complexObservable(annotation)).then( | |
| 79 (out) => expect(out, _complexObservableOutput(annotation))); | |
| 80 }); | |
| 81 | |
| 82 test('no changes', () { | |
| 83 var input = 'class A {/*@$annotation annotation to trigger transform */;
}'; | |
| 84 return _transform(input).then((output) => expect(output, input)); | |
| 85 }); | |
| 86 }); | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 _testClause(String clauses, String expected) { | |
| 91 test(clauses, () { | |
| 92 var className = 'MyClass'; | |
| 93 if (clauses.contains('<T>')) className += '<T>'; | |
| 94 var code = ''' | |
| 95 class $className $clauses { | |
| 96 @observable var field; | |
| 97 }'''; | |
| 98 | |
| 99 return _transform(code).then((output) { | |
| 100 var classPos = output.indexOf(className) + className.length; | |
| 101 var actualClauses = output.substring(classPos, | |
| 102 output.indexOf('{')).trim().replaceAll(' ', ' '); | |
| 103 expect(actualClauses, expected); | |
| 104 }); | |
| 105 }); | |
| 106 } | |
| 107 | |
| 108 _testInitializers(String args, String expected) { | |
| 109 test(args, () { | |
| 110 var constructor = 'MyClass('; | |
| 111 var code = ''' | |
| 112 class MyClass { | |
| 113 @observable var a; | |
| 114 @observable var b; | |
| 115 MyClass($args); | |
| 116 }'''; | |
| 117 | |
| 118 return _transform(code).then((output) { | |
| 119 var begin = output.indexOf(constructor) + constructor.length - 1; | |
| 120 var end = output.indexOf(';', begin); | |
| 121 if (end == -1) end = output.length; | |
| 122 var init = output.substring(begin, end).trim().replaceAll(' ', ' '); | |
| 123 expect(init, expected); | |
| 124 }); | |
| 125 }); | |
| 126 } | |
| 127 | |
| 128 /** Helper that applies the transform by creating mock assets. */ | |
| 129 Future<String> _transform(String code) { | |
| 130 var id = new AssetId('foo', 'a/b/c.dart'); | |
| 131 var asset = new Asset.fromString(id, code); | |
| 132 var transformer = new ObservableTransformer(); | |
| 133 return transformer.isPrimary(asset).then((isPrimary) { | |
| 134 expect(isPrimary, isTrue); | |
| 135 var transform = new _MockTransform(asset); | |
| 136 return transformer.apply(transform).then((_) { | |
| 137 expect(transform.outs, hasLength(1)); | |
| 138 expect(transform.outs[0].id, id); | |
| 139 return transform.outs.first.readAsString(); | |
| 140 }); | |
| 141 }); | |
| 142 } | |
| 143 | |
| 144 class _MockTransform implements Transform { | |
| 145 List<Asset> outs = []; | |
| 146 Asset _asset; | |
| 147 TransformLogger logger = new TransformLogger(_mockLogFn); | |
| 148 Asset get primaryInput => _asset; | |
| 149 | |
| 150 _MockTransform(this._asset); | |
| 151 Future<Asset> getInput(AssetId id) { | |
| 152 if (id == primaryInput.id) return new Future.value(primaryInput); | |
| 153 fail('_MockTransform fail'); | |
| 154 } | |
| 155 | |
| 156 void addOutput(Asset output) { | |
| 157 outs.add(output); | |
| 158 } | |
| 159 | |
| 160 readInput(id) => throw new UnimplementedError(); | |
| 161 readInputAsString(id, {encoding}) => throw new UnimplementedError(); | |
| 162 | |
| 163 static void _mockLogFn(AssetId asset, LogLevel level, String message, | |
| 164 span) { | |
| 165 // Do nothing. | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 String _sampleObservable(String annotation) => ''' | |
| 170 library A_foo; | |
| 171 import 'package:observe/observe.dart'; | |
| 172 | |
| 173 class A extends Observable { | |
| 174 @$annotation int foo; | |
| 175 A(this.foo); | |
| 176 } | |
| 177 '''; | |
| 178 | |
| 179 String _sampleObservableOutput(String annotation) => | |
| 180 "library A_foo;\n" | |
| 181 "import 'package:observe/observe.dart';\n\n" | |
| 182 "class A extends ChangeNotifier {\n" | |
| 183 " @reflectable @$annotation int get foo => __\$foo; int __\$foo; " | |
| 184 "${_makeSetter('int', 'foo')}\n" | |
| 185 " A(foo) : __\$foo = foo;\n" | |
| 186 "}\n"; | |
| 187 | |
| 188 _makeSetter(type, name) => '@reflectable set $name($type value) { ' | |
| 189 '__\$$name = notifyPropertyChange(#$name, __\$$name, value); }'; | |
| 190 | |
| 191 String _complexObservable(String annotation) => ''' | |
| 192 class Foo extends Observable { | |
| 193 @$annotation | |
| 194 @otherMetadata | |
| 195 Foo | |
| 196 foo/*D*/= 1, bar =/*A*/2/*B*/, | |
| 197 quux/*C*/; | |
| 198 | |
| 199 @$annotation var baz; | |
| 200 } | |
| 201 '''; | |
| 202 | |
| 203 String _complexObservableOutput(String meta) => | |
| 204 "class Foo extends ChangeNotifier {\n" | |
| 205 " @reflectable @$meta\n" | |
| 206 " @otherMetadata\n" | |
| 207 " Foo\n" | |
| 208 " get foo => __\$foo; Foo __\$foo/*D*/= 1; " | |
| 209 "${_makeSetter('Foo', 'foo')} " | |
| 210 "@reflectable @$meta @otherMetadata Foo get bar => __\$bar; " | |
| 211 "Foo __\$bar =/*A*/2/*B*/; ${_makeSetter('Foo', 'bar')}\n" | |
| 212 " @reflectable @$meta @otherMetadata Foo get quux => __\$quux; " | |
| 213 "Foo __\$quux/*C*/; ${_makeSetter('Foo', 'quux')}\n\n" | |
| 214 " @reflectable @$meta dynamic get baz => __\$baz; dynamic __\$baz; " | |
| 215 "${_makeSetter('dynamic', 'baz')}\n" | |
| 216 "}\n"; | |
| OLD | NEW |