dont fall back on the wrapped file system when the uri is the multi-uri scheme

Bug: b/130291059
Change-Id: I10f276c36239cd60ae0adf795dc32c462e078ef4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99087
Commit-Queue: Jake Macdonald <jakemac@google.com>
Auto-Submit: Jake Macdonald <jakemac@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/build_integration/lib/file_system/multi_root.dart b/pkg/build_integration/lib/file_system/multi_root.dart
index ed1bb8c..b5edb1b 100644
--- a/pkg/build_integration/lib/file_system/multi_root.dart
+++ b/pkg/build_integration/lib/file_system/multi_root.dart
@@ -52,7 +52,11 @@
       _delegate ??= await _resolveEntity();
 
   Future<FileSystemEntity> _resolveEntity() async {
-    if (uri.scheme == multiRootFileSystem.markerScheme && uri.isAbsolute) {
+    if (uri.scheme == multiRootFileSystem.markerScheme) {
+      if (!uri.isAbsolute) {
+        throw new FileSystemException(
+            uri, "This MultiRootFileSystem only handles absolutes URIs: $uri");
+      }
       var original = multiRootFileSystem.original;
       assert(uri.path.startsWith('/'));
       var path = uri.path.substring(1);
@@ -60,6 +64,7 @@
         var candidate = original.entityForUri(root.resolve(path));
         if (await candidate.exists()) return candidate;
       }
+      return MissingFileSystemEntity(uri);
     }
     return multiRootFileSystem.original.entityForUri(uri);
   }
@@ -76,6 +81,24 @@
   Future<String> readAsString() async => (await delegate).readAsString();
 }
 
+class MissingFileSystemEntity implements FileSystemEntity {
+  @override
+  final Uri uri;
+
+  MissingFileSystemEntity(this.uri);
+
+  @override
+  Future<bool> exists() => Future.value(false);
+
+  @override
+  Future<List<int>> readAsBytes() =>
+      Future.error(FileSystemException(uri, 'File not found'));
+
+  @override
+  Future<String> readAsString() =>
+      Future.error(FileSystemException(uri, 'File not found'));
+}
+
 Uri _normalize(root) {
   Uri uri = root;
   return uri.path.endsWith('/') ? uri : uri.replace(path: '${uri.path}/');
diff --git a/pkg/build_integration/pubspec.yaml b/pkg/build_integration/pubspec.yaml
index b746b5c..722a284 100644
--- a/pkg/build_integration/pubspec.yaml
+++ b/pkg/build_integration/pubspec.yaml
@@ -10,3 +10,6 @@
 
 dependencies:
   front_end: ^0.1.0
+
+dev_dependencies:
+  test: any
diff --git a/pkg/build_integration/test/file_system/multi_root_test.dart b/pkg/build_integration/test/file_system/multi_root_test.dart
index e86fc3f..e92249a 100644
--- a/pkg/build_integration/test/file_system/multi_root_test.dart
+++ b/pkg/build_integration/test/file_system/multi_root_test.dart
@@ -8,6 +8,7 @@
 
 import 'package:build_integration/file_system/multi_root.dart';
 import 'package:front_end/src/api_prototype/memory_file_system.dart';
+import 'package:front_end/src/api_prototype/file_system.dart';
 
 import 'package:test/test.dart';
 
@@ -122,4 +123,17 @@
     expect(await effectiveUriOf('multi-root:///../../A/B/a/8.dart'),
         'multi-root:///A/B/a/8.dart');
   });
+
+  test('multi-root handles all multi-root scheme uris, even if missing',
+      () async {
+    expect(await effectiveUriOf('multi-root:///doesnt/exist.dart'),
+        'multi-root:///doesnt/exist.dart');
+    expect(await exists('multi-root:///doesnt/exist.dart'), isFalse);
+    expect(
+        read('multi-root:///doesnt/exist.dart'),
+        throwsA(const TypeMatcher<FileSystemException>()
+            .having((e) => e.message, 'message', 'File not found')
+            .having((e) => e.uri, 'uri',
+                equals(Uri.parse('multi-root:///doesnt/exist.dart')))));
+  });
 }