|
// 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.Reflection;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.UnitTests
{
public class AssemblyIdentityDisplayNameTests : AssemblyIdentityTestBase
{
private const AssemblyIdentityParts N = AssemblyIdentityParts.Name;
private const AssemblyIdentityParts NV = N | AssemblyIdentityParts.Version;
private const AssemblyIdentityParts NVK = NV | AssemblyIdentityParts.PublicKey;
private const AssemblyIdentityParts NVT = NV | AssemblyIdentityParts.PublicKeyToken;
private const AssemblyIdentityParts NVC = NV | AssemblyIdentityParts.Culture;
private const AssemblyIdentityParts NVCT = NVC | AssemblyIdentityParts.PublicKeyToken;
private void TestParseVersionInvalid(string value)
{
AssemblyIdentityParts actualParts;
ulong actual;
Assert.False(AssemblyIdentity.TryParseVersion(value, out actual, out actualParts));
// compare with fusion
var fusionName = FusionAssemblyIdentity.ToAssemblyNameObject("Name, Version=" + value);
if (fusionName != null)
{
AssemblyIdentityParts fusionParts = 0;
var fusionVersion = FusionAssemblyIdentity.GetVersion(fusionName, out fusionParts);
// name parsing succeeds but there is no version:
Assert.Equal((AssemblyIdentityParts)0, fusionParts);
}
}
private void TestParseVersion(string value, int major, int minor, int build, int revision, AssemblyIdentityParts expectedParts)
{
AssemblyIdentityParts actualParts;
ulong actual;
Assert.True(AssemblyIdentity.TryParseVersion(value, out actual, out actualParts));
Assert.Equal(expectedParts, actualParts);
Version actualVersion = AssemblyIdentity.ToVersion(actual);
Assert.Equal(new Version(major, minor, build, revision), actualVersion);
// compare with fusion
var fusionName = FusionAssemblyIdentity.ToAssemblyNameObject("Name, Version=" + value);
Assert.NotNull(fusionName);
AssemblyIdentityParts fusionParts = 0;
var fusionVersion = FusionAssemblyIdentity.GetVersion(fusionName, out fusionParts);
Assert.Equal(fusionVersion, actualVersion);
// Test limitation:
// When constructing INameObject with CANOF.PARSE_DISPLAY_NAME option,
// the Version=* is treated as unspecified version. That's also done by TryParseDisplayName,
// but outside of TryParseVersion, which we are testing here.
if (value == "*")
{
Assert.Equal((AssemblyIdentityParts)0, fusionParts);
}
else
{
Assert.Equal(expectedParts, fusionParts);
}
}
private void TestParseVersion(string value)
{
string displayName = "Goo, Version=" + value;
var fusion = FusionAssemblyIdentity.ToAssemblyIdentity(FusionAssemblyIdentity.ToAssemblyNameObject(displayName));
AssemblyIdentity id = null;
bool success = AssemblyIdentity.TryParseDisplayName(displayName, out id);
Assert.Equal(fusion != null, success);
if (success)
{
Assert.Equal(fusion.Version, id.Version);
}
}
private void TestParseSimpleName(string displayName, string expected)
{
TestParseSimpleName(displayName, expected, expected);
}
private void TestParseSimpleName(string displayName, string expected, string expectedFusion)
{
var fusionName = FusionAssemblyIdentity.ToAssemblyNameObject(displayName);
var actual = (fusionName != null) ? FusionAssemblyIdentity.GetName(fusionName) : null;
Assert.Equal(expectedFusion, actual);
AssemblyIdentity id;
actual = AssemblyIdentity.TryParseDisplayName(displayName, out id) ? id.Name : null;
Assert.Equal(expected, actual);
}
private void TestParseDisplayName(string displayName, AssemblyIdentity expected, AssemblyIdentityParts expectedParts = 0)
{
TestParseDisplayName(displayName, expected, expectedParts, expected);
}
private void TestParseDisplayName(string displayName, AssemblyIdentity expected, AssemblyIdentityParts expectedParts, AssemblyIdentity expectedFusion)
{
var fusion = FusionAssemblyIdentity.ToAssemblyIdentity(FusionAssemblyIdentity.ToAssemblyNameObject(displayName));
Assert.Equal(expectedFusion, fusion);
AssemblyIdentity id = null;
AssemblyIdentityParts actualParts;
bool success = AssemblyIdentity.TryParseDisplayName(displayName, out id, out actualParts);
Assert.Equal(expected, id);
Assert.Equal(success, id != null);
Assert.Equal(expectedParts, actualParts);
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void GetDisplayName()
{
var id = new AssemblyIdentity("goo");
Assert.Equal("goo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", id.GetDisplayName());
id = new AssemblyIdentity("goo", new Version(1, 2, 3, 4));
Assert.Equal("goo, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null", id.GetDisplayName());
id = new AssemblyIdentity("goo", cultureName: "en-US");
Assert.Equal("goo, Version=0.0.0.0, Culture=en-US, PublicKeyToken=null", id.GetDisplayName());
id = new AssemblyIdentity("goo", publicKeyOrToken: new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }.AsImmutableOrNull());
Assert.Equal("goo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=0123456789abcdef", id.GetDisplayName(), StringComparer.OrdinalIgnoreCase);
id = new AssemblyIdentity("goo", isRetargetable: true);
Assert.Equal("goo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, Retargetable=Yes", id.GetDisplayName());
id = new AssemblyIdentity("goo", contentType: AssemblyContentType.WindowsRuntime);
Assert.Equal("goo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime", id.GetDisplayName());
id = new AssemblyIdentity("Goo", publicKeyOrToken: RoPublicKey1, hasPublicKey: true);
string dn1 = id.GetDisplayName();
string dn2 = id.GetDisplayName(fullKey: false);
Assert.True(ReferenceEquals(dn1, dn2), "cached full name expected");
Assert.Equal("Goo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=" + StrPublicKeyToken1, dn1);
string dnFull = id.GetDisplayName(fullKey: true);
Assert.Equal("Goo, Version=0.0.0.0, Culture=neutral, PublicKey=" + StrPublicKey1, dnFull);
id = new AssemblyIdentity("Goo", cultureName: "neutral");
Assert.Equal("Goo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", id.GetDisplayName());
id = new AssemblyIdentity("Goo", cultureName: " '\t\r\n\\=, ");
Assert.Equal(@"Goo, Version=0.0.0.0, Culture="" \'\t\r\n\\\=\, "", PublicKeyToken=null", id.GetDisplayName());
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TryParseDisplayName_QuotingAndEscaping()
{
// escapes:
TestParseSimpleName("/, Version=1.0.0.0", expected: "/");
TestParseSimpleName("\\\\, Version=1.0.0.0", expected: "\\");
TestParseSimpleName("\\,\\=, Version=1.0.0.0", expected: ",=");
TestParseSimpleName("\\\\, Version=1.0.0.0", expected: "\\");
TestParseSimpleName("\\/, Version=1.0.0.0", expected: "/");
TestParseSimpleName("\\\", Version=1.0.0.0", expected: "\"");
TestParseSimpleName("\\\', Version=1.0.0.0", expected: "\'");
TestParseSimpleName("a\\tb, Version=1.0.0.0", expected: "a\tb");
TestParseSimpleName("a\\rb, Version=1.0.0.0", expected: "a\rb");
TestParseSimpleName("a\\nb, Version=1.0.0.0", expected: "a\nb");
TestParseSimpleName("a\\vb, Version=1.0.0.0", expected: null);
TestParseSimpleName("a\\fb, Version=1.0.0.0", expected: null);
TestParseSimpleName("a , Version=1.0.0.0", expected: "a");
TestParseSimpleName("a\\a, Version=1.0.0.0", expected: null);
TestParseSimpleName("a\\ , Version=1.0.0.0", expected: null);
TestParseSimpleName("a\\ b, Version=1.0.0.0", expected: null);
TestParseSimpleName("a\\\tb, Version=1.0.0.0", expected: null);
TestParseSimpleName("a\\\rb, Version=1.0.0.0", expected: null);
TestParseSimpleName("a\\\nb, Version=1.0.0.0", expected: null);
TestParseSimpleName("a\\u0;b, Version=1.0.0.0", expected: null, expectedFusion: "a"); // fusion bug
TestParseSimpleName("a\\u20;b, Version=1.0.0.0", expected: "a b");
TestParseSimpleName("a\\u020;b, Version=1.0.0.0", expected: "a b");
TestParseSimpleName("a\\u0020;b, Version=1.0.0.0", expected: "a b");
TestParseSimpleName("a\\u1234", expected: null);
TestParseSimpleName("\\u12345;", expected: "\U00012345");
TestParseSimpleName("\\u100000;", expected: "\U00100000");
TestParseSimpleName("\\u10fFfF;", expected: "\U0010ffff");
TestParseSimpleName("\\u110000;", expected: null);
TestParseSimpleName("\\u1000000;", expected: null);
TestParseSimpleName("\\taa, Version=1.0.0.0", expected: "\taa");
TestParseSimpleName("a\\", expected: null);
// double quotes (unescaped can't be in the middle):
TestParseSimpleName("\"a\"", expected: "a");
TestParseSimpleName("\"a'a\", Version=1.0.0.0", expected: "a'a");
TestParseSimpleName("\\\"aa\\\", Version=1.0.0.0", expected: "\"aa\"");
TestParseSimpleName("\\\"a'a\\\", Version=1.0.0.0", expected: null);
TestParseSimpleName("\\\"a, Version=1.0.0.0", expected: "\"a");
TestParseSimpleName("\", Version=1.0.0.0\", Version=1.0.0.0", expected: ", Version=1.0.0.0");
TestParseSimpleName("\", Version=1.0.0.0", expected: ", Version=1.0.0.0");
TestParseSimpleName("\\\", Version=1.0.0.0", expected: "\"");
TestParseSimpleName("xx\\\"abc\\\"xx", expected: "xx\"abc\"xx");
TestParseSimpleName("aaa\\\"bbb, Version=1.0.0.0", expected: "aaa\"bbb");
TestParseSimpleName("\"b\", Version=1.0.0.0", expected: "b");
TestParseSimpleName(" \"b\" , Version=1.0.0.0", expected: "b");
TestParseSimpleName("\"abc', Version=1.0.0.0", expected: "abc', Version=1.0.0.0");
TestParseSimpleName("'\"a\"', Version=1.0.0.0", expected: "\"a\"");
TestParseSimpleName("'xxx\"xxx\"xxx', Version=1.0.0.0", expected: "xxx\"xxx\"xxx");
TestParseSimpleName("'xxx\\\"xxx\\'xxx', Version=1.0.0.0", expected: "xxx\"xxx'xxx");
TestParseSimpleName("b\", Version=1.0.0.0", expected: null);
TestParseSimpleName("aaa\"b\"bb, Version=1.0.0.0", expected: null);
TestParseSimpleName("a\"b, Version=1.0.0.0", expected: null);
TestParseSimpleName("\"\", Version=1.0.0.0", expected: null);
TestParseSimpleName("\"\"a\"\", Version=1.0.0.0", expected: null);
// single quotes (unescaped can't be in the middle):
TestParseSimpleName("'a'", expected: "a");
TestParseSimpleName("'a\"a', Version=1.0.0.0", expected: "a\"a");
TestParseSimpleName("\\'aa\\', Version=1.0.0.0", expected: "'aa'");
TestParseSimpleName("\\'a\"a\\', Version=1.0.0.0", expected: null);
TestParseSimpleName("\\'a,Version=1.0.0.0", expected: "'a");
TestParseSimpleName("', Version=1.0.0.0', Version=1.0.0.0", expected: ", Version=1.0.0.0");
TestParseSimpleName("', Version=1.0.0.0", expected: ", Version=1.0.0.0");
TestParseSimpleName("\\', Version=1.0.0.0", expected: "'");
TestParseSimpleName("xx\\'abc\\'xx", expected: "xx'abc'xx");
TestParseSimpleName("aaa\\'bbb, Version=1.0.0.0", expected: "aaa'bbb");
TestParseSimpleName("'b', Version=1.0.0.0", expected: "b");
TestParseSimpleName(" 'b' , Version=1.0.0.0", expected: "b");
TestParseSimpleName("'abc\", Version=1.0.0.0", expected: "abc\", Version=1.0.0.0");
TestParseSimpleName("\"'a'\", Version=1.0.0.0", expected: "'a'");
TestParseSimpleName("\"xxx'xxx'xxx\", Version=1.0.0.0", expected: "xxx'xxx'xxx");
TestParseSimpleName("\"xxx\\\"xxx\\'xxx\", Version=1.0.0.0", expected: "xxx\"xxx'xxx");
TestParseSimpleName("b', Version=1.0.0.0", expected: null);
TestParseSimpleName("aaa'b'bb, Version=1.0.0.0", expected: null);
TestParseSimpleName("a'b, Version=1.0.0.0", expected: null);
TestParseSimpleName("'', Version=1.0.0.0", expected: null);
TestParseSimpleName("''a'', Version=1.0.0.0", expected: null);
// Unicode quotes
TestParseSimpleName("\u201ca\u201d", expected: "\u201ca\u201d");
TestParseSimpleName("\\u201c;a\\u201d;", expected: "\u201ca\u201d");
TestParseSimpleName("\u201ca", expected: "\u201ca");
TestParseSimpleName("\\u201c;a", expected: "\u201ca");
TestParseSimpleName("a\u201d", expected: "a\u201d");
TestParseSimpleName("a\\u201d;", expected: "a\u201d");
TestParseSimpleName("\u201ca\u201d ", expected: "\u201ca\u201d");
TestParseSimpleName("\\u201c;a\\u201d; ", expected: "\u201ca\u201d");
TestParseSimpleName("\u2018a\u2019", expected: "\u2018a\u2019");
TestParseSimpleName("\\u2018;a\\u2019;", expected: "\u2018a\u2019");
TestParseSimpleName("\u2018a", expected: "\u2018a");
TestParseSimpleName("\\u2018;a", expected: "\u2018a");
TestParseSimpleName("a\u2019", expected: "a\u2019");
TestParseSimpleName("a\\u2019;", expected: "a\u2019");
TestParseSimpleName("\u2018a\u2019 ", expected: "\u2018a\u2019");
TestParseSimpleName("\\u2018;a\\u2019; ", expected: "\u2018a\u2019");
// NUL characters in the name:
TestParseSimpleName(" \0 , Version=1.0.0.0", expected: null);
TestParseSimpleName("zzz, Version=1.0.0\0.0", null);
TestParseSimpleName("\0", expected: null);
// can't be whitespace only
TestParseSimpleName("\t, Version=1.0.0.0", expected: null);
TestParseSimpleName("\r, Version=1.0.0.0", expected: null);
TestParseSimpleName("\n, Version=1.0.0.0", expected: null);
TestParseSimpleName(" , Version=1.0.0.0", expected: null);
// single or double quote if name starts or ends with whitespace:
TestParseSimpleName("\" a \"", expected: " a ");
TestParseSimpleName("' a '", expected: " a ");
TestParseSimpleName("'\r\t\n', Version=1.0.0.0", expected: "\r\t\n");
TestParseSimpleName("\"\r\t\n\", Version=1.0.0.0", expected: "\r\t\n");
TestParseSimpleName("x\n\t\nx, Version=1.0.0.0", expected: "x\n\t\nx");
// Missing parts
TestParseSimpleName("=", null);
TestParseSimpleName(",", null);
TestParseSimpleName("a,", null);
TestParseSimpleName("a ,", null);
TestParseSimpleName("\"a\"=", expected: null);
TestParseSimpleName("\"a\" =", expected: null);
TestParseSimpleName("\"a\",", expected: null);
TestParseSimpleName("\"a\" ,", expected: null);
TestParseSimpleName("'a'=", expected: null);
TestParseSimpleName("'a' =", expected: null);
TestParseSimpleName("'a',", expected: null);
TestParseSimpleName("'a' ,", expected: null);
// skips initial and trailing whitespace characters (' ', \t, \r, \n):
TestParseSimpleName(" \"a\" ", expected: "a");
TestParseSimpleName(" 'a' ", expected: "a");
TestParseSimpleName(" x, Version=1.0.0.0", expected: "x");
TestParseSimpleName(" x\t\r\n , Version=1.0.0.0", expected: "x");
TestParseSimpleName("\u0008x, Version=1.0.0.0", expected: "\u0008x");
TestParseSimpleName("\u0085x, Version=1.0.0.0", expected: "\u0085x");
TestParseSimpleName("\u00A0x, Version=1.0.0.0", expected: "\u00A0x");
TestParseSimpleName("\u2000x, Version=1.0.0.0", expected: "\u2000x");
TestParseSimpleName("x x, Version=1.0.0.0", expected: "x x");
TestParseSimpleName(" \"a'a\" , Version=1.0.0.0", expected: "a'a");
TestParseSimpleName(" \"aa\" x , Version=1.0.0.0", expected: null);
TestParseSimpleName(" \"aa\" \"\" , Version=1.0.0.0", expected: null);
TestParseSimpleName(" \"aa\" \'\' , Version=1.0.0.0", expected: null);
TestParseSimpleName(" A", "A");
TestParseSimpleName("A ", "A");
TestParseSimpleName(" A ", "A");
TestParseSimpleName(" A, Version=1.0.0.0", "A");
TestParseSimpleName("A , Version=1.0.0.0", "A");
TestParseSimpleName("A , Version=1.0.0.0", "A");
// invalid characters:
foreach (var c in ClrInvalidCharacters)
{
TestParseSimpleName("goo" + c, "goo" + c);
}
TestParseSimpleName("'*', Version=1.0.0.0", expected: "*", expectedFusion: null);
TestParseSimpleName("*, Version=1.0.0.0", expected: "*", expectedFusion: null);
TestParseSimpleName("hello 'xxx', Version=1.0.0.0", expected: null);
}
private void TestQuotingAndEscaping(string simpleName, string expectedSimpleName)
{
var ai = new AssemblyIdentity(simpleName);
var dn = ai.GetDisplayName();
Assert.Equal(expectedSimpleName + ", Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", dn);
TestParseSimpleName(dn, simpleName);
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void GetDisplayName_QuotingAndEscaping()
{
TestQuotingAndEscaping(",", "\\,");
TestQuotingAndEscaping("'", "\\'");
TestQuotingAndEscaping("\"", "\\\"");
TestQuotingAndEscaping("/", "/");
TestQuotingAndEscaping("\\", "\\\\");
TestQuotingAndEscaping("x\rx", "x\\rx");
TestQuotingAndEscaping("x\nx", "x\\nx");
TestQuotingAndEscaping("x\tx", "x\\tx");
TestQuotingAndEscaping("\rx", "\"\\rx\"");
TestQuotingAndEscaping("\nx", "\"\\nx\"");
TestQuotingAndEscaping("\tx", "\"\\tx\"");
TestQuotingAndEscaping(" ", "\" \"");
TestQuotingAndEscaping(" x", "\" x\"");
TestQuotingAndEscaping("x ", "\"x \"");
TestQuotingAndEscaping("\u0008", "\u0008");
TestQuotingAndEscaping("\u0085", "\u0085");
TestQuotingAndEscaping("\u00A0", "\u00A0");
TestQuotingAndEscaping("\u2000", "\u2000");
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TryParseDisplayName()
{
string V = "\\u" + ((int)'V').ToString("X4") + ";";
TestParseDisplayName(" \"fo'o\" , " + V + "ersion=1.0.0.0\t, \rCulture=zz-ZZ\n, PublicKeyToken=" + StrPublicKeyToken1,
new AssemblyIdentity("fo'o", new Version(1, 0, 0, 0), "zz-ZZ", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.Default),
NVCT);
// invalid:
AssemblyIdentity id;
Assert.Throws<ArgumentNullException>(() => AssemblyIdentity.TryParseDisplayName(null, out id));
TestParseDisplayName("", null);
TestParseDisplayName("fo=o, Culture=neutral, Version=1.0.0.0", null);
TestParseDisplayName("goo, Culture=neutral, Version,1.0.0.0", null);
// custom properties:
TestParseDisplayName("goo, A=B",
new AssemblyIdentity("goo"), N | AssemblyIdentityParts.Unknown);
// we don't allow CT=WinRT + Retargetable, fusion does.
Assert.False(
AssemblyIdentity.TryParseDisplayName("goo, Version=1.0.0.0, Culture=en-US, Retargetable=Yes, ContentType=WindowsRuntime, PublicKeyToken=" + StrPublicKeyToken1, out id));
// order
TestParseDisplayName("goo, Culture=neutral, Version=1.0.0.0",
new AssemblyIdentity("goo", new Version(1, 0, 0, 0)), NVC);
TestParseDisplayName("goo, Version=1.0.0.0, Culture=en-US, Retargetable=Yes, PublicKeyToken=" + StrPublicKeyToken1,
new AssemblyIdentity("goo", new Version(1, 0, 0, 0), "en-US", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: true),
NVCT | AssemblyIdentityParts.Retargetability);
TestParseDisplayName("goo, PublicKey=" + StrPublicKey1 + ", Version=1.0.0.1",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1), publicKeyOrToken: RoPublicKey1, hasPublicKey: true),
NVK);
TestParseDisplayName(@"Goo, Version=0.0.0.0, Culture="" \'\t\r\n\\\=\, "", PublicKeyToken=null",
new AssemblyIdentity("Goo", cultureName: " '\t\r\n\\=, "),
NVCT);
// duplicates
TestParseDisplayName("goo, Version=1.0.0.0, Version=1.0.0.0", null);
TestParseDisplayName("goo, Version=1.0.0.0, Version=2.0.0.0", null);
TestParseDisplayName("goo, Culture=neutral, Version=1.0.0.0, Culture=en-US", null);
}
[Fact]
[WorkItem(39647, "https://github.com/dotnet/roslyn/issues/39647")]
public void AssemblyIdentity_EmptyName()
{
var identity = new AssemblyIdentity(noThrow: true, name: "");
var name = identity.GetDisplayName();
Assert.Equal(", Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", name);
Assert.False(AssemblyIdentity.TryParseDisplayName(name, out _));
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TryParseDisplayName_Version()
{
TestParseDisplayName("Version=1.2.3.4, goo", null);
TestParseDisplayName("Version=1.2.3.4", null);
TestParseDisplayName("Version=", null);
TestParseDisplayName("goo, Version=", null);
TestParseDisplayName("goo, Version", null);
TestParseDisplayName("goo, Version=1",
new AssemblyIdentity("goo", new Version(1, 0, 0, 0)), N | AssemblyIdentityParts.VersionMajor);
TestParseDisplayName("goo, Version=.", new AssemblyIdentity("goo"), N);
TestParseDisplayName("goo, Version=..", new AssemblyIdentity("goo"), N);
TestParseDisplayName("goo, Version=...", new AssemblyIdentity("goo"), N);
TestParseDisplayName("goo, Version=*, Culture=en-US",
new AssemblyIdentity("goo", cultureName: "en-US"),
AssemblyIdentityParts.Name | AssemblyIdentityParts.Culture);
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TestParseVersion_Parts()
{
TestParseVersionInvalid("a");
TestParseVersionInvalid("-1");
TestParseVersionInvalid("2*");
TestParseVersionInvalid("2.1*");
TestParseVersionInvalid("2.0*.0.0");
TestParseVersionInvalid("2.*0.0.0");
TestParseVersion("1", 1, 0, 0, 0, AssemblyIdentityParts.VersionMajor);
TestParseVersion("65535", 65535, 0, 0, 0, AssemblyIdentityParts.VersionMajor);
TestParseVersionInvalid("65536");
TestParseVersion(".", 0, 0, 0, 0, 0);
TestParseVersion("1.", 1, 0, 0, 0, AssemblyIdentityParts.VersionMajor);
TestParseVersion("0.1", 0, 1, 0, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor);
TestParseVersion("1.2", 1, 2, 0, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor);
TestParseVersionInvalid("1. 2");
TestParseVersionInvalid("1 . 2");
TestParseVersion("1..", 1, 0, 0, 0, AssemblyIdentityParts.VersionMajor);
TestParseVersion("1.2.", 1, 2, 0, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor);
TestParseVersion("1.2.3", 1, 2, 3, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor | AssemblyIdentityParts.VersionBuild);
TestParseVersion(".2.3", 0, 2, 3, 0, AssemblyIdentityParts.VersionMinor | AssemblyIdentityParts.VersionBuild);
TestParseVersion("1..3", 1, 0, 3, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionBuild);
TestParseVersion("1.2.3.", 1, 2, 3, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor | AssemblyIdentityParts.VersionBuild);
TestParseVersion("1.2..4", 1, 2, 0, 4, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor | AssemblyIdentityParts.VersionRevision);
TestParseVersion("1.2..", 1, 2, 0, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor);
TestParseVersion("1.2.3.4", 1, 2, 3, 4, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor | AssemblyIdentityParts.VersionBuild | AssemblyIdentityParts.VersionRevision);
TestParseVersionInvalid("1. 2.3.4");
TestParseVersionInvalid("1.2.3. 4");
TestParseVersion("65535.65535.65535.65535", 65535, 65535, 65535, 65535,
AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor | AssemblyIdentityParts.VersionBuild | AssemblyIdentityParts.VersionRevision);
TestParseVersionInvalid("65535.65535.65535.65536");
TestParseVersion("*", 0, 0, 0, 0, AssemblyIdentityParts.VersionMajor);
TestParseVersion("1.*", 1, 0, 0, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor);
TestParseVersion("1.2.*", 1, 2, 0, 0, AssemblyIdentityParts.VersionMajor | AssemblyIdentityParts.VersionMinor | AssemblyIdentityParts.VersionBuild);
TestParseVersion("1.2.3.*", 1, 2, 3, 0, AssemblyIdentityParts.Version);
TestParseVersion("1.*.2.*", 1, 0, 2, 0, AssemblyIdentityParts.Version);
TestParseVersionInvalid("1.2.3.4.");
TestParseVersionInvalid("1.2.3.4.5");
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TestParseVersionAll()
{
// all combinations:
var possibleParts = new[] { "0", "3", ".", "", "*", null };
foreach (var part1 in possibleParts)
{
foreach (var part2 in possibleParts)
{
foreach (var part3 in possibleParts)
{
foreach (var part4 in possibleParts)
{
TestParseVersion(
(part1 ?? "") +
(part2 != null ? "." + part2 : "") +
(part3 != null ? "." + part3 : "") +
(part4 != null ? "." + part4 : ""));
}
}
}
}
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TryParseDisplayName_Culture()
{
TestParseDisplayName("goo, Version=1.0.0.1, Culture=null",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1), cultureName: "null"), NVC);
TestParseDisplayName("goo, Version=1.0.0.1, cULture=en-US",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1), cultureName: "en-US"), NVC);
TestParseDisplayName("goo, Version=1.0.0.1, Language=en-US",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1), cultureName: "en-US"), NVC);
TestParseDisplayName("goo, Version=1.0.0.1, languagE=en-US",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1), cultureName: "en-US"), NVC);
TestParseDisplayName("goo, Culture=*, Version=1.0.0.1",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1)), NV);
TestParseDisplayName("goo, Culture=*", new AssemblyIdentity("goo"), N);
TestParseDisplayName("goo, Culture=*, Culture=en-US, Version=1.0.0.1", null);
TestParseDisplayName("Goo, Version=1.0.0.0, Culture='neutral', PublicKeyToken=null",
new AssemblyIdentity("Goo", new Version(1, 0, 0, 0), cultureName: null), NVCT);
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TryParseDisplayName_Keys()
{
// empty keys:
TestParseDisplayName("goo, PublicKeyToken=null, Version=1.0.0.1",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1)), NVT);
TestParseDisplayName("goo, PublicKeyToken=neutral, Version=1.0.0.1",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1)), NVT);
TestParseDisplayName("goo, PublicKeyToken=*, Version=1.0.0.1",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1)), NV);
TestParseDisplayName("goo, PublicKey=null, Version=1.0.0.1", null);
TestParseDisplayName("goo, PublicKey=neutral, Version=1.0.0.1", null);
TestParseDisplayName("goo, PublicKey=*, Version=1.0.0.1",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1)), NV);
// keys
TestParseDisplayName("goo, PublicKeyToken=, Version=1.0.0.1", null);
TestParseDisplayName("goo, PublicKeyToken=1, Version=1.0.0.1", null);
TestParseDisplayName("goo, PublicKeyToken=111111111111111, Version=1.0.0.1", null);
TestParseDisplayName("goo, PublicKeyToken=1111111111111111111, Version=1.0.0.1", null);
TestParseDisplayName("goo, PublicKey=1, Version=1.0.0.1", null);
TestParseDisplayName("goo, PublicKey=1000000040000000", null);
TestParseDisplayName("goo, PublicKey=11, Version=1.0.0.1", null);
// TODO: need to calculate the correct token for the ECMA key.
// TestParseDisplayName("goo, PublicKey=0000000040000000",
// expectedParts: 0,
// expectedFusion: null, // Fusion rejects the ECMA key.
// expected: new AssemblyIdentity("goo", hasPublicKey: true, publicKeyOrToken: new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0 }.AsImmutable()));
// if public key token calculated from public key matches, then it's ok to specify both
TestParseDisplayName("goo, Culture=neutral, Version=1.0.0.0, PublicKey=" + StrPublicKey1 + ", PublicKeyToken=" + StrPublicKeyToken1,
new AssemblyIdentity("goo", new Version(1, 0, 0, 0), publicKeyOrToken: RoPublicKey1, hasPublicKey: true), NVC | AssemblyIdentityParts.PublicKeyOrToken);
TestParseDisplayName("goo, Culture=neutral, Version=1.0.0.0, PublicKey=" + StrPublicKey1 + ", PublicKeyToken=1111111111111111", null);
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TryParseDisplayName_ContentType()
{
TestParseDisplayName("goo, Version=1.0.0.1, ContentType=WindowsRuntime",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1), contentType: AssemblyContentType.WindowsRuntime), NV | AssemblyIdentityParts.ContentType);
TestParseDisplayName("goo, Version=1.0.0.1, ContentType=*",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1)), NV);
TestParseDisplayName("goo, Version=1.0.0.1, ContentType=Default", null);
}
[ConditionalFact(typeof(WindowsDesktopOnly), Reason = ConditionalSkipReason.TestExecutionNeedsFusion)]
public void TryParseDisplayName_Retargetable()
{
// for some reason the Fusion rejects to parse Retargetable if they are not full names
TestParseDisplayName("goo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=" + StrPublicKeyToken1 + ", Retargetable=yEs",
new AssemblyIdentity("goo", new Version(1, 0, 0, 0), publicKeyOrToken: RoPublicKeyToken1, isRetargetable: true),
NVCT | AssemblyIdentityParts.Retargetability);
TestParseDisplayName("goo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=" + StrPublicKeyToken1 + ", Retargetable=*",
new AssemblyIdentity("goo", new Version(1, 0, 0, 0), publicKeyOrToken: RoPublicKeyToken1),
NVCT);
TestParseDisplayName("goo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=" + StrPublicKeyToken1 + ", retargetable=NO",
new AssemblyIdentity("goo", new Version(1, 0, 0, 0), publicKeyOrToken: RoPublicKeyToken1),
NVCT | AssemblyIdentityParts.Retargetability);
TestParseDisplayName("goo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=" + StrPublicKeyToken1 + ", Retargetable=Bar",
null);
TestParseDisplayName("goo, Version=1.0.0.1, Retargetable=*",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1)), NV);
TestParseDisplayName("goo, Version=1.0.0.1, Retargetable=No",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1)), NV | AssemblyIdentityParts.Retargetability,
expectedFusion: null);
TestParseDisplayName("goo, Version=1.0.0.1, retargetable=YEs",
new AssemblyIdentity("goo", new Version(1, 0, 0, 1), isRetargetable: true), NV | AssemblyIdentityParts.Retargetability,
expectedFusion: null);
}
}
}
|