Make UriMapper and StdoutHandler public and add test cases (#26932)

diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart
index 82254de..b08f028 100644
--- a/packages/flutter_tools/lib/src/compile.dart
+++ b/packages/flutter_tools/lib/src/compile.dart
@@ -63,8 +63,9 @@
   final int errorCount;
 }
 
-class _StdoutHandler {
-  _StdoutHandler({this.consumer = printError}) {
+/// Handles stdin/stdout communication with the frontend server.
+class StdoutHandler {
+  StdoutHandler({this.consumer = printError}) {
     reset();
   }
 
@@ -90,8 +91,7 @@
         CompilerOutput(
           message.substring(boundaryKey.length + 1, spaceDelimiter),
           int.parse(message.substring(spaceDelimiter + 1).trim())));
-    }
-    else if (!_suppressCompilerMessages) {
+    } else if (!_suppressCompilerMessages) {
       if (compilerMessageReceived == false) {
         consumer('\nCompiler message:');
         compilerMessageReceived = true;
@@ -110,9 +110,9 @@
   }
 }
 
-// Converts filesystem paths to package URIs.
-class _PackageUriMapper {
-  _PackageUriMapper(String scriptPath, String packagesPath) {
+/// Converts filesystem paths to package URIs.
+class PackageUriMapper {
+  PackageUriMapper(String scriptPath, String packagesPath) {
     final Map<String, Uri> packageMap = PackageMap(fs.path.absolute(packagesPath)).map;
     final String scriptUri = Uri.file(scriptPath, windows: platform.isWindows).toString();
 
@@ -132,7 +132,6 @@
   Uri map(String scriptPath) {
     if (_packageName == null)
       return null;
-
     final String scriptUri = Uri.file(scriptPath, windows: platform.isWindows).toString();
     if (scriptUri.startsWith(_uriPrefix)) {
       return Uri.parse('package:$_packageName/${scriptUri.substring(_uriPrefix.length)}');
@@ -142,7 +141,7 @@
   }
 
   static Uri findUri(String scriptPath, String packagesPath) {
-    return _PackageUriMapper(scriptPath, packagesPath).map(scriptPath);
+    return PackageUriMapper(scriptPath, packagesPath).map(scriptPath);
   }
 }
 
@@ -224,7 +223,7 @@
     Uri mainUri;
     if (packagesPath != null) {
       command.addAll(<String>['--packages', packagesPath]);
-      mainUri = _PackageUriMapper.findUri(mainPath, packagesPath);
+      mainUri = PackageUriMapper.findUri(mainPath, packagesPath);
     }
     if (outputFilePath != null) {
       command.addAll(<String>['--output-dill', outputFilePath]);
@@ -253,7 +252,7 @@
       printError('Failed to start frontend server $error, $stack');
     });
 
-    final _StdoutHandler _stdoutHandler = _StdoutHandler();
+    final StdoutHandler _stdoutHandler = StdoutHandler();
 
     server.stderr
       .transform<String>(utf8.decoder)
@@ -340,7 +339,7 @@
        _fileSystemRoots = fileSystemRoots,
        _fileSystemScheme = fileSystemScheme,
        _targetModel = targetModel,
-       _stdoutHandler = _StdoutHandler(consumer: compilerMessageConsumer),
+       _stdoutHandler = StdoutHandler(consumer: compilerMessageConsumer),
        _controller = StreamController<_CompilationRequest>(),
        _initializeFromDill = initializeFromDill,
        _unsafePackageSerialization = unsafePackageSerialization,
@@ -357,7 +356,7 @@
   final String _fileSystemScheme;
   String _sdkRoot;
   Process _server;
-  final _StdoutHandler _stdoutHandler;
+  final StdoutHandler _stdoutHandler;
   String _initializeFromDill;
   bool _unsafePackageSerialization;
   final List<String> _experimentalFlags;
@@ -390,9 +389,9 @@
 
     // First time recompile is called we actually have to compile the app from
     // scratch ignoring list of invalidated files.
-    _PackageUriMapper packageUriMapper;
+    PackageUriMapper packageUriMapper;
     if (request.packagesFilePath != null) {
-      packageUriMapper = _PackageUriMapper(request.mainPath, request.packagesFilePath);
+      packageUriMapper = PackageUriMapper(request.mainPath, request.packagesFilePath);
     }
 
     if (_server == null) {
@@ -560,11 +559,11 @@
     _server?.stdin?.writeln('reset');
   }
 
-  String _mapFilename(String filename, _PackageUriMapper packageUriMapper) {
+  String _mapFilename(String filename, PackageUriMapper packageUriMapper) {
     return _doMapFilename(filename, packageUriMapper) ?? filename;
   }
 
-  String _mapFileUri(String fileUri, _PackageUriMapper packageUriMapper) {
+  String _mapFileUri(String fileUri, PackageUriMapper packageUriMapper) {
     String filename;
     try {
       filename = Uri.parse(fileUri).toFilePath();
@@ -574,7 +573,7 @@
     return _doMapFilename(filename, packageUriMapper) ?? fileUri;
   }
 
-  String _doMapFilename(String filename, _PackageUriMapper packageUriMapper) {
+  String _doMapFilename(String filename, PackageUriMapper packageUriMapper) {
     if (packageUriMapper != null) {
       final Uri packageUri = packageUriMapper.map(filename);
       if (packageUri != null)
diff --git a/packages/flutter_tools/test/compile_test.dart b/packages/flutter_tools/test/compile_test.dart
index b1ca663..bd99156 100644
--- a/packages/flutter_tools/test/compile_test.dart
+++ b/packages/flutter_tools/test/compile_test.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 import 'dart:convert';
 
+import 'package:flutter_tools/src/base/file_system.dart';
 import 'package:flutter_tools/src/base/io.dart';
 import 'package:flutter_tools/src/base/context.dart';
 import 'package:flutter_tools/src/base/logger.dart';
@@ -20,6 +21,50 @@
 final Generator _kNoColorTerminalPlatform = () => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false;
 
 void main() {
+  group(PackageUriMapper, () {
+    const String packagesContents = r'''
+xml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/xml-3.2.3/lib/
+yaml:file:///Users/flutter_user/.pub-cache/hosted/pub.dartlang.org/yaml-2.1.15/lib/
+example:file:///example/lib/
+''';
+    final MockFileSystem mockFileSystem = MockFileSystem();
+    final MockFile mockFile = MockFile();
+    when(mockFileSystem.path).thenReturn(fs.path);
+    when(mockFileSystem.file(any)).thenReturn(mockFile);
+    when(mockFile.readAsBytesSync()).thenReturn(utf8.encode(packagesContents));
+
+    testUsingContext('Can map main.dart to correct package', () async {
+      final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages');
+      expect(packageUriMapper.map('/example/lib/main.dart').toString(), 'package:example/main.dart');
+    }, overrides: <Type, Generator>{
+      FileSystem: () => mockFileSystem,
+    });
+
+    testUsingContext('Maps file from other package to null', () async {
+      final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages');
+      expect(packageUriMapper.map('/xml/lib/xml.dart'),  null);
+    }, overrides: <Type, Generator>{
+      FileSystem: () => mockFileSystem,
+    });
+
+    testUsingContext('Maps non-main file from same package', () async {
+      final PackageUriMapper packageUriMapper = PackageUriMapper('/example/lib/main.dart', '.packages');
+      expect(packageUriMapper.map('/example/lib/src/foo.dart').toString(), 'package:example/src/foo.dart');
+    }, overrides: <Type, Generator>{
+      FileSystem: () => mockFileSystem,
+    });
+  });
+
+  test(StdoutHandler, () async {
+    final StdoutHandler stdoutHandler = StdoutHandler();
+    stdoutHandler.handler('result 12345');
+    expect(stdoutHandler.boundaryKey, '12345');
+    stdoutHandler.handler('12345 message 0');
+    final CompilerOutput output = await stdoutHandler.compilerOutput.future;
+    expect(output.errorCount, 0);
+    expect(output.outputFilename, 'message');
+  });
+
   group('batch compile', () {
     ProcessManager mockProcessManager;
     MockProcess mockFrontendServer;
@@ -458,3 +503,5 @@
     _stdInWrites.writeln(o);
   }
 }
+class MockFileSystem extends Mock implements FileSystem {}
+class MockFile extends Mock implements File {}