blob: 02ee164b17b6f658a0ca03c3b40812ebacbc91c0 [file] [log] [blame]
// Copyright (c) 2023, 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.
import 'package:expect/expect.dart';
import 'package:js_ast/js_ast.dart';
class Source implements JavaScriptNodeSourceInformation {
final Object tag;
Source(this.tag);
@override
String toString() => 'Source($tag)';
}
void check(Node node, expectedSource, expectedAnnotations) {
Expect.equals('$expectedSource', '${node.sourceInformation}', 'source');
Expect.equals('$expectedAnnotations', '${node.annotations}', 'annotations');
}
void simpleTests(Node node) {
check(node, null, []);
final s1 = node.withSourceInformation(Source(1));
check(node, null, []);
check(s1, Source(1), []);
final a1 = node.withAnnotation(1);
check(node, null, []);
check(s1, Source(1), []);
check(a1, null, [1]);
final a2 = node.withAnnotation(2);
check(node, null, []);
check(s1, Source(1), []);
check(a1, null, [1]);
check(a2, null, [2]);
final s1a3 = s1.withAnnotation(3);
check(node, null, []);
check(s1, Source(1), []);
check(s1, Source(1), []);
check(a2, null, [2]);
check(s1a3, Source(1), [3]);
final s1a3a4 = s1a3.withAnnotation(4);
check(node, null, []);
check(s1, Source(1), []);
check(s1, Source(1), []);
check(a2, null, [2]);
check(s1a3, Source(1), [3]);
check(s1a3a4, Source(1), [3, 4]);
final a2s5 = a2.withSourceInformation(Source(5));
check(node, null, []);
check(s1, Source(1), []);
check(s1, Source(1), []);
check(a2, null, [2]);
check(s1a3, Source(1), [3]);
check(s1a3a4, Source(1), [3, 4]);
check(a2s5, Source(5), [2]);
}
bool debugging = false;
/// Explore all combinations of withSourceInformation and withAnnotation.
void testGraph(Node root) {
// At each node in the graph, all the previous checks are re-run to ensure
// that source information or annotations do not change.
List<void Function(String state)> tests = [];
void explore(
String state,
Node node,
int sourceDepth,
int annotationDepth,
JavaScriptNodeSourceInformation? expectedSource,
List<Object> expectedAnnotations) {
void newCheck(String currentState) {
if (debugging) {
print('In state $currentState check $state:'
' source: $expectedSource, annotations: $expectedAnnotations');
}
Expect.equals(
'$expectedSource',
'${node.sourceInformation}',
' at state $currentState for node at state $state:'
' ${node.debugPrint()}');
Expect.equals(
'$expectedAnnotations',
'${node.annotations}',
' at state $currentState for node at state $state:'
' ${node.debugPrint()}');
}
tests.add(newCheck);
for (final test in tests) {
test(state);
}
if (sourceDepth < 3) {
final newSourceDepth = sourceDepth + 1;
final newSource = Source(newSourceDepth);
final newState = '$state-s$newSourceDepth';
final newNode = node.withSourceInformation(newSource);
explore(newState, newNode, newSourceDepth, annotationDepth, newSource,
expectedAnnotations);
}
if (annotationDepth < 3) {
final newAnnotationDepth = annotationDepth + 1;
final newAnnotation = 'a:$newAnnotationDepth';
final newAnnotations = [...expectedAnnotations, newAnnotation];
final newState = '$state-a$newAnnotationDepth';
final newNode = node.withAnnotation(newAnnotation);
explore(newState, newNode, sourceDepth, newAnnotationDepth,
expectedSource, newAnnotations);
}
}
explore('root', root, 0, 0, null, []);
}
void main() {
simpleTests(js('x + 1'));
simpleTests(js.statement('f()'));
testGraph(js('1'));
testGraph(js('x + 1'));
testGraph(js('f()'));
testGraph(js.statement('f()'));
testGraph(js.statement('break'));
}