File: CompilerServerTests.cs
Web Access
Project: src\src\Compilers\Server\VBCSCompilerTests\VBCSCompiler.UnitTests.csproj (VBCSCompiler.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
#nullable disable
 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Basic.Reference.Assemblies;
using Castle.Core.Resource;
using Microsoft.CodeAnalysis.CommandLine;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.CodeAnalysis.CompilerServer.UnitTests
{
    public class CompilerServerUnitTests : TestBase
    {
        internal static readonly RequestLanguage CSharpCompilerClientExecutable = RequestLanguage.CSharpCompile;
 
        internal static readonly RequestLanguage BasicCompilerClientExecutable = RequestLanguage.VisualBasicCompile;
 
        internal static readonly UTF8Encoding UTF8Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
 
        private static readonly KeyValuePair<string, string>[] s_helloWorldSrcCs =
        {
            new KeyValuePair<string, string>("hello.cs",
@"using System;
using System.Diagnostics;
class Hello
{
    static void Main()
    {
        var obj = new Process();
        Console.WriteLine(""Hello, world.""); 
    }
}")
        };
 
        private static readonly KeyValuePair<string, string>[] s_helloWorldSrcVb =
        {
            new KeyValuePair<string, string>("hello.vb",
@"Imports System
Imports System.Diagnostics
 
Module Module1
    Sub Main()
        Dim p As New Process()
        Console.WriteLine(""Hello from VB"")
    End Sub
End Module")
        };
 
        private readonly TempDirectory _tempDirectory;
        private readonly ICompilerServerLogger _logger;
 
        public CompilerServerUnitTests(ITestOutputHelper testOutputHelper)
        {
            _tempDirectory = Temp.CreateDirectory();
            _logger = new XunitCompilerServerLogger(testOutputHelper);
        }
 
        #region Helpers
 
        private static void CheckForBadShared(List<string> arguments)
        {
            bool hasShared;
            string keepAlive;
            string errorMessage;
            string pipeName;
            List<string> parsedArgs;
            if (CommandLineParser.TryParseClientArgs(
                    arguments,
                    out parsedArgs,
                    out hasShared,
                    out keepAlive,
                    out pipeName,
                    out errorMessage))
            {
                if (hasShared && string.IsNullOrEmpty(pipeName))
                {
                    throw new InvalidOperationException("Must specify a pipe name in these suites to ensure we're not running out of proc servers");
                }
            }
        }
 
        private static void ReferenceNetstandardDllIfCoreClr(TempDirectory currentDirectory, List<string> arguments)
        {
#if !NET472
            var filePath = Path.Combine(currentDirectory.Path, "netstandard.dll");
            File.WriteAllBytes(filePath, NetStandard20.Resources.netstandard);
            arguments.Add("/nostdlib");
            arguments.Add("/r:netstandard.dll");
#endif
        }
 
        private static void CreateFiles(TempDirectory currentDirectory, IEnumerable<KeyValuePair<string, string>> files)
        {
            if (files != null)
            {
                foreach (var pair in files)
                {
                    TempFile file = currentDirectory.CreateFile(pair.Key);
                    file.WriteAllText(pair.Value);
                }
            }
        }
 
        private static T ApplyEnvironmentVariables<T>(
            IEnumerable<KeyValuePair<string, string>> environmentVariables,
            Func<T> func)
        {
            if (environmentVariables == null)
            {
                return func();
            }
 
            var resetVariables = new Dictionary<string, string>();
            try
            {
                foreach (var variable in environmentVariables)
                {
                    resetVariables.Add(variable.Key, Environment.GetEnvironmentVariable(variable.Key));
                    Environment.SetEnvironmentVariable(variable.Key, variable.Value);
                }
 
                return func();
            }
            finally
            {
                foreach (var variable in resetVariables)
                {
                    Environment.SetEnvironmentVariable(variable.Key, variable.Value);
                }
            }
        }
 
        private static (T Result, string Output) UseTextWriter<T>(Encoding encoding, Func<TextWriter, T> func)
        {
            MemoryStream memoryStream;
            TextWriter writer;
            if (encoding == null)
            {
                memoryStream = null;
                writer = new StringWriter();
            }
            else
            {
                memoryStream = new MemoryStream();
                writer = new StreamWriter(memoryStream, encoding);
            }
 
            var result = func(writer);
            writer.Flush();
            if (memoryStream != null)
            {
                return (result, encoding.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length));
            }
            else
            {
                return (result, ((StringWriter)writer).ToString());
            }
        }
 
        internal (int ExitCode, string Output) RunCommandLineCompiler(
            RequestLanguage language,
            string argumentsSingle,
            TempDirectory currentDirectory,
            IEnumerable<KeyValuePair<string, string>> filesInDirectory = null,
            IEnumerable<KeyValuePair<string, string>> additionalEnvironmentVars = null,
            Encoding redirectEncoding = null,
            bool shouldRunOnServer = true)
        {
            var arguments = new List<string>(argumentsSingle.Split(' '));
 
            // This is validating that localization to a specific locale works no matter what the locale of the 
            // machine running the tests are. 
            arguments.Add("/preferreduilang:en");
 
            ReferenceNetstandardDllIfCoreClr(currentDirectory, arguments);
            CheckForBadShared(arguments);
            CreateFiles(currentDirectory, filesInDirectory);
 
            var client = ServerUtil.CreateBuildClient(language, _logger);
 
            var sdkDir = ServerUtil.DefaultSdkDirectory;
 
            var buildPaths = new BuildPaths(
                clientDir: Path.GetDirectoryName(typeof(CommonCompiler).Assembly.Location),
                workingDir: currentDirectory.Path,
                sdkDir: sdkDir,
                tempDir: Path.GetTempPath());
 
            var (result, output) = UseTextWriter(redirectEncoding, writer => ApplyEnvironmentVariables(additionalEnvironmentVars, () => client.RunCompilation(arguments, buildPaths, writer)));
            Assert.Equal(shouldRunOnServer, result.RanOnServer);
            return (result.ExitCode, output);
        }
 
        /// <summary>
        /// Compiles some source code and returns the bytes that were contained in the compiled DLL file.
        /// 
        /// Each time that this function is called, it will be compiled in a different directory.
        /// 
        /// The default flags are "/shared /deterministic+ /nologo /t:library".
        /// </summary>
        /// <param name="source"> The source code for the program that will be compiled </param>
        /// <returns> An array of bytes that were read from the compiled DLL</returns>
        private async Task<(byte[] assemblyBytes, string finalFlags)> CompileAndGetBytes(string source, string flags)
        {
            // Setup
            var tempDir = Temp.CreateDirectory();
            var srcFile = tempDir.CreateFile("test.cs").WriteAllText(source).Path;
            var outFile = srcFile.Replace("test.cs", "test.dll");
 
            try
            {
                string finalFlags = null;
                using (var serverData = await ServerUtil.CreateServer(_logger))
                {
                    finalFlags = $"{flags} /shared:{serverData.PipeName} /pathmap:{tempDir.Path}=/ /out:{outFile} {srcFile}";
                    var result = RunCommandLineCompiler(
                        CSharpCompilerClientExecutable,
                        finalFlags,
                        currentDirectory: tempDir);
                    if (result.ExitCode != 0)
                    {
                        AssertEx.Fail($"Deterministic compile failed \n stdout:  {result.Output}");
                    }
                    var listener = await serverData.Complete();
                    Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
                }
                var bytes = File.ReadAllBytes(outFile);
                AssertEx.NotNull(bytes);
 
                return (bytes, finalFlags);
            }
            finally
            {
                File.Delete(srcFile);
                File.Delete(outFile);
            }
        }
 
        private static DisposableFile GetResultFile(TempDirectory directory, string resultFileName)
        {
            return new DisposableFile(Path.Combine(directory.Path, resultFileName));
        }
 
        private static void RunCompilerOutput(TempFile file, string expectedOutput)
        {
            if (RuntimeHostInfo.IsDesktopRuntime)
            {
                var result = ProcessUtilities.Run(file.Path, "", Path.GetDirectoryName(file.Path));
                Assert.Equal(expectedOutput.Trim(), result.Output.Trim());
            }
        }
 
        private static void VerifyResult((int ExitCode, string Output) result)
        {
            AssertEx.AssertEqualToleratingWhitespaceDifferences("", result.Output);
            Assert.Equal(0, result.ExitCode);
        }
 
        private void VerifyResultAndOutput((int ExitCode, string Output) result, TempDirectory path, string expectedOutput)
        {
            using (var resultFile = GetResultFile(path, "hello.exe"))
            {
                VerifyResult(result);
 
                RunCompilerOutput(resultFile, expectedOutput);
            }
        }
 
        #endregion
 
        [ConditionalFact(typeof(UnixLikeOnly))]
        public async Task ServerFailsWithLongTempPathUnix()
        {
            var newTempDir = _tempDirectory.CreateDirectory(new string('a', 100 - _tempDirectory.Path.Length));
            await ApplyEnvironmentVariables(
                new[] { new KeyValuePair<string, string>("TMPDIR", newTempDir.Path) },
                async () => await Task.Run(async () =>
            {
                using var serverData = await ServerUtil.CreateServer(_logger);
                var result = RunCommandLineCompiler(
                    CSharpCompilerClientExecutable,
                    $"/shared:{serverData.PipeName} /nologo hello.cs",
                    _tempDirectory,
                    s_helloWorldSrcCs,
                    shouldRunOnServer: true);
                VerifyResultAndOutput(result, _tempDirectory, "Hello, world.");
 
                var listener = await serverData.Complete();
                Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
            }));
        }
 
        [Fact]
        public async Task FallbackToCsc()
        {
            // Verify csc will fall back to command line when server fails to process
            var testableCompilerServerHost = new TestableCompilerServerHost(delegate { throw new Exception(); });
            using var serverData = await ServerUtil.CreateServer(_logger, compilerServerHost: testableCompilerServerHost);
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"/shared:{serverData.PipeName} /nologo hello.cs", _tempDirectory, s_helloWorldSrcCs, shouldRunOnServer: false);
            VerifyResultAndOutput(result, _tempDirectory, "Hello, world.");
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestError, listener.CompletionDataList.Single());
        }
 
        [Fact]
        public async Task CscFallBackOutputNoUtf8()
        {
            // Verify csc will fall back to command line when server fails to process
            var testableCompilerServerHost = new TestableCompilerServerHost(delegate { throw new Exception(); });
            using var serverData = await ServerUtil.CreateServer(_logger, compilerServerHost: testableCompilerServerHost);
 
            var files = new Dictionary<string, string> { { "hello.cs", "♕" } };
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"/shared:{serverData.PipeName} /nologo hello.cs", _tempDirectory, files, redirectEncoding: Encoding.ASCII, shouldRunOnServer: false);
            Assert.Equal(1, result.ExitCode);
            Assert.Equal("hello.cs(1,1): error CS1056: Unexpected character '?'", result.Output.Trim());
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestError, listener.CompletionDataList.Single());
        }
 
        [Fact]
        public async Task CscFallBackOutputUtf8()
        {
            var srcFile = _tempDirectory.CreateFile("test.cs").WriteAllText("♕").Path;
 
            var testableCompilerServerHost = new TestableCompilerServerHost(delegate { throw new Exception(); });
            using var serverData = await ServerUtil.CreateServer(_logger, compilerServerHost: testableCompilerServerHost);
            var result = RunCommandLineCompiler(
                CSharpCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /utf8output /nologo /t:library {srcFile}",
                _tempDirectory,
                redirectEncoding: UTF8Encoding,
                shouldRunOnServer: false);
 
            Assert.Equal("test.cs(1,1): error CS1056: Unexpected character '♕'".Trim(),
                result.Output.Trim().Replace(srcFile, "test.cs"));
            Assert.Equal(1, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestError, listener.CompletionDataList.Single());
        }
 
        [Fact]
        public async Task VbcFallbackNoUtf8()
        {
            var srcFile = _tempDirectory.CreateFile("test.vb").WriteAllText("♕").Path;
 
            var testableCompilerServerHost = new TestableCompilerServerHost(delegate { throw new Exception(); });
            using var serverData = await ServerUtil.CreateServer(_logger, compilerServerHost: testableCompilerServerHost);
            var result = RunCommandLineCompiler(
                BasicCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /vbruntime* /nologo test.vb",
                _tempDirectory,
                redirectEncoding: Encoding.ASCII,
                shouldRunOnServer: false);
 
            Assert.Equal(1, result.ExitCode);
            Assert.Equal(@"test.vb(1) : error BC30037: Character is not valid.
 
?
~", result.Output.Trim().Replace(srcFile, "test.vb"));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestError, listener.CompletionDataList.Single());
        }
 
        [Fact]
        public async Task VbcFallbackUtf8()
        {
            var srcFile = _tempDirectory.CreateFile("test.vb").WriteAllText("♕").Path;
 
            var testableCompilerServerHost = new TestableCompilerServerHost(delegate { throw new Exception(); });
            using var serverData = await ServerUtil.CreateServer(_logger, compilerServerHost: testableCompilerServerHost);
            var result = RunCommandLineCompiler(
                BasicCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /vbruntime* /utf8output /nologo /t:library {srcFile}",
                _tempDirectory,
                redirectEncoding: UTF8Encoding,
                shouldRunOnServer: false);
 
            Assert.Equal(@"test.vb(1) : error BC30037: Character is not valid.
 
♕
~", result.Output.Trim().Replace(srcFile, "test.vb"));
            Assert.Equal(1, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestError, listener.CompletionDataList.Single());
        }
 
        [Fact]
        public async Task FallbackToVbc()
        {
            var testableCompilerServerHost = new TestableCompilerServerHost(delegate { throw new Exception(); });
            using var serverData = await ServerUtil.CreateServer(_logger, compilerServerHost: testableCompilerServerHost);
 
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"/shared:{serverData.PipeName} /nologo /vbruntime* hello.vb", _tempDirectory, s_helloWorldSrcVb, shouldRunOnServer: false);
            VerifyResultAndOutput(result, _tempDirectory, "Hello from VB");
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestError, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task HelloWorldCS()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"/shared:{serverData.PipeName} /nologo hello.cs", _tempDirectory, s_helloWorldSrcCs);
 
            VerifyResultAndOutput(result, _tempDirectory, "Hello, world.");
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task HelloWorldCSDashShared()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"-shared:{serverData.PipeName} /nologo hello.cs", _tempDirectory, s_helloWorldSrcCs);
            VerifyResultAndOutput(result, _tempDirectory, "Hello, world.");
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        [WorkItem(946954, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/946954")]
        public void CompilerBinariesAreNotX86()
        {
            var basePath = Path.GetDirectoryName(typeof(CompilerServerUnitTests).Assembly.Location);
            var compilerServerExecutable = Path.Combine(basePath, "VBCSCompiler.exe");
#pragma warning disable SYSLIB0037
            // warning SYSLIB0037: 'AssemblyName.ProcessorArchitecture' is obsolete: 'AssemblyName members HashAlgorithm, ProcessorArchitecture, and VersionCompatibility are obsolete and not supported.'
            Assert.NotEqual(ProcessorArchitecture.X86,
                AssemblyName.GetAssemblyName(compilerServerExecutable).ProcessorArchitecture);
#pragma warning restore SYSLIB0037
        }
 
        /// <summary>
        /// This method tests that when a 64-bit compiler server loads a 
        /// 64-bit mscorlib with /platform:x86 enabled no warning about
        /// emitting a reference to a 64-bit assembly is produced.
        /// The test should pass on x86 or amd64, but can only fail on
        /// amd64.
        /// </summary>
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task Platformx86MscorlibCsc()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            var files = new Dictionary<string, string> { { "c.cs", "class C {}" } };
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable,
                                                $"/shared:{serverData.PipeName} /nologo /t:library /platform:x86 c.cs",
                                                _tempDirectory,
                                                files);
            VerifyResult(result);
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task Platformx86MscorlibVbc()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            var files = new Dictionary<string, string> { { "c.vb", "Class C\nEnd Class" } };
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable,
                                                $"/shared:{serverData.PipeName} /vbruntime* /nologo /t:library /platform:x86 c.vb",
                                                _tempDirectory,
                                                files);
            VerifyResult(result);
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task ExtraMSCorLibCS()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable,
                                                $"/shared:{serverData.PipeName} /nologo /r:mscorlib.dll hello.cs",
                                                _tempDirectory,
                                                s_helloWorldSrcCs);
            VerifyResultAndOutput(result, _tempDirectory, "Hello, world.");
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task HelloWorldVB()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable,
                                                $"/shared:{serverData.PipeName} /nologo /vbruntime* hello.vb",
                                                _tempDirectory,
                                                s_helloWorldSrcVb);
            VerifyResultAndOutput(result, _tempDirectory, "Hello from VB");
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task ExtraMSCorLibVB()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /nologo /r:mscorlib.dll /vbruntime* hello.vb",
                _tempDirectory,
                s_helloWorldSrcVb);
            VerifyResultAndOutput(result, _tempDirectory, "Hello from VB");
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task CompileErrorsCS()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                       { "hello.cs",
@"using System;
class Hello 
{
    static void Main()
    { Console.WriteLine(""Hello, world."") }
}"}};
 
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"/shared:{serverData.PipeName} hello.cs", _tempDirectory, files);
 
            // Should output errors, but not create output file.
            Assert.Contains("Copyright (C) Microsoft Corporation. All rights reserved.", result.Output, StringComparison.Ordinal);
            Assert.Contains("hello.cs(5,42): error CS1002: ; expected", result.Output, StringComparison.Ordinal);
            Assert.Equal(1, result.ExitCode);
            Assert.False(File.Exists(Path.Combine(_tempDirectory.Path, "hello.exe")));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task CompileErrorsVB()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                       { "hellovb.vb",
@"Imports System
 
Module Module1
Sub Main()
    Console.WriteLine(""Hello from VB"")
End Sub
End Class"}};
 
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"/shared:{serverData.PipeName} /vbruntime* hellovb.vb", _tempDirectory, files);
 
            // Should output errors, but not create output file.
            Assert.Contains("Copyright (C) Microsoft Corporation. All rights reserved.", result.Output, StringComparison.Ordinal);
            Assert.Contains("hellovb.vb(3) : error BC30625: 'Module' statement must end with a matching 'End Module'.", result.Output, StringComparison.Ordinal);
            Assert.Contains("hellovb.vb(7) : error BC30460: 'End Class' must be preceded by a matching 'Class'.", result.Output, StringComparison.Ordinal);
            Assert.Equal(1, result.ExitCode);
            Assert.False(File.Exists(Path.Combine(_tempDirectory.Path, "hello.exe")));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task MissingFileErrorCS()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"/shared:{serverData.PipeName} missingfile.cs", _tempDirectory);
 
            // Should output errors, but not create output file.
            Assert.Contains("Copyright (C) Microsoft Corporation. All rights reserved.", result.Output, StringComparison.Ordinal);
            Assert.Contains("error CS2001: Source file", result.Output, StringComparison.Ordinal);
            Assert.Equal(1, result.ExitCode);
            Assert.False(File.Exists(Path.Combine(_tempDirectory.Path, "missingfile.exe")));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task MissingReferenceErrorCS()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"/shared:{serverData.PipeName} /r:missing.dll hello.cs", _tempDirectory, s_helloWorldSrcCs);
 
            // Should output errors, but not create output file.
            Assert.Contains("Copyright (C) Microsoft Corporation. All rights reserved.", result.Output, StringComparison.Ordinal);
            Assert.Contains("error CS0006: Metadata file", result.Output, StringComparison.Ordinal);
            Assert.Equal(1, result.ExitCode);
            Assert.False(File.Exists(Path.Combine(_tempDirectory.Path, "hello.exe")));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [WorkItem(546067, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546067")]
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task InvalidMetadataFileErrorCS()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                           { "Lib.cs", "public class C {}"},
                                           { "app.cs", "class Test { static void Main() {} }"},
                                           };
 
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"/shared:{serverData.PipeName} /r:Lib.cs app.cs", _tempDirectory, files);
 
            // Should output errors, but not create output file.
            Assert.Contains("Copyright (C) Microsoft Corporation. All rights reserved.", result.Output, StringComparison.Ordinal);
            Assert.Contains("error CS0009: Metadata file", result.Output, StringComparison.Ordinal);
            Assert.Equal(1, result.ExitCode);
            Assert.False(File.Exists(Path.Combine(_tempDirectory.Path, "app.exe")));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task MissingFileErrorVB()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"/shared:{serverData.PipeName} /vbruntime* missingfile.vb", _tempDirectory);
 
            // Should output errors, but not create output file.
            Assert.Contains("Copyright (C) Microsoft Corporation. All rights reserved.", result.Output, StringComparison.Ordinal);
            Assert.Contains("error BC2001", result.Output, StringComparison.Ordinal);
            Assert.Equal(1, result.ExitCode);
            Assert.False(File.Exists(Path.Combine(_tempDirectory.Path, "missingfile.exe")));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact, WorkItem(761131, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/761131")]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task MissingReferenceErrorVB()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                       { "hellovb.vb",
@"Imports System.Diagnostics
 
Module Module1
Sub Main()
    Dim p As New Process()
    Console.WriteLine(""Hello from VB"")
End Sub
End Module"}};
 
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"/shared:{serverData.PipeName} /nologo /vbruntime* /r:missing.dll hellovb.vb", _tempDirectory, files);
 
            // Should output errors, but not create output file.
            Assert.Contains("error BC2017: could not find library", result.Output, StringComparison.Ordinal);
            Assert.Equal(1, result.ExitCode);
            Assert.False(File.Exists(Path.Combine(_tempDirectory.Path, "hellovb.exe")));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [WorkItem(546067, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546067")]
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task InvalidMetadataFileErrorVB()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                        { "Lib.vb",
@"Class C
End Class" },
                                        { "app.vb",
@"Module M1
Sub Main()
End Sub
End Module"}};
 
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"/shared:{serverData.PipeName} /nologo /vbruntime* /r:Lib.vb app.vb", _tempDirectory, files);
 
            // Should output errors, but not create output file.
            Assert.Contains("error BC31519", result.Output, StringComparison.Ordinal);
            Assert.Equal(1, result.ExitCode);
            Assert.False(File.Exists(Path.Combine(_tempDirectory.Path, "app.exe")));
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact(Skip = "https://github.com/dotnet/roslyn/issues/20345")]
        [WorkItem(723280, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/723280")]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task ReferenceCachingVB()
        {
            TempDirectory rootDirectory = _tempDirectory.CreateDirectory("ReferenceCachingVB");
 
            // Create DLL "lib.dll"
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                           { "src1.vb",
@"Imports System
Public Class Library 
 
    Public Shared Function GetString() As String
        Return ""library1""
    End Function
End Class
"}};
 
            using (var serverData = await ServerUtil.CreateServer(_logger))
            using (var tmpFile = GetResultFile(rootDirectory, "lib.dll"))
            {
                var result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"src1.vb /shared:{serverData.PipeName} /nologo /t:library /out:lib.dll", rootDirectory, files);
                Assert.Equal("", result.Output);
                Assert.Equal(0, result.ExitCode);
 
                using (var hello1_file = GetResultFile(rootDirectory, "hello1.exe"))
                {
                    // Create EXE "hello1.exe"
                    files = new Dictionary<string, string> {
                                           { "hello1.vb",
@"Imports System
Module Module1 
    Public Sub Main()
        Console.WriteLine(""Hello1 from {0}"", Library.GetString())
    End Sub
End Module
"}};
                    result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"hello1.vb /shared:{serverData.PipeName} /nologo /vbruntime* /r:lib.dll /out:hello1.exe", rootDirectory, files);
                    Assert.Equal("", result.Output);
                    Assert.Equal(0, result.ExitCode);
 
                    // Run hello1.exe.
                    RunCompilerOutput(hello1_file, "Hello1 from library1");
 
                    using (var hello2_file = GetResultFile(rootDirectory, "hello2.exe"))
                    {
                        // Create EXE "hello2.exe" referencing same DLL
                        files = new Dictionary<string, string> {
                                                { "hello2.vb",
@"Imports System
Module Module1 
Public Sub Main()
    Console.WriteLine(""Hello2 from {0}"", Library.GetString())
End Sub
End Module
"}};
                        result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"hello2.vb /shared:{serverData.PipeName} /nologo /vbruntime* /r:lib.dll /out:hello2.exe", rootDirectory, files);
                        Assert.Equal("", result.Output);
                        Assert.Equal(0, result.ExitCode);
 
                        // Run hello2.exe.
                        RunCompilerOutput(hello2_file, "Hello2 from library1");
 
                        // Change DLL "lib.dll" to something new.
                        files =
                                               new Dictionary<string, string> {
                                           { "src2.vb",
@"Imports System
Public Class Library 
    Public Shared Function GetString() As String
        Return ""library2""
    End Function
    Public Shared Function GetString2() As String
        Return ""library3""
    End Function
End Class
"}};
 
                        result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"src2.vb /shared:{serverData.PipeName} /nologo /t:library /out:lib.dll", rootDirectory, files);
                        Assert.Equal("", result.Output);
                        Assert.Equal(0, result.ExitCode);
 
                        using (var hello3_file = GetResultFile(rootDirectory, "hello3.exe"))
                        {
                            // Create EXE "hello3.exe" referencing new DLL
                            files = new Dictionary<string, string> {
                                           { "hello3.vb",
@"Imports System
Module Module1 
    Public Sub Main()
        Console.WriteLine(""Hello3 from {0}"", Library.GetString2())
    End Sub
End Module
"}};
                            result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"hello3.vb /shared:{serverData.PipeName} /nologo /vbruntime* /r:lib.dll /out:hello3.exe", rootDirectory, files);
                            Assert.Equal("", result.Output);
                            Assert.Equal(0, result.ExitCode);
 
                            // Run hello3.exe. Should work.
                            RunCompilerOutput(hello3_file, "Hello3 from library3");
 
                            // Run hello2.exe one more time. Should have different output than before from updated library.
                            RunCompilerOutput(hello2_file, "Hello2 from library2");
                        }
                    }
                }
 
                var listener = await serverData.Complete();
                Assert.Equal(5, listener.CompletionDataList.Count);
                Assert.All(listener.CompletionDataList, completionData => Assert.Equal(CompletionReason.RequestCompleted, completionData.Reason));
            }
 
            GC.KeepAlive(rootDirectory);
        }
 
        [ConditionalFact(typeof(WindowsOnly), Reason = "https://github.com/dotnet/roslyn/issues/19763")]
        [WorkItem(723280, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/723280")]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task ReferenceCachingCS()
        {
            TempDirectory rootDirectory = _tempDirectory.CreateDirectory("ReferenceCachingCS");
 
            using (var serverData = await ServerUtil.CreateServer(_logger))
            using (var tmpFile = GetResultFile(rootDirectory, "lib.dll"))
            {
                // Create DLL "lib.dll"
                Dictionary<string, string> files =
                                       new Dictionary<string, string> {
                                           { "src1.cs",
@"using System;
public class Library 
{
    public static string GetString()
    { return ""library1""; }
}"}};
 
                var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"src1.cs /shared:{serverData.PipeName} /nologo /t:library /out:lib.dll", rootDirectory, files);
                Assert.Equal("", result.Output);
                Assert.Equal(0, result.ExitCode);
 
                using (var hello1_file = GetResultFile(rootDirectory, "hello1.exe"))
                {
                    // Create EXE "hello1.exe"
                    files = new Dictionary<string, string> {
                                           { "hello1.cs",
@"using System;
class Hello 
{
    public static void Main()
    { Console.WriteLine(""Hello1 from {0}"", Library.GetString()); }
}"}};
                    result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"hello1.cs /shared:{serverData.PipeName} /nologo /r:lib.dll /out:hello1.exe", rootDirectory, files);
                    Assert.Equal("", result.Output);
                    Assert.Equal(0, result.ExitCode);
 
                    // Run hello1.exe.
                    RunCompilerOutput(hello1_file, "Hello1 from library1");
 
                    using (var hello2_file = GetResultFile(rootDirectory, "hello2.exe"))
                    {
                        var hello2exe = Temp.AddFile(hello2_file);
 
                        // Create EXE "hello2.exe" referencing same DLL
                        files = new Dictionary<string, string> {
                                               { "hello2.cs",
@"using System;
class Hello 
{
    public static void Main()
    { Console.WriteLine(""Hello2 from {0}"", Library.GetString()); }
}"}};
                        result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"hello2.cs /shared:{serverData.PipeName} /nologo /r:lib.dll /out:hello2.exe", rootDirectory, files);
                        Assert.Equal("", result.Output);
                        Assert.Equal(0, result.ExitCode);
 
                        // Run hello2.exe.
                        RunCompilerOutput(hello2exe, "Hello2 from library1");
 
                        // Change DLL "lib.dll" to something new.
                        files =
                                               new Dictionary<string, string> {
                                           { "src2.cs",
@"using System;
public class Library 
{
    public static string GetString()
    { return ""library2""; }
 
    public static string GetString2()
    { return ""library3""; }
}"}};
 
                        result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"src2.cs /shared:{serverData.PipeName} /nologo /t:library /out:lib.dll", rootDirectory, files);
                        Assert.Equal("", result.Output);
                        Assert.Equal(0, result.ExitCode);
 
                        using (var hello3_file = GetResultFile(rootDirectory, "hello3.exe"))
                        {
                            // Create EXE "hello3.exe" referencing new DLL
                            files = new Dictionary<string, string> {
                                           { "hello3.cs",
@"using System;
class Hello 
{
    public static void Main()
    { Console.WriteLine(""Hello3 from {0}"", Library.GetString2()); }
}"}};
                            result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"hello3.cs /shared:{serverData.PipeName} /nologo /r:lib.dll /out:hello3.exe", rootDirectory, files);
                            // Instrumenting to assist investigation of flakiness. Tracked by https://github.com/dotnet/roslyn/issues/19763
                            RoslynDebug.AssertOrFailFast("" == result.Output);
                            RoslynDebug.AssertOrFailFast(0 == result.ExitCode);
 
                            // Run hello3.exe. Should work.
                            RunCompilerOutput(hello3_file, "Hello3 from library3");
 
                            // Run hello2.exe one more time. Should have different output than before from updated library.
                            RunCompilerOutput(hello2_file, "Hello2 from library2");
                        }
                    }
                }
 
                var listener = await serverData.Complete();
                Assert.Equal(5, listener.CompletionDataList.Count);
                Assert.All(listener.CompletionDataList, completionData => Assert.Equal(CompletionReason.RequestCompleted, completionData.Reason));
            }
 
            GC.KeepAlive(rootDirectory);
        }
 
        private Task<DisposableFile> RunCompilationAsync(RequestLanguage language, string pipeName, int i, TempDirectory compilationDir)
        {
            string sourceFile;
            string exeFileName;
            string prefix;
            string sourceText;
            string additionalArgument;
 
            if (language == RequestLanguage.CSharpCompile)
            {
                exeFileName = $"hellocs{i}.exe";
                prefix = "CS";
                sourceFile = $"hello{i}.cs";
                sourceText =
$@"using System;
class Hello 
{{
    public static void Main()
    {{ Console.WriteLine(""{prefix} Hello number {i}""); }}
}}";
                additionalArgument = "";
            }
            else
            {
                exeFileName = $"hellovb{i}.exe";
                prefix = "VB";
                sourceFile = $"hello{i}.vb";
                sourceText =
$@"Imports System
Module Hello 
    Sub Main()
       Console.WriteLine(""{prefix} Hello number {i}"") 
    End Sub
End Module";
                additionalArgument = " /vbruntime*";
            }
 
            var arguments = $"/shared:{pipeName} /nologo {sourceFile} /out:{exeFileName}{additionalArgument}";
            var filesInDirectory = new Dictionary<string, string>()
            {
                { sourceFile, sourceText }
            };
 
            return Task.Run(() =>
            {
                var result = RunCommandLineCompiler(language, string.Join(" ", arguments), compilationDir, filesInDirectory: filesInDirectory);
 
                Assert.Equal(0, result.ExitCode);
 
                // Run the EXE and verify it prints the desired output.
                var exeFile = GetResultFile(compilationDir, exeFileName);
                RunCompilerOutput(exeFile, $"{prefix} Hello number {i}");
                return exeFile;
            });
        }
 
        [WorkItem(997372, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/997372")]
        [WorkItem(761326, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/761326")]
        [ConditionalFact(typeof(WindowsOnly))]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task MultipleSimultaneousCompiles()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            // Run this many compiles simultaneously in different directories.
            const int numberOfCompiles = 20;
            var tasks = new Task<DisposableFile>[numberOfCompiles];
 
            for (int i = 0; i < numberOfCompiles; ++i)
            {
                var language = i % 2 == 0 ? RequestLanguage.CSharpCompile : RequestLanguage.VisualBasicCompile;
                var compilationDir = Temp.CreateDirectory();
                tasks[i] = RunCompilationAsync(language, serverData.PipeName, i, compilationDir);
            }
 
            await Task.WhenAll(tasks);
 
            var listener = await serverData.Complete();
            Assert.Equal(numberOfCompiles, listener.CompletionDataList.Count);
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task UseLibVariableCS()
        {
            var libDirectory = _tempDirectory.CreateDirectory("LibraryDir");
 
            // Create DLL "lib.dll"
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                           { "src1.cs",
@"
public class Library 
{
    public static string GetString()
    { return ""library1""; }
}"}};
 
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable,
                                                $"src1.cs /shared:{serverData.PipeName} /nologo /t:library /out:" + Path.Combine(libDirectory.Path, "lib.dll"),
                                                _tempDirectory, files);
 
            Assert.Equal("", result.Output);
            Assert.Equal(0, result.ExitCode);
 
            Temp.AddFile(GetResultFile(libDirectory, "lib.dll"));
 
            // Create EXE "hello1.exe"
            files = new Dictionary<string, string> {
                                       { "hello1.cs",
@"using System;
class Hello 
{
public static void Main()
{ Console.WriteLine(""Hello1 from {0}"", Library.GetString()); }
}"}};
            result = RunCommandLineCompiler(CSharpCompilerClientExecutable, $"hello1.cs /shared:{serverData.PipeName} /nologo /r:lib.dll /out:hello1.exe", _tempDirectory, files,
                                            additionalEnvironmentVars: new Dictionary<string, string>() { { "LIB", libDirectory.Path } });
 
            Assert.Equal("", result.Output);
            Assert.Equal(0, result.ExitCode);
 
            var resultFile = Temp.AddFile(GetResultFile(_tempDirectory, "hello1.exe"));
 
            var listener = await serverData.Complete();
            Assert.Equal(2, listener.CompletionDataList.Count);
        }
 
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task UseLibVariableVB()
        {
            var libDirectory = _tempDirectory.CreateDirectory("LibraryDir");
 
            // Create DLL "lib.dll"
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                           { "src1.vb",
@"Imports System
Public Class Library 
 
    Public Shared Function GetString() As String
        Return ""library1""
    End Function
End Class
"}};
 
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var result = RunCommandLineCompiler(BasicCompilerClientExecutable,
                                                $"src1.vb /shared:{serverData.PipeName} /vbruntime* /nologo /t:library /out:" + Path.Combine(libDirectory.Path, "lib.dll"),
                                                _tempDirectory, files);
 
            Assert.Equal("", result.Output);
            Assert.Equal(0, result.ExitCode);
 
            Temp.AddFile(GetResultFile(libDirectory, "lib.dll"));
 
            // Create EXE "hello1.exe"
            files = new Dictionary<string, string> {
                                       { "hello1.vb",
@"Imports System
Module Module1 
Public Sub Main()
    Console.WriteLine(""Hello1 from {0}"", Library.GetString())
End Sub
End Module
"}};
            result = RunCommandLineCompiler(BasicCompilerClientExecutable, $"hello1.vb /shared:{serverData.PipeName} /nologo /vbruntime* /r:lib.dll /out:hello1.exe", _tempDirectory, files,
                                            additionalEnvironmentVars: new Dictionary<string, string>() { { "LIB", libDirectory.Path } });
 
            Assert.Equal("", result.Output);
            Assert.Equal(0, result.ExitCode);
 
            var resultFile = Temp.AddFile(GetResultFile(_tempDirectory, "hello1.exe"));
            var listener = await serverData.Complete();
            Assert.Equal(2, listener.CompletionDataList.Count);
        }
 
        [WorkItem(545446, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545446")]
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task Utf8Output_WithRedirecting_Off_Shared()
        {
            var srcFile = _tempDirectory.CreateFile("test.cs").WriteAllText("♕").Path;
 
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(
                CSharpCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /nologo /t:library {srcFile}",
                _tempDirectory,
                redirectEncoding: Encoding.ASCII);
 
            Assert.Equal("test.cs(1,1): error CS1056: Unexpected character '?'".Trim(),
                result.Output.Trim());
            Assert.Equal(1, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [WorkItem(545446, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545446")]
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task Utf8Output_WithRedirecting_Off_Share()
        {
            var srcFile = _tempDirectory.CreateFile("test.vb").WriteAllText(@"♕").Path;
            var tempOut = _tempDirectory.CreateFile("output.txt");
 
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(
                BasicCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /nologo /vbruntime* /t:library {srcFile}",
                _tempDirectory,
                redirectEncoding: Encoding.ASCII);
 
            Assert.Equal(@"SRC.VB(1) : error BC30037: Character is not valid.
 
?
~
".Trim(),
                        result.Output.Trim().Replace(srcFile, "SRC.VB"));
            Assert.Equal(1, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [WorkItem(545446, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545446")]
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task Utf8Output_WithRedirecting_On_Shared_CS()
        {
            var srcFile = _tempDirectory.CreateFile("test.cs").WriteAllText("♕").Path;
 
            using var serverData = await ServerUtil.CreateServer(_logger);
            var result = RunCommandLineCompiler(
                CSharpCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /utf8output /nologo /t:library {srcFile}",
                _tempDirectory,
                redirectEncoding: UTF8Encoding);
 
            Assert.Equal("test.cs(1,1): error CS1056: Unexpected character '♕'".Trim(),
                result.Output.Trim());
            Assert.Equal(1, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [WorkItem(545446, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545446")]
        [Fact]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task Utf8Output_WithRedirecting_On_Shared_VB()
        {
            var srcFile = _tempDirectory.CreateFile("test.vb").WriteAllText(@"♕").Path;
 
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var result = RunCommandLineCompiler(
                BasicCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /utf8output /nologo /vbruntime* /t:library {srcFile}",
                _tempDirectory,
                redirectEncoding: UTF8Encoding);
 
            Assert.Equal(@"SRC.VB(1) : error BC30037: Character is not valid.
 
♕
~
".Trim(),
                        result.Output.Trim().Replace(srcFile, "SRC.VB"));
            Assert.Equal(1, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [WorkItem(871477, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/871477")]
        [ConditionalFact(typeof(DesktopOnly))]
        [Trait(Traits.Environment, Traits.Environments.VSProductInstall)]
        public async Task AssemblyIdentityComparer1()
        {
            _tempDirectory.CreateFile("mscorlib20.dll").WriteAllBytes(Net20.Resources.mscorlib);
            _tempDirectory.CreateFile("mscorlib40.dll").WriteAllBytes(Net40.Resources.mscorlib);
 
            // Create DLL "lib.dll"
            Dictionary<string, string> files =
                                   new Dictionary<string, string> {
                                           { "ref_mscorlib2.cs",
@"public class C
{
    public System.Exception GetException()
    {
        return new System.Exception();
    }
}
"}};
 
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable,
                                                $"ref_mscorlib2.cs /shared:{serverData.PipeName} /nologo /nostdlib /noconfig /t:library /r:mscorlib20.dll",
                                                _tempDirectory, files);
 
            Assert.Equal("", result.Output);
            Assert.Equal(0, result.ExitCode);
 
            Temp.AddFile(GetResultFile(_tempDirectory, "ref_mscorlib2.dll"));
 
            // Create EXE "main.exe"
            files = new Dictionary<string, string> {
                                       { "main.cs",
@"using System;
 
class Program
{
static void Main(string[] args)
{
    var e = new C().GetException();
    Console.WriteLine(e);
}
}
"}};
            result = RunCommandLineCompiler(CSharpCompilerClientExecutable,
                                            $"main.cs /shared:{serverData.PipeName} /nologo /nostdlib /noconfig /r:mscorlib40.dll /r:ref_mscorlib2.dll",
                                            _tempDirectory, files);
 
            Assert.Equal("", result.Output);
            Assert.Equal(0, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(2, listener.CompletionDataList.Count);
        }
 
        [WorkItem(979588, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/979588")]
        [Fact]
        public async Task Utf8OutputInRspFileCsc()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var srcFile = _tempDirectory.CreateFile("test.cs").WriteAllText("♕").Path;
            var rspFile = _tempDirectory.CreateFile("temp.rsp").WriteAllText(
                string.Format("/utf8output /nologo /t:library {0}", srcFile));
 
            var result = RunCommandLineCompiler(
                CSharpCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /noconfig @{rspFile}",
                _tempDirectory,
                redirectEncoding: UTF8Encoding);
 
            Assert.Equal("test.cs(1,1): error CS1056: Unexpected character '♕'",
                result.Output.Trim());
            Assert.Equal(1, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [WorkItem(979588, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/979588")]
        [Fact]
        public async Task Utf8OutputInRspFileVbc()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var srcFile = _tempDirectory.CreateFile("test.cs").WriteAllText("♕").Path;
            var rspFile = _tempDirectory.CreateFile("temp.rsp").WriteAllText(
                string.Format("/utf8output /nologo /vbruntime* /t:library {0}", srcFile));
 
            var result = RunCommandLineCompiler(
                BasicCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /noconfig @{rspFile}",
                _tempDirectory,
                redirectEncoding: UTF8Encoding);
 
            Assert.Equal(@"src.vb(1) : error BC30037: Character is not valid.
 
♕
~", result.Output.Trim().Replace(srcFile, "src.vb"));
            Assert.Equal(1, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [WorkItem(25777, "https://github.com/dotnet/roslyn/issues/25777")]
        [ConditionalFact(typeof(DesktopOnly), typeof(IsEnglishLocal))]
        public void BadKeepAlive1()
        {
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, "/shared /keepalive", _tempDirectory, shouldRunOnServer: false);
 
            Assert.Equal(1, result.ExitCode);
            Assert.Equal("Missing argument for '/keepalive' option.", result.Output.Trim());
        }
 
        [WorkItem(25777, "https://github.com/dotnet/roslyn/issues/25777")]
        [ConditionalFact(typeof(DesktopOnly), typeof(IsEnglishLocal))]
        public void BadKeepAlive2()
        {
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, "/shared /keepalive:goo", _tempDirectory, shouldRunOnServer: false);
 
            Assert.Equal(1, result.ExitCode);
            Assert.Equal("Argument to '/keepalive' option is not a 32-bit integer.", result.Output.Trim());
        }
 
        [WorkItem(25777, "https://github.com/dotnet/roslyn/issues/25777")]
        [ConditionalFact(typeof(DesktopOnly), typeof(IsEnglishLocal))]
        public void BadKeepAlive3()
        {
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, "/shared /keepalive:-100", _tempDirectory, shouldRunOnServer: false);
 
            Assert.Equal(1, result.ExitCode);
            Assert.Equal("Arguments to '/keepalive' option below -1 are invalid.", result.Output.Trim());
        }
 
        [WorkItem(25777, "https://github.com/dotnet/roslyn/issues/25777")]
        [ConditionalFact(typeof(DesktopOnly), typeof(IsEnglishLocal))]
        public void BadKeepAlive4()
        {
            var result = RunCommandLineCompiler(CSharpCompilerClientExecutable, "/shared /keepalive:9999999999", _tempDirectory, shouldRunOnServer: false);
 
            Assert.Equal(1, result.ExitCode);
            Assert.Equal("Argument to '/keepalive' option is not a 32-bit integer.", result.Output.Trim());
        }
 
        [ConditionalFact(typeof(DesktopOnly))]
        [WorkItem(1024619, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1024619")]
        public async Task Bug1024619_01()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var srcFile = _tempDirectory.CreateFile("test.cs").WriteAllText("").Path;
 
            _tempDirectory.CreateDirectory("Temp");
            var tmp = Path.Combine(_tempDirectory.Path, "Temp");
 
            var result = RunCommandLineCompiler(
                CSharpCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /nologo /t:library {srcFile}",
                _tempDirectory,
                additionalEnvironmentVars: new Dictionary<string, string> { { "TMP", tmp } });
 
            Assert.Equal(0, result.ExitCode);
 
            Directory.Delete(tmp);
 
            result = RunCommandLineCompiler(
                CSharpCompilerClientExecutable,
                $"/nologo /t:library {srcFile}",
                _tempDirectory,
                shouldRunOnServer: false);
 
            Assert.Equal("", result.Output.Trim());
            Assert.Equal(0, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        [Fact]
        [WorkItem(1024619, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/1024619")]
        public async Task Bug1024619_02()
        {
            using var serverData = await ServerUtil.CreateServer(_logger);
 
            var srcFile = _tempDirectory.CreateFile("test.vb").WriteAllText("").Path;
 
            _tempDirectory.CreateDirectory("Temp");
            var tmp = Path.Combine(_tempDirectory.Path, "Temp");
 
            var result = RunCommandLineCompiler(
                BasicCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /vbruntime* /nologo /t:library {srcFile}",
                _tempDirectory,
                additionalEnvironmentVars: new Dictionary<string, string> { { "TMP", tmp } });
 
            Assert.Equal("", result.Output.Trim());
            Assert.Equal(0, result.ExitCode);
 
            Directory.Delete(tmp);
 
            result = RunCommandLineCompiler(
                CSharpCompilerClientExecutable,
                $"/shared:{serverData.PipeName} /nologo /t:library {srcFile}",
                _tempDirectory);
 
            Assert.Equal("", result.Output.Trim());
            Assert.Equal(0, result.ExitCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(2, listener.CompletionDataList.Count);
        }
 
        [WorkItem(406649, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=406649")]
        [ConditionalFact(typeof(DesktopOnly))]
        public void MissingCompilerAssembly_CompilerServer()
        {
            var basePath = Path.GetDirectoryName(typeof(CompilerServerUnitTests).Assembly.Location);
            var compilerServerExecutable = Path.Combine(basePath, "VBCSCompiler.exe");
            var dir = Temp.CreateDirectory();
            var workingDirectory = dir.Path;
            var serverExe = dir.CopyFile(compilerServerExecutable).Path;
            dir.CopyFile(typeof(System.Collections.Immutable.ImmutableArray).Assembly.Location);
 
            // Missing Microsoft.CodeAnalysis.dll launching server.
            var result = ProcessUtilities.Run(serverExe, arguments: $"-pipename:{GetUniqueName()}", workingDirectory: workingDirectory);
            Assert.Equal(1, result.ExitCode);
            // Exception is logged rather than written to output/error streams.
            Assert.Equal("", result.Output.Trim());
        }
 
        [WorkItem(406649, "https://devdiv.visualstudio.com/DevDiv/_workitems?id=406649")]
        [WorkItem(19213, "https://github.com/dotnet/roslyn/issues/19213")]
        [Fact(Skip = "19213")]
        public async Task MissingCompilerAssembly_CompilerServerHost()
        {
            var host = new TestableCompilerServerHost((request, cancellationToken) =>
            {
                throw new FileNotFoundException();
            });
 
            using var serverData = await ServerUtil.CreateServer(_logger, compilerServerHost: host);
            var request = new BuildRequest(RequestLanguage.CSharpCompile, string.Empty, new BuildRequest.Argument[0]);
            var compileTask = serverData.SendAsync(request);
            var response = await compileTask;
            Assert.Equal(BuildResponse.ResponseType.Completed, response.Type);
            Assert.Equal(0, ((CompletedBuildResponse)response).ReturnCode);
 
            var listener = await serverData.Complete();
            Assert.Equal(CompletionData.RequestCompleted, listener.CompletionDataList.Single());
        }
 
        /// <summary>
        /// Runs CompileAndGetBytes twice and compares the output. 
        /// </summary>
        /// <param name="source"> The source of the program that will be compiled </param>
        private async Task RunDeterministicTest(string source)
        {
            var flags = "/deterministic+ /nologo /t:library /pdb:none";
            var (first, finalFlags1) = await CompileAndGetBytes(source, flags);
            var (second, finalFlags2) = await CompileAndGetBytes(source, flags);
            Assert.Equal(first.Length, second.Length);
            for (int i = 0; i < first.Length; i++)
            {
                if (first[i] != second[i])
                {
                    AssertEx.Fail($"Bytes were different at position {i} ({first[i]} vs {second[i]}).  Flags used were (\"{finalFlags1}\" vs \"{finalFlags2}\")");
                }
            }
        }
 
        [Fact]
        public async Task DeterminismHelloWorld()
        {
            var source = @"using System;
class Hello
{
    static void Main()
    {
        Console.WriteLine(""Hello, world.""); 
    }
}";
 
            await RunDeterministicTest(source);
        }
 
        [Fact]
        public async Task DeterminismCallerInfo()
        {
            var source = @"using System;
class CallerInfo {
    public static void DoProcessing()
    {
        TraceMessage(""Something happened."");
    }
    public static void TraceMessage(string message,
            [System.Runtime.CompilerServices.CallerMemberName] string memberName = """",
            [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = """",
            [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
    {
        System.Diagnostics.Trace.WriteLine(""message: "" + message);
        System.Diagnostics.Trace.WriteLine(""member name: "" + memberName);
        System.Diagnostics.Trace.WriteLine(""source file path: "" + sourceFilePath);
        System.Diagnostics.Trace.WriteLine(""source line number: "" + sourceLineNumber);
    }
    static void Main() {
        DoProcessing();
    }
}";
            await RunDeterministicTest(source);
        }
 
        [Fact]
        public async Task DeterminismAnonType()
        {
            var source = @"using System;
class AnonType {
    public static void Main() {
        var person = new { firstName = ""john"", lastName = ""Smith"" };
        var date = new { year = 2015, month = ""jan"", day = 5 };
        var color = new { red = 255, green = 125, blue = 0 };
        
        Console.WriteLine(person);
        Console.WriteLine(date);
        Console.WriteLine(color);
    }
}";
            await RunDeterministicTest(source);
        }
 
        [Fact]
        public async Task DeterminismLineDirective()
        {
            var source = @"using System;
class CallerInfo {
    public static void TraceMessage(string message,
            [System.Runtime.CompilerServices.CallerMemberName] string memberName = """",
            [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = """",
            [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
    {
        System.Diagnostics.Trace.WriteLine(""message: "" + message);
        System.Diagnostics.Trace.WriteLine(""member name: "" + memberName);
        System.Diagnostics.Trace.WriteLine(""source file path: "" + sourceFilePath);
        System.Diagnostics.Trace.WriteLine(""source line number: "" + sourceLineNumber);
    }
    static void Main() {
        TraceMessage(""from main"");
#line 10 ""coolFile.cs""
        TraceMessage(""from the cool file"");
#line default
        TraceMessage(""back in main"");
    }
}";
            await RunDeterministicTest(source);
        }
    }
}