[dart2js] Adding tests for angularInfo conversion for runtime coverage

Change-Id: I143565cb2c36c551ed7e1189ffbcf64fb9b2a5de
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/252560
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Mark Zhou <markzipan@google.com>
diff --git a/pkg/dart2js_info/pubspec.yaml b/pkg/dart2js_info/pubspec.yaml
index 04e3c7b..68bab56 100644
--- a/pkg/dart2js_info/pubspec.yaml
+++ b/pkg/dart2js_info/pubspec.yaml
@@ -20,6 +20,7 @@
 
 # Use 'any' constraints here; we get our versions from the DEPS file.
 dev_dependencies:
+  expect: any
   lints: any
   test: any
 
diff --git a/pkg/dart2js_info/test/classes/class_filter.txt b/pkg/dart2js_info/test/classes/class_filter.txt
new file mode 100644
index 0000000..aa011aa
--- /dev/null
+++ b/pkg/dart2js_info/test/classes/class_filter.txt
@@ -0,0 +1,5 @@
+dart:_rti - _Universe
+dart:core - Error
+testroot:classes.dart - Subsub1
+testroot:classes.dart - Super
+package:expect/expect.dart - Expect
diff --git a/pkg/dart2js_info/test/classes/classes.dart b/pkg/dart2js_info/test/classes/classes.dart
new file mode 100644
index 0000000..d7b49e0
--- /dev/null
+++ b/pkg/dart2js_info/test/classes/classes.dart
@@ -0,0 +1,45 @@
+import 'package:expect/expect.dart';
+
+class Super<T> {
+  void method(T t) {
+    print(t.runtimeType);
+  }
+}
+
+class Mixin {
+  void method(int t) {
+    print(t + 1);
+  }
+}
+
+class Clazz = Super<int> with Mixin;
+
+class Subclass extends Clazz {
+  void test() {
+    void Function(int) f = super.method;
+    f(42);
+    print(f);
+  }
+}
+
+class Subsub1 extends Subclass {
+  void a(dynamic x) {
+    print(x);
+  }
+}
+
+class Subsub2 extends Subclass {
+  void a(dynamic x) {
+    print(x);
+    print(x);
+  }
+}
+
+main() {
+  Super<Object> s = Subclass()..test();
+  Expect.throws(() => s.method(''));
+  dynamic x = Subsub1();
+  x.a(x);
+  x = Subsub2();
+  x.a(x);
+}
diff --git a/pkg/dart2js_info/test/classes/classes.js.info.data b/pkg/dart2js_info/test/classes/classes.js.info.data
new file mode 100644
index 0000000..cc738e1
--- /dev/null
+++ b/pkg/dart2js_info/test/classes/classes.js.info.data
Binary files differ
diff --git a/pkg/dart2js_info/test/runtime_coverage_test.dart b/pkg/dart2js_info/test/runtime_coverage_test.dart
new file mode 100644
index 0000000..9d5d048
--- /dev/null
+++ b/pkg/dart2js_info/test/runtime_coverage_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2022, 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.
+
+// Tests for dart2js_info's runtime_coverage command.
+//
+// Regenerate files with dart2js flags:
+// --multi-root-scheme='testroot'
+// --multi-root='$PATH_TO_TEST_ROOT'
+// --entry-uri='testroot:$TEST_FILE.dart'
+// --dump-info=binary
+// --packages=$PATH_TO_SDK/.dart_tool/package_config.json
+
+import 'dart:io';
+
+import 'package:dart2js_info/binary_serialization.dart';
+import 'package:dart2js_info/src/util.dart';
+import 'package:test/test.dart';
+
+import '../bin/src/runtime_coverage_analysis.dart';
+
+void main() {
+  group('runtime coverage', () {
+    group('class filter (angular info)', () {
+      final infoBinaryFile =
+          File.fromUri(Platform.script.resolve('classes/classes.js.info.data'));
+      final allInfo = decode(infoBinaryFile.readAsBytesSync());
+      final classFilters =
+          File.fromUri(Platform.script.resolve('classes/class_filter.txt'))
+              .readAsLinesSync();
+      final runtimeClassInfos = <String, RuntimeClassInfo>{};
+
+      setUp(() {
+        runtimeClassInfos.clear();
+      });
+
+      test('class filters are formatted properly', () {
+        for (final filterString in classFilters) {
+          expect(filterString.contains(' - '), isTrue);
+        }
+      });
+
+      test('AngularInfo conversions throws on invalid schemes', () {
+        expect(
+            () => RuntimeClassInfo.fromAngularInfo(
+                'no/scheme/here.dart - ClassName'),
+            throwsArgumentError);
+        expect(
+            () => RuntimeClassInfo.fromAngularInfo('noscheme.dart - ClassName'),
+            throwsArgumentError);
+      });
+
+      test('class filters parse and annotate properly', () {
+        // Process class filters.
+        for (final filterString in classFilters) {
+          final runtimeClassInfo =
+              RuntimeClassInfo.fromAngularInfo(filterString);
+          expect(runtimeClassInfo.annotated, isFalse);
+          runtimeClassInfos[runtimeClassInfo.key] = runtimeClassInfo;
+        }
+
+        // Annotate class filters with their corresponding ClassInfo.
+        for (final classInfo in allInfo.classes) {
+          final name = qualifiedName(classInfo);
+          final nameWithoutScheme =
+              name.substring(name.indexOf(':') + 1, name.length);
+          final runtimeClassInfo = runtimeClassInfos[nameWithoutScheme];
+          if (runtimeClassInfo != null) {
+            runtimeClassInfo.annotateWithClassInfo(classInfo);
+            expect(runtimeClassInfos[runtimeClassInfo.key], isNotNull);
+          }
+        }
+
+        // Check that all class info objects are annotated.
+        for (final runtimeClassInfo in runtimeClassInfos.values) {
+          expect(runtimeClassInfo.annotated, isTrue);
+        }
+      });
+    });
+  });
+}