|
// 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.Globalization;
using System.IO;
using System.Reflection;
using Xunit;
using Roslyn.Test.Utilities;
namespace Microsoft.CodeAnalysis.UnitTests.MetadataReferences
{
public class FusionAssemblyIdentityTests
{
/// <summary>
/// Converts <see cref="FusionAssemblyIdentity.IAssemblyName"/> to <see cref="AssemblyName"/> with possibly
/// missing name components.
/// </summary>
/// <returns>
/// An <see cref="AssemblyName"/> whose fields are be null if not present in <paramref name="nameObject"/>.
/// </returns>
internal static AssemblyName ToAssemblyName(FusionAssemblyIdentity.IAssemblyName nameObject)
{
var result = new AssemblyName();
result.Name = FusionAssemblyIdentity.GetName(nameObject);
result.Version = FusionAssemblyIdentity.GetVersion(nameObject);
var cultureName = FusionAssemblyIdentity.GetCulture(nameObject);
result.CultureInfo = (cultureName != null) ? new CultureInfo(cultureName) : null;
byte[] publicKey = FusionAssemblyIdentity.GetPublicKey(nameObject);
if (publicKey != null && publicKey.Length != 0)
{
result.SetPublicKey(publicKey);
}
else
{
result.SetPublicKeyToken(FusionAssemblyIdentity.GetPublicKeyToken(nameObject));
}
result.Flags = FusionAssemblyIdentity.GetFlags(nameObject);
result.ContentType = FusionAssemblyIdentity.GetContentType(nameObject);
return result;
}
private void RoundTrip(AssemblyName name, bool testFullName = true)
{
AssemblyName rtName;
FusionAssemblyIdentity.IAssemblyName obj;
if (testFullName)
{
string fullName = name.FullName;
obj = FusionAssemblyIdentity.ToAssemblyNameObject(fullName);
rtName = ToAssemblyName(obj);
Assert.Equal(name.Name, rtName.Name);
Assert.Equal(name.Version, rtName.Version);
Assert.Equal(name.CultureInfo, rtName.CultureInfo);
Assert.Equal(name.GetPublicKeyToken(), rtName.GetPublicKeyToken());
Assert.Equal(name.Flags, rtName.Flags);
Assert.Equal(name.ContentType, rtName.ContentType);
string displayName = FusionAssemblyIdentity.GetDisplayName(obj, FusionAssemblyIdentity.ASM_DISPLAYF.FULL);
Assert.Equal(fullName, displayName);
}
obj = FusionAssemblyIdentity.ToAssemblyNameObject(name);
rtName = ToAssemblyName(obj);
Assert.Equal(name.Name, rtName.Name);
Assert.Equal(name.Version, rtName.Version);
Assert.Equal(name.CultureInfo, rtName.CultureInfo);
Assert.Equal(name.GetPublicKeyToken(), rtName.GetPublicKeyToken());
Assert.Equal(name.Flags, rtName.Flags);
Assert.Equal(name.ContentType, rtName.ContentType);
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void FusionAssemblyNameRoundTrip()
{
RoundTrip(new AssemblyName("goo"));
RoundTrip(new AssemblyName { Name = "~!@#$%^&*()_+={}:\"<>?[];',./" });
RoundTrip(new AssemblyName("\\,"));
RoundTrip(new AssemblyName("\\\""));
RoundTrip(new AssemblyIdentity("goo").ToAssemblyName());
// 0xffff version is not included in AssemblyName.FullName for some reason:
var name = new AssemblyIdentity("goo", version: new Version(0xffff, 0xffff, 0xffff, 0xffff)).ToAssemblyName();
RoundTrip(name, testFullName: false);
var obj = FusionAssemblyIdentity.ToAssemblyNameObject(name);
var display = FusionAssemblyIdentity.GetDisplayName(obj, FusionAssemblyIdentity.ASM_DISPLAYF.FULL);
Assert.Equal("goo, Version=65535.65535.65535.65535, Culture=neutral, PublicKeyToken=null", display);
RoundTrip(new AssemblyIdentity("goo", version: new Version(1, 2, 3, 4)).ToAssemblyName());
RoundTrip(new AssemblyName("goo") { Version = new Version(1, 2, 3, 4) });
RoundTrip(new AssemblyIdentity("goo", cultureName: CultureInfo.CurrentCulture.Name).ToAssemblyName());
RoundTrip(new AssemblyIdentity("goo", cultureName: "").ToAssemblyName());
RoundTrip(new AssemblyName("goo") { CultureInfo = CultureInfo.InvariantCulture });
RoundTrip(new AssemblyIdentity("goo", version: new Version(1, 2, 3, 4), cultureName: "en-US").ToAssemblyName());
RoundTrip(new AssemblyIdentity("goo", publicKeyOrToken: new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }.AsImmutableOrNull()).ToAssemblyName());
RoundTrip(new AssemblyIdentity("goo", version: new Version(1, 2, 3, 4), cultureName: CultureInfo.CurrentCulture.Name, publicKeyOrToken: new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }.AsImmutableOrNull()).ToAssemblyName());
RoundTrip(new AssemblyIdentity("goo", isRetargetable: true).ToAssemblyName());
RoundTrip(new AssemblyIdentity("goo", contentType: AssemblyContentType.WindowsRuntime).ToAssemblyName());
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void FusionGetBestMatch()
{
var goo = FusionAssemblyIdentity.ToAssemblyNameObject("goo");
var goo1 = FusionAssemblyIdentity.ToAssemblyNameObject("goo, Version=1.0.0.0, Culture=neutral");
var goo2 = FusionAssemblyIdentity.ToAssemblyNameObject("goo, Version=2.0.0.0, Culture=neutral");
var goo3 = FusionAssemblyIdentity.ToAssemblyNameObject("goo, Version=3.0.0.0, Culture=neutral");
var goo3_enUS = FusionAssemblyIdentity.ToAssemblyNameObject("goo, Version=3.0.0.0, Culture=en-US");
var goo3_deDE = FusionAssemblyIdentity.ToAssemblyNameObject("goo, Version=3.0.0.0, Culture=de-DE");
var m = FusionAssemblyIdentity.GetBestMatch(new[] { goo2, goo1, goo3 }, null);
Assert.Equal(goo3, m);
m = FusionAssemblyIdentity.GetBestMatch(new[] { goo3, goo2, goo1 }, null);
Assert.Equal(goo3, m);
// only simple name is used
m = FusionAssemblyIdentity.GetBestMatch(new[] { goo2, goo3 }, null);
Assert.Equal(goo3, m);
// the first match if preferred cultures not specified
m = FusionAssemblyIdentity.GetBestMatch(new[] { goo1, goo3_deDE, goo3_enUS, goo2 }, null);
Assert.Equal(goo3_deDE, m);
// the first match if preferred cultures not specified
m = FusionAssemblyIdentity.GetBestMatch(new[] { goo1, goo3_deDE, goo3_enUS, goo2 }, null);
Assert.Equal(goo3_deDE, m);
m = FusionAssemblyIdentity.GetBestMatch(new[] { goo1, goo3, goo3_deDE, goo3_enUS, goo2 }, "en-US");
Assert.Equal(goo3_enUS, m);
m = FusionAssemblyIdentity.GetBestMatch(new[] { goo1, goo3_deDE, goo3, goo3_enUS, goo2 }, "cz-CZ");
Assert.Equal(goo3, m);
m = FusionAssemblyIdentity.GetBestMatch(new[] { goo3_deDE, goo2 }, "en-US");
Assert.Equal(goo3_deDE, m);
// neutral culture wins over specific non-matching one:
m = FusionAssemblyIdentity.GetBestMatch(new[] { goo3_deDE, goo3, goo2 }, "en-US");
Assert.Equal(goo3, m);
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void FusionToAssemblyName()
{
var nameObject = FusionAssemblyIdentity.ToAssemblyNameObject("mscorlib");
var name = ToAssemblyName(nameObject);
Assert.Equal("mscorlib", name.Name);
Assert.Null(name.Version);
Assert.Null(name.CultureInfo);
Assert.Null(name.GetPublicKey());
Assert.Null(name.GetPublicKeyToken());
Assert.Equal(AssemblyContentType.Default, name.ContentType);
nameObject = FusionAssemblyIdentity.ToAssemblyNameObject("mscorlib, Version=2.0.0.0");
name = ToAssemblyName(nameObject);
Assert.Equal("mscorlib", name.Name);
Assert.Equal(new Version(2, 0, 0, 0), name.Version);
Assert.Null(name.CultureInfo);
Assert.Null(name.GetPublicKey());
Assert.Null(name.GetPublicKeyToken());
Assert.Equal(AssemblyContentType.Default, name.ContentType);
nameObject = FusionAssemblyIdentity.ToAssemblyNameObject("mscorlib, Version=2.0.0.0, Culture=neutral");
name = ToAssemblyName(nameObject);
Assert.Equal("mscorlib", name.Name);
Assert.Equal(new Version(2, 0, 0, 0), name.Version);
Assert.Equal(name.CultureInfo, CultureInfo.InvariantCulture);
Assert.Null(name.GetPublicKey());
Assert.Null(name.GetPublicKeyToken());
Assert.Equal(AssemblyContentType.Default, name.ContentType);
nameObject = FusionAssemblyIdentity.ToAssemblyNameObject("mscorlib, Version=2.0.0.0, Culture=en-US");
name = ToAssemblyName(nameObject);
Assert.Equal("mscorlib", name.Name);
Assert.Equal(new Version(2, 0, 0, 0), name.Version);
Assert.NotNull(name.CultureInfo);
Assert.Equal("en-US", name.CultureInfo.Name);
Assert.Null(name.GetPublicKey());
Assert.Null(name.GetPublicKeyToken());
Assert.Equal(AssemblyContentType.Default, name.ContentType);
nameObject = FusionAssemblyIdentity.ToAssemblyNameObject("Windows, Version=255.255.255.255, ContentType=WindowsRuntime");
name = ToAssemblyName(nameObject);
Assert.Equal("Windows", name.Name);
Assert.Equal(new Version(255, 255, 255, 255), name.Version);
Assert.Null(name.CultureInfo);
Assert.Null(name.GetPublicKey());
Assert.Null(name.GetPublicKeyToken());
Assert.Equal(AssemblyContentType.WindowsRuntime, name.ContentType);
nameObject = FusionAssemblyIdentity.ToAssemblyNameObject("mscorlib, Version=2.0.0.0, Culture=nonsense");
Assert.NotNull(nameObject);
Assert.Throws<CultureNotFoundException>(() => ToAssemblyName(nameObject));
nameObject = FusionAssemblyIdentity.ToAssemblyNameObject("mscorlib, Version=2.0.0.0, Culture=null");
Assert.NotNull(nameObject);
Assert.Throws<CultureNotFoundException>(() => ToAssemblyName(nameObject));
Assert.Throws<CultureNotFoundException>(() => new AssemblyName("mscorlib, Version=2.0.0.0, Culture=nonsense"));
Assert.Throws<CultureNotFoundException>(() => new AssemblyName("mscorlib, Version=2.0.0.0, Culture=null"));
Assert.Throws<ArgumentException>(() => FusionAssemblyIdentity.ToAssemblyNameObject(new AssemblyName { Name = "x\0x" }));
// invalid characters are ok in the name, the FullName can't be built though:
foreach (char c in AssemblyIdentityTests.ClrInvalidCharacters)
{
nameObject = FusionAssemblyIdentity.ToAssemblyNameObject(new AssemblyName { Name = c.ToString() });
name = ToAssemblyName(nameObject);
Assert.Equal(c.ToString(), name.Name);
Assert.Throws<FileLoadException>(() => name.FullName);
}
}
}
}
|