Add the dart: api doc code sample validation to the CI.

Change-Id: Ib2a97728d35d15e6cda247444a00ca813d88b9d3
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/218325
Reviewed-by: Michael Thomsen <mit@google.com>
Commit-Queue: Devon Carew <devoncarew@google.com>
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index ab04c56..448629c 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -3470,6 +3470,20 @@
           ]
         },
         {
+          "name": "validate SDK API doc code samples",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
+          "arguments": [
+            "tools/verify_docs/bin/verify_docs.dart",
+            "sdk/lib/_internal",
+            "sdk/lib/cli",
+            "sdk/lib/convert",
+            "sdk/lib/ffi",
+            "sdk/lib/js",
+            "sdk/lib/math",
+            "sdk/lib/mirrors"
+          ]
+        },
+        {
           "name": "validate SDK API data-driven fixes",
           "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
diff --git a/tools/verify_docs/bin/verify_docs.dart b/tools/verify_docs/bin/verify_docs.dart
index aee1176..c23b102 100644
--- a/tools/verify_docs/bin/verify_docs.dart
+++ b/tools/verify_docs/bin/verify_docs.dart
@@ -55,7 +55,7 @@
 
   var hadErrors = false;
   for (final dir in coreLibraries) {
-    hadErrors |= await validateLibrary(dir);
+    hadErrors |= !(await validateLibrary(dir));
   }
 
   exitCode = hadErrors ? 1 : 0;
@@ -69,16 +69,16 @@
   print('## dart:$libName');
   print('');
 
-  var hadErrors = false;
+  var validDocs = true;
 
   for (final file in dir
       .listSync(recursive: true)
       .whereType<File>()
       .where((file) => file.path.endsWith('.dart'))) {
-    hadErrors |= await verifyFile(analysisHelper, libName, file, dir);
+    validDocs &= await verifyFile(analysisHelper, libName, file, dir);
   }
 
-  return hadErrors;
+  return validDocs;
 }
 
 Future<bool> verifyFile(
@@ -113,12 +113,7 @@
     sampleAssumptions,
   );
   await visitor.process(parseResult);
-  if (visitor.errors.isNotEmpty) {
-    print('${path.relative(file.path, from: parent.parent.path)}');
-    print('${visitor.errors.toString()}');
-  }
-
-  return visitor.errors.isEmpty;
+  return !visitor.hadErrors;
 }
 
 /// Visit a compilation unit and validate the code samples found in dartdoc
@@ -131,7 +126,7 @@
   final String? sampleAssumptions;
 
   final List<CodeSample> samples = [];
-  final StringBuffer errors = StringBuffer();
+  bool hadErrors = false;
 
   ValidateCommentCodeSamplesVisitor(
     this.analysisHelper,
@@ -283,6 +278,8 @@
       if (errors.isNotEmpty) {
         print('$filePath:${sample.lineStartOffset}: ${errors.length} errors');
 
+        hadErrors = true;
+
         errors = errors.toList()
           ..sort(
             (a, b) => a.offset - b.offset,
@@ -381,18 +378,23 @@
   final String libraryName;
   final resourceProvider =
       OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
+  final pathRoot = Platform.isWindows ? r'c:\' : '/';
   late AnalysisContextCollection collection;
   int index = 0;
 
   AnalysisHelper(this.libraryName) {
+    resourceProvider.pathContext;
+
     collection = AnalysisContextCollection(
-      includedPaths: ['/$libraryName'],
+      includedPaths: ['$pathRoot$libraryName'],
       resourceProvider: resourceProvider,
     );
   }
 
   Future<SomeResolvedUnitResult> resolveFile(String contents) async {
-    final samplePath = '/$libraryName/sample_${index++}.dart';
+    final samplePath =
+        '$pathRoot$libraryName${resourceProvider.pathContext.separator}'
+        'sample_${index++}.dart';
     resourceProvider.setOverlay(
       samplePath,
       content: contents,