File: InteractiveSessionReferencesTests.cs
Web Access
Project: src\src\Scripting\CSharpTest\Microsoft.CodeAnalysis.CSharp.Scripting.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Scripting.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.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Scripting.Hosting;
using Microsoft.CodeAnalysis.Scripting.TestUtilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
using static Microsoft.CodeAnalysis.Scripting.TestCompilationFactory;
 
namespace Microsoft.CodeAnalysis.CSharp.Scripting.Test
{
    public class InteractiveSessionReferencesTests : CSharpScriptTestBase
    {
        /// <summary>
        /// Test adding a reference to NetStandard 2.0 library.
        /// Validates that we resolve all references correctly in the first and the subsequent submissions.
        /// </summary>
        [Fact, WorkItem("https://github.com/dotnet/try/issues/345")]
        public async Task LibraryReference_NetStandard20()
        {
            var libSource = @"
public class C
{
    public readonly int X = 1;
}
";
            var libImage = CreateCSharpCompilation(libSource, TargetFrameworkUtil.NetStandard20References, "lib").EmitToArray();
 
            var dir = Temp.CreateDirectory();
            var libFile = dir.CreateFile("lib.dll").WriteAllBytes(libImage);
 
            var s0 = CSharpScript.Create($@"
#r ""{libFile.Path}""
int F(C c) => c.X;
", ScriptOptions);
            var s1 = s0.ContinueWith($@"
F(new C())
");
            var diagnostics = s1.Compile();
            Assert.Empty(diagnostics);
 
            var result = await s1.EvaluateAsync();
            Assert.Equal(1, (int)result);
        }
 
        [Theory]
        [InlineData(true)]
        [InlineData(false)]
        public async Task LibraryReference_MissingDependency_MultipleResolveAttempts(bool swapReferences)
        {
            var libASource = @"
public class A
{
    public readonly int X = D.Y;
}
";
            var libBSource = @"
public class B
{
    public readonly int X = D.Y;
}
";
            var libDSource = @"
public class D
{
    public static readonly int Y = 1;
}
";
 
            var dir = Temp.CreateDirectory();
 
            // 1\a.dll
            // 2\{b.dll, d.dll}
            var dir1 = dir.CreateDirectory("1");
            var dir2 = dir.CreateDirectory("2");
 
            var libDImage = CreateCSharpCompilation(libDSource, TargetFrameworkUtil.NetStandard20References, "libD").EmitToArray();
            var libDFile = dir2.CreateFile("libD.dll").WriteAllBytes(libDImage);
            var libDRef = MetadataReference.CreateFromFile(libDFile.Path);
 
            var libAImage = CreateCSharpCompilation(libASource, TargetFrameworkUtil.NetStandard20References.Concat(libDRef), "libA").EmitToArray();
            var libAFile = dir1.CreateFile("libA.dll").WriteAllBytes(libAImage);
 
            var libBImage = CreateCSharpCompilation(libBSource, TargetFrameworkUtil.NetStandard20References.Concat(libDRef), "libB").EmitToArray();
            var libBFile = dir2.CreateFile("libB.dll").WriteAllBytes(libBImage);
 
            var r1 = swapReferences ? libBFile.Path : libAFile.Path;
            var r2 = swapReferences ? libAFile.Path : libBFile.Path;
 
            var s0 = CSharpScript.Create($@"
#r ""{r1}""
#r ""{r2}""
new A().X + new B().X
", ScriptOptions);
            var diagnostics0 = s0.Compile();
            Assert.Empty(diagnostics0);
 
            var result = await s0.EvaluateAsync();
            Assert.Equal(2, (int)result);
        }
 
        [Fact]
        public void LibraryReference_MissingDependency()
        {
            var libASource = @"
public class C
{
    public readonly int X = D.Y;
}
";
            var libBSource = @"
public class D
{
    public static readonly int Y = 1;
    public static readonly int Z = 2;
}
";
 
            var dir = Temp.CreateDirectory();
            var libBImage = CreateCSharpCompilation(libBSource, TargetFrameworkUtil.NetStandard20References, "libB").EmitToArray();
 
            // store the reference under a different file name, so that it is not found by the resolver:
            var libBFile = dir.CreateFile("libB1.dll").WriteAllBytes(libBImage);
            var libBRef = MetadataReference.CreateFromFile(libBFile.Path);
 
            var libAImage = CreateCSharpCompilation(libASource, TargetFrameworkUtil.NetStandard20References.Concat(libBRef), "libA").EmitToArray();
            var libAFile = dir.CreateFile("libA.dll").WriteAllBytes(libAImage);
 
            var s0 = CSharpScript.Create($@"
#r ""{libAFile.Path}""
int F(C c) => c.X;
", ScriptOptions);
            var diagnostics0 = s0.Compile();
            Assert.Empty(diagnostics0);
 
            File.Move(libBFile.Path, Path.Combine(dir.Path, "libB.dll"));
 
            var s1 = s0.ContinueWith($@"
F(new C())
");
            var diagnostics1 = s1.Compile();
            Assert.Empty(diagnostics1);
 
            var m = s1.GetCompilation().Assembly.Modules.Single();
            Assert.False(m.ReferencedAssemblies.Any(a => a.Name == "libB"));
            var missingB = m.ReferencedAssemblySymbols.Single(a => a.Name == "libA").Modules.Single().ReferencedAssemblySymbols.Single(a => a.Name == "libB");
            Assert.IsType<MissingAssemblySymbol>(missingB.GetSymbol());
        }
    }
}