blob: b4ff074256cf273ad87d82e8bb522ba705322748 [file] [log] [blame]
// 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.
// Note: This test relies on LF line endings in the source file.
// Test that JS printer callbacks occur when expected.
library js_ast.printer.callback_test;
import 'package:js_ast/js_ast.dart';
import 'package:unittest/unittest.dart';
enum TestMode {
NONE,
ENTER,
DELIMITER,
EXIT,
}
const DATA = const [
const {
TestMode.NONE: """
function(a, b) {
return null;
}""",
TestMode.ENTER: """
@0function(@1a, @2b) @3{
@4return @5null;
}""",
TestMode.DELIMITER: """
function(a, b) {
return null;
@0}""",
TestMode.EXIT: """
function(a@1, b@2) {
return null@5;
@4}@3@0"""
},
const {
TestMode.NONE: """
function() {
if (true) {
foo1();
foo2();
} else {
bar1();
bar2();
}
while (false) {
baz3();
baz4();
}
}""",
TestMode.ENTER: """
@0function() @1{
@2if (@3true) @4{
@5@6@7foo1();
@8@9@10foo2();
} else @11{
@12@13@14bar1();
@15@16@17bar2();
}
@18while (@19false) @20{
@21@22@23baz3();
@24@25@26baz4();
}
}""",
TestMode.DELIMITER: """
function() {
if (true) {
foo1();
foo2();
} else {
bar1();
bar2();
}
while (false) {
baz3();
baz4();
}
@0}""",
TestMode.EXIT: """
function() {
if (true@3) {
foo1@7()@6;
@5 foo2@10()@9;
@8 }@4 else {
bar1@14()@13;
@12 bar2@17()@16;
@15 }@11
@2 while (false@19) {
baz3@23()@22;
@21 baz4@26()@25;
@24 }@20
@18}@1@0""",
},
];
void check(Map<TestMode, String> map) {
String code = map[TestMode.NONE];
JavaScriptPrintingOptions options = new JavaScriptPrintingOptions();
Node node = js.parseForeignJS(code).instantiate({});
map.forEach((TestMode mode, String expectedOutput) {
Context context = new Context(mode);
new Printer(options, context).visit(node);
expect(context.getText(), equals(expectedOutput),
reason: "Unexpected output for $code in $mode");
});
}
class Context extends SimpleJavaScriptPrintingContext {
final TestMode mode;
final Map<Node, int> idMap = {};
final Map<int, List<String>> tagMap = {};
Context(this.mode);
int id(Node node) => idMap.putIfAbsent(node, () => idMap.length);
String tag(int value) => '@$value';
void enterNode(Node node, int startPosition) {
int value = id(node);
if (mode == TestMode.ENTER) {
tagMap.putIfAbsent(startPosition, () => []).add(tag(value));
}
}
void exitNode(Node node,
int startPosition,
int endPosition,
int delimiterPosition) {
int value = id(node);
if (mode == TestMode.DELIMITER && delimiterPosition != null) {
tagMap.putIfAbsent(delimiterPosition, () => []).add(tag(value));
} else if (mode == TestMode.EXIT) {
tagMap.putIfAbsent(endPosition, () => []).add(tag(value));
}
}
String getText() {
String text = super.getText();
int offset = 0;
StringBuffer sb = new StringBuffer();
for (int position in tagMap.keys.toList()..sort()) {
if (offset < position) {
sb.write(text.substring(offset, position));
}
tagMap[position].forEach((String tag) => sb.write(tag));
offset = position;
}
if (offset < text.length) {
sb.write(text.substring(offset));
}
return sb.toString();
}
}
void main() {
DATA.forEach(check);
}