| // 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')); | |
| } |