OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library polymer.test.build.script_compactor_test; | 5 library polymer.test.build.script_compactor_test; |
6 | 6 |
| 7 import 'package:code_transformers/tests.dart' show testingDartSdkDirectory; |
7 import 'package:polymer/src/build/common.dart'; | 8 import 'package:polymer/src/build/common.dart'; |
8 import 'package:polymer/src/build/script_compactor.dart'; | 9 import 'package:polymer/src/build/script_compactor.dart'; |
| 10 import 'package:smoke/codegen/generator.dart' show DEFAULT_IMPORTS; |
9 import 'package:unittest/compact_vm_config.dart'; | 11 import 'package:unittest/compact_vm_config.dart'; |
| 12 import 'package:unittest/unittest.dart'; |
10 | 13 |
11 import 'common.dart'; | 14 import 'common.dart'; |
12 | 15 |
13 void main() { | 16 void main() { |
14 useCompactVMConfiguration(); | 17 useCompactVMConfiguration(); |
15 var phases = [[new ScriptCompactor(new TransformOptions())]]; | 18 var phases = [[new ScriptCompactor(new TransformOptions(), |
| 19 sdkDir: testingDartSdkDirectory)]]; |
| 20 group('initializers', () => initializerTests(phases)); |
| 21 group('codegen', () => codegenTests(phases)); |
| 22 } |
16 | 23 |
| 24 initializerTests(phases) { |
17 testPhases('no changes', phases, { | 25 testPhases('no changes', phases, { |
18 'a|web/test.html': '<!DOCTYPE html><html></html>', | 26 'a|web/test.html': '<!DOCTYPE html><html></html>', |
19 'a|web/test.html.scriptUrls': '[]', | 27 'a|web/test.html.scriptUrls': '[]', |
20 }, { | 28 }, { |
21 'a|web/test.html': '<!DOCTYPE html><html></html>', | 29 'a|web/test.html': '<!DOCTYPE html><html></html>', |
22 }); | 30 }); |
23 | 31 |
24 testPhases('no changes outside web/', phases, { | 32 testPhases('no changes outside web/', phases, { |
25 'a|lib/test.html': | 33 'a|lib/test.html': |
26 '<!DOCTYPE html><html><head>' | 34 '<!DOCTYPE html><html><head>' |
27 '<script type="application/dart" src="a.dart"></script>', | 35 '<script type="application/dart" src="a.dart"></script>', |
28 }, { | 36 }, { |
29 'a|lib/test.html': | 37 'a|lib/test.html': |
30 '<!DOCTYPE html><html><head>' | 38 '<!DOCTYPE html><html><head>' |
31 '<script type="application/dart" src="a.dart"></script>', | 39 '<script type="application/dart" src="a.dart"></script>', |
32 }); | 40 }); |
33 | 41 |
34 testPhases('single script', phases, { | 42 testPhases('single script', phases, { |
35 'a|web/test.html': | 43 'a|web/test.html': |
36 '<!DOCTYPE html><html><head>' | 44 '<!DOCTYPE html><html><head>' |
37 '<script type="application/dart" src="a.dart"></script>', | 45 '<script type="application/dart" src="a.dart"></script>', |
38 'a|web/test.html.scriptUrls': '[]', | 46 'a|web/test.html.scriptUrls': '[]', |
39 'a|web/a.dart': 'library a;\nmain(){}', | 47 'a|web/a.dart': |
| 48 'library a;\n' |
| 49 'import "package:polymer/polymer.dart";\n' |
| 50 'main(){}', |
40 }, { | 51 }, { |
41 'a|web/test.html': | 52 'a|web/test.html': |
42 '<!DOCTYPE html><html><head>' | 53 '<!DOCTYPE html><html><head>' |
43 '<script type="application/dart" ' | 54 '<script type="application/dart" ' |
44 'src="test.html_bootstrap.dart"></script>' | 55 'src="test.html_bootstrap.dart"></script>' |
45 '</head><body></body></html>', | 56 '</head><body></body></html>', |
46 | 57 |
47 'a|web/test.html_bootstrap.dart': | 58 'a|web/test.html_bootstrap.dart': |
48 '''$MAIN_HEADER | 59 '''$MAIN_HEADER |
49 import 'a.dart' as i0; | 60 import 'a.dart' as i0; |
| 61 ${DEFAULT_IMPORTS.join('\n')} |
50 | 62 |
51 void main() { | 63 void main() { |
| 64 useGeneratedCode(new StaticConfiguration( |
| 65 checkedMode: false)); |
52 configureForDeployment([ | 66 configureForDeployment([ |
53 ]); | 67 ]); |
54 i0.main(); | 68 i0.main(); |
55 } | 69 } |
56 '''.replaceAll('\n ', '\n'), | 70 '''.replaceAll('\n ', '\n'), |
57 'a|web/a.dart': 'library a;\nmain(){}', | 71 'a|web/a.dart': |
| 72 'library a;\n' |
| 73 'import "package:polymer/polymer.dart";\n' |
| 74 'main(){}', |
58 }); | 75 }); |
59 | 76 |
60 testPhases('several scripts', phases, { | 77 testPhases('several scripts', phases, { |
61 'a|web/test.html': | 78 'a|web/test.html': |
62 '<!DOCTYPE html><html><head>' | 79 '<!DOCTYPE html><html><head>' |
63 '</head><body><div>' | 80 '</head><body><div>' |
64 '<script type="application/dart" src="d.dart"></script>' | 81 '<script type="application/dart" src="d.dart"></script>' |
65 '</div>', | 82 '</div>', |
66 'a|web/test.html.scriptUrls': | 83 'a|web/test.html.scriptUrls': |
67 '[["a", "web/a.dart"],["a", "web/b.dart"],["a", "web/c.dart"]]', | 84 '[["a", "web/a.dart"],["a", "web/b.dart"],["a", "web/c.dart"]]', |
68 'a|web/d.dart': 'library d;\nmain(){}\n@initMethod mD(){}', | 85 'a|web/d.dart': |
| 86 'library d;\n' |
| 87 'import "package:polymer/polymer.dart";\n' |
| 88 'main(){}\n@initMethod mD(){}', |
69 | 89 |
70 'a|web/a.dart': | 90 'a|web/a.dart': |
71 'import "package:polymer/polymer.dart";\n' | 91 'import "package:polymer/polymer.dart";\n' |
72 '@initMethod mA(){}\n', | 92 '@initMethod mA(){}\n', |
73 | 93 |
74 'a|web/b.dart': | 94 'a|web/b.dart': |
| 95 'import "package:polymer/polymer.dart";\n' |
75 'export "e.dart";\n' | 96 'export "e.dart";\n' |
76 'export "f.dart" show XF1, mF1;\n' | 97 'export "f.dart" show XF1, mF1;\n' |
77 'export "g.dart" hide XG1, mG1;\n' | 98 'export "g.dart" hide XG1, mG1;\n' |
78 'export "h.dart" show XH1, mH1 hide mH1, mH2;\n' | 99 'export "h.dart" show XH1, mH1 hide mH1, mH2;\n' |
79 '@initMethod mB(){}\n', | 100 '@initMethod mB(){}\n', |
80 | 101 |
81 'a|web/c.dart': | 102 'a|web/c.dart': |
82 'import "package:polymer/polymer.dart";\n' | 103 'import "package:polymer/polymer.dart";\n' |
83 'part "c_part.dart"\n' | 104 'part "c_part.dart";\n' |
84 '@CustomTag("x-c2") class XC2 {}\n', | 105 '@CustomTag("x-c1") class XC1 {}\n', |
85 | 106 |
86 'a|web/c_part.dart': | 107 'a|web/c_part.dart': |
87 '@CustomTag("x-c1") class XC1 {}\n', | 108 '@CustomTag("x-c2") class XC2 {}\n', |
88 | 109 |
89 'a|web/e.dart': | 110 'a|web/e.dart': |
90 'import "package:polymer/polymer.dart";\n' | 111 'import "package:polymer/polymer.dart";\n' |
91 '@CustomTag("x-e") class XE {}\n' | 112 '@CustomTag("x-e") class XE {}\n' |
92 '@initMethod mE(){}\n', | 113 '@initMethod mE(){}\n', |
93 | 114 |
94 'a|web/f.dart': | 115 'a|web/f.dart': |
95 'import "package:polymer/polymer.dart";\n' | 116 'import "package:polymer/polymer.dart";\n' |
96 '@CustomTag("x-f1") class XF1 {}\n' | 117 '@CustomTag("x-f1") class XF1 {}\n' |
97 '@initMethod mF1(){}\n' | 118 '@initMethod mF1(){}\n' |
(...skipping 20 matching lines...) Expand all Loading... |
118 '</script>' | 139 '</script>' |
119 '</div>' | 140 '</div>' |
120 '</body></html>', | 141 '</body></html>', |
121 | 142 |
122 'a|web/test.html_bootstrap.dart': | 143 'a|web/test.html_bootstrap.dart': |
123 '''$MAIN_HEADER | 144 '''$MAIN_HEADER |
124 import 'a.dart' as i0; | 145 import 'a.dart' as i0; |
125 import 'b.dart' as i1; | 146 import 'b.dart' as i1; |
126 import 'c.dart' as i2; | 147 import 'c.dart' as i2; |
127 import 'd.dart' as i3; | 148 import 'd.dart' as i3; |
| 149 ${DEFAULT_IMPORTS.join('\n')} |
| 150 import 'e.dart' as smoke_0; |
| 151 import 'f.dart' as smoke_1; |
| 152 import 'g.dart' as smoke_2; |
| 153 import 'h.dart' as smoke_3; |
| 154 import 'c.dart' as smoke_4; |
128 | 155 |
129 void main() { | 156 void main() { |
| 157 useGeneratedCode(new StaticConfiguration( |
| 158 checkedMode: false, |
| 159 declarations: { |
| 160 smoke_4.XC1: const {}, |
| 161 smoke_4.XC2: const {}, |
| 162 smoke_0.XE: const {}, |
| 163 smoke_1.XF1: const {}, |
| 164 smoke_2.XG2: const {}, |
| 165 smoke_3.XH1: const {}, |
| 166 })); |
130 configureForDeployment([ | 167 configureForDeployment([ |
131 i0.mA, | 168 i0.mA, |
132 () => Polymer.register('x-e', i1.XE), | 169 () => Polymer.register('x-e', i1.XE), |
133 i1.mE, | |
134 () => Polymer.register('x-f1', i1.XF1), | 170 () => Polymer.register('x-f1', i1.XF1), |
135 i1.mF1, | |
136 () => Polymer.register('x-g2', i1.XG2), | 171 () => Polymer.register('x-g2', i1.XG2), |
137 i1.mG2, | |
138 () => Polymer.register('x-h1', i1.XH1), | 172 () => Polymer.register('x-h1', i1.XH1), |
139 i1.mB, | 173 i1.mB, |
| 174 i1.mE, |
| 175 i1.mF1, |
| 176 i1.mG2, |
140 () => Polymer.register('x-c1', i2.XC1), | 177 () => Polymer.register('x-c1', i2.XC1), |
141 () => Polymer.register('x-c2', i2.XC2), | 178 () => Polymer.register('x-c2', i2.XC2), |
142 i3.mD, | 179 i3.mD, |
143 ]); | 180 ]); |
144 i3.main(); | 181 i3.main(); |
145 } | 182 } |
146 '''.replaceAll('\n ', '\n'), | 183 '''.replaceAll('\n ', '\n'), |
147 }); | 184 }, null); |
148 } | 185 } |
| 186 |
| 187 codegenTests(phases) { |
| 188 testPhases('bindings', phases, { |
| 189 'a|web/test.html': |
| 190 '<!DOCTYPE html><html><body>' |
| 191 '<polymer-element name="foo-bar"><template>' |
| 192 '<div>{{a.node}}</div>' |
| 193 '<div>{{anotherNode}}</div>' |
| 194 '<div class="{{an.attribute}}"></div>' |
| 195 '<a href="path/{{within.an.attribute}}/foo/bar"></a>' |
| 196 '<div data-attribute="{{anotherAttribute}}"></div>' |
| 197 // input and custom-element attributes are treated as 2-way bindings: |
| 198 '<input value="{{this.is.twoWay}}">' |
| 199 '<something-else my-attribute="{{here.too}}"></something-else>' |
| 200 '<div on-click="{{methodName}}"></div>' |
| 201 '<div on-click="{{@read.method}}"></div>' |
| 202 '</template></polymer-element>' |
| 203 '<script type="application/dart" src="a.dart"></script>', |
| 204 'a|web/test.html.scriptUrls': '[]', |
| 205 'a|web/a.dart': |
| 206 'library a;\n' |
| 207 'import "package:polymer/polymer.dart";\n' |
| 208 'main(){}', |
| 209 }, { |
| 210 'a|web/test.html_bootstrap.dart': |
| 211 '''$MAIN_HEADER |
| 212 import 'a.dart' as i0; |
| 213 ${DEFAULT_IMPORTS.join('\n')} |
| 214 |
| 215 void main() { |
| 216 useGeneratedCode(new StaticConfiguration( |
| 217 checkedMode: false, |
| 218 getters: { |
| 219 #a: (o) => o.a, |
| 220 #an: (o) => o.an, |
| 221 #anotherAttribute: (o) => o.anotherAttribute, |
| 222 #anotherNode: (o) => o.anotherNode, |
| 223 #attribute: (o) => o.attribute, |
| 224 #here: (o) => o.here, |
| 225 #is: (o) => o.is, |
| 226 #method: (o) => o.method, |
| 227 #methodName: (o) => o.methodName, |
| 228 #node: (o) => o.node, |
| 229 #read: (o) => o.read, |
| 230 #too: (o) => o.too, |
| 231 #twoWay: (o) => o.twoWay, |
| 232 #within: (o) => o.within, |
| 233 }, |
| 234 setters: { |
| 235 #too: (o, v) { o.too = v; }, |
| 236 #twoWay: (o, v) { o.twoWay = v; }, |
| 237 }, |
| 238 names: { |
| 239 #a: r'a', |
| 240 #an: r'an', |
| 241 #anotherAttribute: r'anotherAttribute', |
| 242 #anotherNode: r'anotherNode', |
| 243 #attribute: r'attribute', |
| 244 #here: r'here', |
| 245 #is: r'is', |
| 246 #method: r'method', |
| 247 #methodName: r'methodName', |
| 248 #node: r'node', |
| 249 #read: r'read', |
| 250 #too: r'too', |
| 251 #twoWay: r'twoWay', |
| 252 #within: r'within', |
| 253 })); |
| 254 configureForDeployment([ |
| 255 ]); |
| 256 i0.main(); |
| 257 } |
| 258 '''.replaceAll('\n ', '\n'), |
| 259 'a|web/a.dart': |
| 260 'library a;\n' |
| 261 'import "package:polymer/polymer.dart";\n' |
| 262 'main(){}', |
| 263 }); |
| 264 |
| 265 final field1Details = "annotations: const [smoke_1.published]"; |
| 266 final field3Details = "isFinal: true, annotations: const [smoke_1.published]"; |
| 267 final prop1Details = "kind: PROPERTY, annotations: const [smoke_1.published]"; |
| 268 final prop3Details = |
| 269 "kind: PROPERTY, isFinal: true, annotations: const [smoke_1.published]"; |
| 270 testPhases('published via annotation', phases, { |
| 271 'a|web/test.html': |
| 272 '<!DOCTYPE html><html><body>' |
| 273 '<script type="application/dart" src="a.dart"></script>', |
| 274 'a|web/test.html.scriptUrls': '[]', |
| 275 'a|web/a.dart': |
| 276 'library a;\n' |
| 277 'import "package:polymer/polymer.dart";\n' |
| 278 '@CustomTag("x-foo")\n' |
| 279 'class XFoo {\n' |
| 280 ' @published int field1;\n' |
| 281 ' int field2;\n' |
| 282 ' @published final int field3;\n' |
| 283 ' final int field4;\n' |
| 284 ' @published int get prop1 => 1;\n' |
| 285 ' set prop1(int x) {};\n' |
| 286 ' int get prop2 => 2;\n' |
| 287 ' set prop2(int x) {};\n' |
| 288 ' @published int get prop3 => 3;\n' |
| 289 ' int get prop4 => 4;\n' |
| 290 ' @published int method1() => 1;\n' |
| 291 ' int method2() => 2;\n' |
| 292 '}\n' |
| 293 'main(){}', |
| 294 }, { |
| 295 'a|web/test.html_bootstrap.dart': |
| 296 '''$MAIN_HEADER |
| 297 import 'a.dart' as i0; |
| 298 ${DEFAULT_IMPORTS.join('\n')} |
| 299 import 'a.dart' as smoke_0; |
| 300 import 'package:polymer/polymer.dart' as smoke_1; |
| 301 |
| 302 void main() { |
| 303 useGeneratedCode(new StaticConfiguration( |
| 304 checkedMode: false, |
| 305 getters: { |
| 306 #field1: (o) => o.field1, |
| 307 #field3: (o) => o.field3, |
| 308 #prop1: (o) => o.prop1, |
| 309 #prop3: (o) => o.prop3, |
| 310 }, |
| 311 setters: { |
| 312 #field1: (o, v) { o.field1 = v; }, |
| 313 #prop1: (o, v) { o.prop1 = v; }, |
| 314 }, |
| 315 declarations: { |
| 316 smoke_0.XFoo: { |
| 317 #field1: const Declaration(#field1, int, $field1Details), |
| 318 #field3: const Declaration(#field3, int, $field3Details), |
| 319 #prop1: const Declaration(#prop1, int, $prop1Details), |
| 320 #prop3: const Declaration(#prop3, int, $prop3Details), |
| 321 }, |
| 322 }, |
| 323 names: { |
| 324 #field1: r'field1', |
| 325 #field3: r'field3', |
| 326 #prop1: r'prop1', |
| 327 #prop3: r'prop3', |
| 328 })); |
| 329 configureForDeployment([ |
| 330 () => Polymer.register(\'x-foo\', i0.XFoo), |
| 331 ]); |
| 332 i0.main(); |
| 333 } |
| 334 '''.replaceAll('\n ', '\n'), |
| 335 }); |
| 336 |
| 337 testPhases('published via attributes', phases, { |
| 338 'a|web/test.html': |
| 339 '<!DOCTYPE html><html><body>' |
| 340 '<polymer-element name="x-foo" attributes="field1,prop2">' |
| 341 '</polymer-element>' |
| 342 '<script type="application/dart" src="a.dart"></script>', |
| 343 'a|web/test.html.scriptUrls': '[]', |
| 344 'a|web/a.dart': |
| 345 'library a;\n' |
| 346 'import "package:polymer/polymer.dart";\n' |
| 347 '@CustomTag("x-foo")\n' |
| 348 'class XFoo {\n' |
| 349 ' int field1;\n' |
| 350 ' int field2;\n' |
| 351 ' int get prop1 => 1;\n' |
| 352 ' set prop1(int x) {};\n' |
| 353 ' int get prop2 => 2;\n' |
| 354 ' set prop2(int x) {};\n' |
| 355 '}\n' |
| 356 'main(){}', |
| 357 }, { |
| 358 'a|web/test.html_bootstrap.dart': |
| 359 '''$MAIN_HEADER |
| 360 import 'a.dart' as i0; |
| 361 ${DEFAULT_IMPORTS.join('\n')} |
| 362 import 'a.dart' as smoke_0; |
| 363 |
| 364 void main() { |
| 365 useGeneratedCode(new StaticConfiguration( |
| 366 checkedMode: false, |
| 367 getters: { |
| 368 #field1: (o) => o.field1, |
| 369 #prop2: (o) => o.prop2, |
| 370 }, |
| 371 setters: { |
| 372 #field1: (o, v) { o.field1 = v; }, |
| 373 #prop2: (o, v) { o.prop2 = v; }, |
| 374 }, |
| 375 declarations: { |
| 376 smoke_0.XFoo: { |
| 377 #field1: const Declaration(#field1, int), |
| 378 #prop2: const Declaration(#prop2, int, kind: PROPERTY), |
| 379 }, |
| 380 }, |
| 381 names: { |
| 382 #field1: r'field1', |
| 383 #prop2: r'prop2', |
| 384 })); |
| 385 configureForDeployment([ |
| 386 () => Polymer.register(\'x-foo\', i0.XFoo), |
| 387 ]); |
| 388 i0.main(); |
| 389 } |
| 390 '''.replaceAll('\n ', '\n'), |
| 391 }); |
| 392 |
| 393 final fooDetails = |
| 394 "kind: METHOD, annotations: const [const smoke_1.ObserveProperty('x')]"; |
| 395 final xChangedDetails = "Function, kind: METHOD"; |
| 396 testPhases('ObserveProperty and *Changed methods', phases, { |
| 397 'a|web/test.html': |
| 398 '<!DOCTYPE html><html><body>' |
| 399 '</polymer-element>' |
| 400 '<script type="application/dart" src="a.dart"></script>', |
| 401 'a|web/test.html.scriptUrls': '[]', |
| 402 'a|web/a.dart': |
| 403 'library a;\n' |
| 404 'import "package:polymer/polymer.dart";\n' |
| 405 '@CustomTag("x-foo")\n' |
| 406 'class XFoo {\n' |
| 407 ' int x;\n' |
| 408 ' void xChanged() {}\n' |
| 409 ' void attributeChanged() {}\n' // should be excluded |
| 410 ' @ObserveProperty("x")' |
| 411 ' void foo() {}\n' |
| 412 '}\n' |
| 413 'main(){}', |
| 414 }, { |
| 415 'a|web/test.html_bootstrap.dart': |
| 416 '''$MAIN_HEADER |
| 417 import 'a.dart' as i0; |
| 418 ${DEFAULT_IMPORTS.join('\n')} |
| 419 import 'a.dart' as smoke_0; |
| 420 import 'package:polymer/polymer.dart' as smoke_1; |
| 421 |
| 422 void main() { |
| 423 useGeneratedCode(new StaticConfiguration( |
| 424 checkedMode: false, |
| 425 getters: { |
| 426 #foo: (o) => o.foo, |
| 427 #xChanged: (o) => o.xChanged, |
| 428 }, |
| 429 declarations: { |
| 430 smoke_0.XFoo: { |
| 431 #foo: const Declaration(#foo, Function, $fooDetails), |
| 432 #xChanged: const Declaration(#xChanged, $xChangedDetails), |
| 433 }, |
| 434 }, |
| 435 names: { |
| 436 #foo: r'foo', |
| 437 #xChanged: r'xChanged', |
| 438 })); |
| 439 configureForDeployment([ |
| 440 () => Polymer.register(\'x-foo\', i0.XFoo), |
| 441 ]); |
| 442 i0.main(); |
| 443 } |
| 444 '''.replaceAll('\n ', '\n'), |
| 445 }); |
| 446 |
| 447 final rcDetails = "#registerCallback, Function, kind: METHOD, isStatic: true"; |
| 448 testPhases('register callback is included', phases, { |
| 449 'a|web/test.html': |
| 450 '<!DOCTYPE html><html><body>' |
| 451 '</polymer-element>' |
| 452 '<script type="application/dart" src="a.dart"></script>', |
| 453 'a|web/test.html.scriptUrls': '[]', |
| 454 'a|web/a.dart': |
| 455 'library a;\n' |
| 456 'import "package:polymer/polymer.dart";\n' |
| 457 '@CustomTag("x-foo")\n' |
| 458 'class XFoo {\n' |
| 459 ' static registerCallback() {};\n' |
| 460 ' static foo() {};\n' |
| 461 '}\n' |
| 462 'main(){}', |
| 463 }, { |
| 464 'a|web/test.html_bootstrap.dart': |
| 465 '''$MAIN_HEADER |
| 466 import 'a.dart' as i0; |
| 467 ${DEFAULT_IMPORTS.join('\n')} |
| 468 import 'a.dart' as smoke_0; |
| 469 |
| 470 void main() { |
| 471 useGeneratedCode(new StaticConfiguration( |
| 472 checkedMode: false, |
| 473 declarations: { |
| 474 smoke_0.XFoo: { |
| 475 #registerCallback: const Declaration($rcDetails), |
| 476 }, |
| 477 }, |
| 478 staticMethods: { |
| 479 smoke_0.XFoo: { |
| 480 #registerCallback: smoke_0.XFoo.registerCallback, |
| 481 }, |
| 482 }, |
| 483 names: { |
| 484 #registerCallback: r'registerCallback', |
| 485 })); |
| 486 configureForDeployment([ |
| 487 () => Polymer.register(\'x-foo\', i0.XFoo), |
| 488 ]); |
| 489 i0.main(); |
| 490 } |
| 491 '''.replaceAll('\n ', '\n'), |
| 492 }); |
| 493 } |
OLD | NEW |