Merge remote-tracking branch 'origin/netcore/netcore' into netcore/feature/migrate-remaining-trees

This commit is contained in:
Bjarke Berg
2020-06-17 18:05:40 +02:00
100 changed files with 1336 additions and 2141 deletions

View File

@@ -0,0 +1,23 @@
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
[TestFixture]
public class AttemptTests
{
[Test]
public void AttemptIf()
{
// just making sure that it is ok to use TryParse as a condition
int value;
var attempt = Attempt.If(int.TryParse("1234", out value), value);
Assert.IsTrue(attempt.Success);
Assert.AreEqual(1234, attempt.Result);
attempt = Attempt.If(int.TryParse("12xxx34", out value), value);
Assert.IsFalse(attempt.Success);
}
}
}

View File

@@ -71,7 +71,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
}
[TestCase(ClaimTypes.NameIdentifier, _testUserId)]
[TestCase(ClaimTypes.Name, _testUserName)]
[TestCase(ClaimTypes.Name, _testUserName)]
public async Task CreateAsync_Should_Include_Claim(string expectedClaimType, object expectedClaimValue)
{
var sut = CreateSut();
@@ -79,7 +79,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
var claimsPrincipal = await sut.CreateAsync(_testUser);
Assert.True(claimsPrincipal.HasClaim(expectedClaimType, expectedClaimValue.ToString()));
Assert.True(claimsPrincipal.GetUmbracoIdentity().Actor.HasClaim(expectedClaimType, expectedClaimValue.ToString()));
Assert.True(claimsPrincipal.GetUmbracoIdentity().HasClaim(expectedClaimType, expectedClaimValue.ToString()));
}
[Test]
@@ -94,9 +94,9 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
var sut = CreateSut();
var claimsPrincipal = await sut.CreateAsync(_testUser);
Assert.True(claimsPrincipal.HasClaim(expectedClaimType, expectedClaimValue));
Assert.True(claimsPrincipal.GetUmbracoIdentity().Actor.HasClaim(expectedClaimType, expectedClaimValue));
Assert.True(claimsPrincipal.GetUmbracoIdentity().HasClaim(expectedClaimType, expectedClaimValue));
}
[Test]
@@ -112,7 +112,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
var sut = CreateSut();
var claimsPrincipal = await sut.CreateAsync(_testUser);
Assert.True(claimsPrincipal.HasClaim(expectedClaimType, expectedClaimValue));
}
@@ -131,7 +131,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
var claimsPrincipal = await sut.CreateAsync(_testUser);
Assert.True(claimsPrincipal.GetUmbracoIdentity().Actor.HasClaim(expectedClaimType, expectedClaimValue));
Assert.True(claimsPrincipal.GetUmbracoIdentity().HasClaim(expectedClaimType, expectedClaimValue));
}
[SetUp]

View File

@@ -37,6 +37,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
if (!UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out var backofficeIdentity))
Assert.Fail();
Assert.IsNull(backofficeIdentity.Actor);
Assert.AreEqual(1234, backofficeIdentity.Id);
//Assert.AreEqual(sessionId, backofficeIdentity.SessionId);
Assert.AreEqual(securityStamp, backofficeIdentity.SecurityStamp);
@@ -60,7 +61,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
new Claim(ClaimTypes.Name, "testing", ClaimValueTypes.String, TestIssuer, TestIssuer),
});
if (UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out var backofficeIdentity))
if (UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out _))
Assert.Fail();
Assert.Pass();
@@ -83,7 +84,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
new Claim(ClaimsIdentity.DefaultRoleClaimType, "admin", ClaimValueTypes.String, TestIssuer, TestIssuer),
});
if (UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out var backofficeIdentity))
if (UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity, out _))
Assert.Fail();
Assert.Pass();
@@ -105,6 +106,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
1234, "testing", "hello world", new[] { 654 }, new[] { 654 }, "en-us", securityStamp, new[] { "content", "media" }, new[] { "admin" });
Assert.AreEqual(12, identity.Claims.Count());
Assert.IsNull(identity.Actor);
}
@@ -116,7 +118,11 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.BackOffice
var identity = new UmbracoBackOfficeIdentity(
1234, "testing", "hello world", new[] { 654 }, new[] { 654 }, "en-us", securityStamp, new[] { "content", "media" }, new[] { "admin" });
// this will be filtered out during cloning
identity.AddClaim(new Claim(Constants.Security.TicketExpiresClaimType, "test"));
var cloned = identity.Clone();
Assert.IsNull(cloned.Actor);
Assert.AreEqual(10, cloned.Claims.Count());
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Security.Claims;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
public class ClaimsIdentityExtensionsTests
{
[Test]
public void FindFirstValue_WhenIdentityIsNull_ExpectArgumentNullException()
{
ClaimsIdentity identity = null;
Assert.Throws<ArgumentNullException>(() => identity.FindFirstValue("test"));
}
[Test]
public void FindFirstValue_WhenClaimNotPresent_ExpectNull()
{
var identity = new ClaimsIdentity(new List<Claim>());
var value = identity.FindFirstValue("test");
Assert.IsNull(value);
}
[Test]
public void FindFirstValue_WhenMatchingClaimPresent_ExpectCorrectValue()
{
var expectedClaim = new Claim("test", "123", "string", "Umbraco");
var identity = new ClaimsIdentity(new List<Claim> {expectedClaim});
var value = identity.FindFirstValue("test");
Assert.AreEqual(expectedClaim.Value, value);
}
[Test]
public void FindFirstValue_WhenMultipleMatchingClaimsPresent_ExpectFirstValue()
{
var expectedClaim = new Claim("test", "123", "string", "Umbraco");
var dupeClaim = new Claim(expectedClaim.Type, Guid.NewGuid().ToString());
var identity = new ClaimsIdentity(new List<Claim> {expectedClaim, dupeClaim});
var value = identity.FindFirstValue("test");
Assert.AreEqual(expectedClaim.Value, value);
}
}
}

View File

@@ -0,0 +1,97 @@
using System.Linq;
using NUnit.Framework;
using Umbraco.Core.Collections;
using Umbraco.Tests.Common;
namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections
{
[TestFixture]
public class DeepCloneableListTests
{
[Test]
public void Deep_Clones_Each_Item_Once()
{
var list = new DeepCloneableList<TestClone>(ListCloneBehavior.CloneOnce);
list.Add(new TestClone());
list.Add(new TestClone());
list.Add(new TestClone());
var cloned = list.DeepClone() as DeepCloneableList<TestClone>;
//Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID)
Assert.IsTrue(list.SequenceEqual(cloned));
//Test that each instance in the list is not the same one
foreach (var item in list)
{
var clone = cloned.Single(x => x.Id == item.Id);
Assert.AreNotSame(item, clone);
}
//clone again from the clone - since it's clone once the items should be the same
var cloned2 = cloned.DeepClone() as DeepCloneableList<TestClone>;
//Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID)
Assert.IsTrue(cloned.SequenceEqual(cloned2));
//Test that each instance in the list is the same one
foreach (var item in cloned)
{
var clone = cloned2.Single(x => x.Id == item.Id);
Assert.AreSame(item, clone);
}
}
[Test]
public void Deep_Clones_All_Elements()
{
var list = new DeepCloneableList<TestClone>(ListCloneBehavior.Always);
list.Add(new TestClone());
list.Add(new TestClone());
list.Add(new TestClone());
var cloned = list.DeepClone() as DeepCloneableList<TestClone>;
Assert.IsNotNull(cloned);
Assert.AreNotSame(list, cloned);
Assert.AreEqual(list.Count, cloned.Count);
}
[Test]
public void Clones_Each_Item()
{
var list = new DeepCloneableList<TestClone>(ListCloneBehavior.Always);
list.Add(new TestClone());
list.Add(new TestClone());
list.Add(new TestClone());
var cloned = (DeepCloneableList<TestClone>) list.DeepClone();
foreach (var item in cloned)
{
Assert.IsTrue(item.IsClone);
}
}
[Test]
public void Cloned_Sequence_Equals()
{
var list = new DeepCloneableList<TestClone>(ListCloneBehavior.Always);
list.Add(new TestClone());
list.Add(new TestClone());
list.Add(new TestClone());
var cloned = (DeepCloneableList<TestClone>) list.DeepClone();
//Test that each item in the sequence is equal - based on the equality comparer of TestClone (i.e. it's ID)
Assert.IsTrue(list.SequenceEqual(cloned));
//Test that each instance in the list is not the same one
foreach (var item in list)
{
var clone = cloned.Single(x => x.Id == item.Id);
Assert.AreNotSame(item, clone);
}
}
}
}

View File

@@ -0,0 +1,81 @@
using System;
using NUnit.Framework;
using Umbraco.Core.Collections;
namespace Umbraco.Tests.UnitTests.Umbraco.Core.Collections
{
[TestFixture]
public class OrderedHashSetTests
{
[Test]
public void Keeps_Last()
{
var list = new OrderedHashSet<MyClass>(keepOldest: false);
var items = new[] {new MyClass("test"), new MyClass("test"), new MyClass("test")};
foreach (var item in items)
{
list.Add(item);
}
Assert.AreEqual(1, list.Count);
Assert.AreEqual(items[2].Id, list[0].Id);
Assert.AreNotEqual(items[0].Id, list[0].Id);
}
[Test]
public void Keeps_First()
{
var list = new OrderedHashSet<MyClass>(keepOldest: true);
var items = new[] {new MyClass("test"), new MyClass("test"), new MyClass("test")};
foreach (var item in items)
{
list.Add(item);
}
Assert.AreEqual(1, list.Count);
Assert.AreEqual(items[0].Id, list[0].Id);
}
private class MyClass : IEquatable<MyClass>
{
public MyClass(string name)
{
Name = name;
Id = Guid.NewGuid();
}
public string Name { get; }
public Guid Id { get; }
public bool Equals(MyClass other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return string.Equals(Name, other.Name);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MyClass) obj);
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
public static bool operator ==(MyClass left, MyClass right)
{
return Equals(left, right);
}
public static bool operator !=(MyClass left, MyClass right)
{
return Equals(left, right) == false;
}
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using Lucene.Net.Index;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
[TestFixture]
public class DelegateExtensionsTests
{
[Test]
public void Only_Executes_Specific_Count()
{
const int maxTries = 5;
var totalTries = 0;
DelegateExtensions.RetryUntilSuccessOrMaxAttempts((currentTry) =>
{
totalTries = currentTry;
return Attempt<IndexWriter>.Fail();
}, 5, TimeSpan.FromMilliseconds(10));
Assert.AreEqual(maxTries, totalTries);
}
[Test]
public void Quits_On_Success_Count()
{
var totalTries = 0;
DelegateExtensions.RetryUntilSuccessOrMaxAttempts((currentTry) =>
{
totalTries = currentTry;
return totalTries == 2 ? Attempt<string>.Succeed() : Attempt<string>.Fail();
}, 5, TimeSpan.FromMilliseconds(10));
Assert.AreEqual(2, totalTries);
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Web.Trees;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
[TestFixture]
public class EnumExtensionsTests
{
[TestCase(TreeUse.Dialog, TreeUse.Dialog, true)]
[TestCase(TreeUse.Dialog, TreeUse.Main, false)]
[TestCase(TreeUse.Dialog | TreeUse.Main, TreeUse.Dialog, true)]
[TestCase(TreeUse.Dialog, TreeUse.Dialog | TreeUse.Main, false)]
public void HasFlagTest(TreeUse value, TreeUse test, bool expected)
{
// the built-in Enum.HasFlag() method determines whether
// all bits from <test> are set (other bits can be set too)
if (expected)
Assert.IsTrue(value.HasFlag(test));
else
Assert.IsFalse(value.HasFlag(test));
}
[Obsolete]
[TestCase(TreeUse.Dialog, TreeUse.Dialog, true)]
[TestCase(TreeUse.Dialog, TreeUse.Main, false)]
[TestCase(TreeUse.Dialog | TreeUse.Main, TreeUse.Dialog, true)]
[TestCase(TreeUse.Dialog, TreeUse.Dialog | TreeUse.Main, false)]
public void HasFlagAllTest(TreeUse value, TreeUse test, bool expected)
{
// the HasFlagAll() extension method determines whether
// all bits from <test> are set (other bits can be set too)
if (expected)
Assert.IsTrue(value.HasFlagAll(test));
else
Assert.IsFalse(value.HasFlagAll(test));
}
[TestCase(TreeUse.Dialog, TreeUse.Dialog, true)]
[TestCase(TreeUse.Dialog, TreeUse.Main, false)]
[TestCase(TreeUse.Dialog | TreeUse.Main, TreeUse.Dialog, true)]
[TestCase(TreeUse.Dialog, TreeUse.Dialog | TreeUse.Main, true)]
public void HasFlagAnyTest(TreeUse value, TreeUse test, bool expected)
{
// the HasFlagAny() extension method determines whether
// at least one bit from <test> is set
if (expected)
Assert.IsTrue(value.HasFlagAny(test));
else
Assert.IsFalse(value.HasFlagAny(test));
}
}
}

View File

@@ -0,0 +1,186 @@
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
[TestFixture]
public class EnumerableExtensionsTests
{
[Test]
public void Unsorted_Sequence_Equal()
{
var list1 = new[] { 1, 2, 3, 4, 5, 6 };
var list2 = new[] { 6, 5, 3, 2, 1, 4 };
var list3 = new[] { 6, 5, 4, 3, 2, 2 };
Assert.IsTrue(list1.UnsortedSequenceEqual(list2));
Assert.IsTrue(list2.UnsortedSequenceEqual(list1));
Assert.IsFalse(list1.UnsortedSequenceEqual(list3));
Assert.IsTrue(((IEnumerable<object>)null).UnsortedSequenceEqual(null));
Assert.IsFalse(((IEnumerable<int>)null).UnsortedSequenceEqual(list1));
Assert.IsFalse(list1.UnsortedSequenceEqual(null));
}
[Test]
public void Contains_All()
{
var list1 = new[] {1, 2, 3, 4, 5, 6};
var list2 = new[] {6, 5, 3, 2, 1, 4};
var list3 = new[] {6, 5, 4, 3};
Assert.IsTrue(list1.ContainsAll(list2));
Assert.IsTrue(list2.ContainsAll(list1));
Assert.IsTrue(list1.ContainsAll(list3));
Assert.IsFalse(list3.ContainsAll(list1));
}
[Test]
public void SelectRecursive_2()
{
var hierarchy = new TestItem("1")
{
Children = new List<TestItem>
{
new TestItem("1.1"),
new TestItem("1.2"),
new TestItem("1.3")
}
};
var selectRecursive = hierarchy.Children.SelectRecursive(x => x.Children);
Assert.AreEqual(3, selectRecursive.Count());
}
[Test]
public void SelectRecursive()
{
var hierarchy = new TestItem("1")
{
Children = new List<TestItem>
{
new TestItem("1.1")
{
Children = new List<TestItem>
{
new TestItem("1.1.1")
{
Children = new List<TestItem>
{
new TestItem("1.1.1.1")
{
Children = new List<TestItem>
{
new TestItem("1.1.1.1.1"),
new TestItem("1.1.1.1.2")
}
}
}
}
}
},
new TestItem("1.2")
{
Children = new List<TestItem>
{
new TestItem("1.2.1")
{
Children = new List<TestItem>
{
new TestItem("1.2.1.1")
{
Children = new List<TestItem>()
}
}
},
new TestItem("1.2.2")
{
Children = new List<TestItem>
{
new TestItem("1.2.2.1")
{
Children = new List<TestItem>()
}
}
}
}
}
}
};
var selectRecursive = hierarchy.Children.SelectRecursive(x => x.Children);
Assert.AreEqual(10, selectRecursive.Count());
}
private class TestItem
{
public TestItem(string name)
{
Children = Enumerable.Empty<TestItem>();
Name = name;
}
public string Name { get; }
public IEnumerable<TestItem> Children { get; set; }
}
[Test]
public void InGroupsOf_ReturnsAllElements()
{
var integers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
var groupsOfTwo = integers.InGroupsOf(2).ToArray();
var flattened = groupsOfTwo.SelectMany(x => x).ToArray();
Assert.That(groupsOfTwo.Length, Is.EqualTo(5));
Assert.That(flattened.Length, Is.EqualTo(integers.Length));
CollectionAssert.AreEquivalent(integers, flattened);
var groupsOfMassive = integers.InGroupsOf(100).ToArray();
Assert.That(groupsOfMassive.Length, Is.EqualTo(1));
flattened = groupsOfMassive.SelectMany(x => x).ToArray();
Assert.That(flattened.Length, Is.EqualTo(integers.Length));
CollectionAssert.AreEquivalent(integers, flattened);
}
[Test]
public void InGroupsOf_CanRepeat()
{
var integers = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
var inGroupsOf = integers.InGroupsOf(2);
Assert.AreEqual(5, inGroupsOf.Count());
Assert.AreEqual(5, inGroupsOf.Count()); // again
}
[TestCase]
public void DistinctBy_ReturnsDistinctElements_AndResetsIteratorCorrectly()
{
// Arrange
var tuple1 = new System.Tuple<string, string>("fruit", "apple");
var tuple2 = new System.Tuple<string, string>("fruit", "orange");
var tuple3 = new System.Tuple<string, string>("fruit", "banana");
var tuple4 = new System.Tuple<string, string>("fruit", "banana"); // Should be filtered out
var list = new List<System.Tuple<string, string>>()
{
tuple1,
tuple2,
tuple3,
tuple4
};
// Act
var iteratorSource = list.DistinctBy(x => x.Item2);
// Assert
// First check distinction
Assert.AreEqual(3, iteratorSource.Count());
// Check for iterator block mistakes - reset to original query first
iteratorSource = list.DistinctBy(x => x.Item2);
Assert.AreEqual(iteratorSource.Count(), iteratorSource.ToList().Count());
}
}
}

View File

@@ -0,0 +1,40 @@
using System;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
public class GuidUtilsTests
{
[Test]
public void GuidCombineMethodsAreEqual()
{
var a = Guid.NewGuid();
var b = Guid.NewGuid();
Assert.AreEqual(GuidUtils.Combine(a, b).ToByteArray(), Combine(a, b));
}
[Test]
public void GuidThingTest()
{
var guid = new Guid("f918382f-2bba-453f-a3e2-1f594016ed3b");
Assert.AreEqual("f22br4n0fm5fli5c", GuidUtils.ToBase32String(guid, 16));
Assert.AreEqual("f22br4n0f", GuidUtils.ToBase32String(guid, 9));
}
// Reference implementation taken from original code.
private static byte[] Combine(Guid guid1, Guid guid2)
{
var bytes1 = guid1.ToByteArray();
var bytes2 = guid2.ToByteArray();
var bytes = new byte[bytes1.Length];
for (var i = 0; i < bytes1.Length; i++)
{
bytes[i] = (byte)(bytes1[i] ^ bytes2[i]);
}
return bytes;
}
}
}

View File

@@ -0,0 +1,71 @@
using System;
using System.Text;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
public class HexEncoderTests
{
[Test]
public void ToHexStringCreatesCorrectValue()
{
var buffer = new byte[255];
var random = new Random();
random.NextBytes(buffer);
var sb = new StringBuilder(buffer.Length * 2);
for (var i = 0; i < buffer.Length; i++)
{
sb.Append(buffer[i].ToString("X2"));
}
var expected = sb.ToString();
var actual = HexEncoder.Encode(buffer);
Assert.AreEqual(expected, actual);
}
[Test]
public void ToHexStringWithSeparatorCreatesCorrectValue()
{
var buffer = new byte[255];
var random = new Random();
random.NextBytes(buffer);
var expected = ToHexString(buffer, '/', 2, 4);
var actual = HexEncoder.Encode(buffer, '/', 2, 4);
Assert.AreEqual(expected, actual);
}
private static readonly char[] _bytesToHexStringLookup = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
// Reference implementation taken from original extension method.
private static string ToHexString(byte[] bytes, char separator, int blockSize, int blockCount)
{
int p = 0, bytesLength = bytes.Length, count = 0, size = 0;
var chars = new char[(bytesLength * 2) + blockCount];
for (var i = 0; i < bytesLength; i++)
{
var b = bytes[i];
chars[p++] = _bytesToHexStringLookup[b / 0x10];
chars[p++] = _bytesToHexStringLookup[b % 0x10];
if (count == blockCount)
{
continue;
}
if (++size < blockSize)
{
continue;
}
chars[p++] = separator;
size = 0;
count++;
}
return new string(chars, 0, chars.Length);
}
}
}

View File

@@ -0,0 +1,40 @@
using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
[TestFixture]
public class ReflectionTests
{
[Test]
public void GetBaseTypesIsOk()
{
// tests that the GetBaseTypes extension method works.
var type = typeof(Class2);
var types = type.GetBaseTypes(true).ToArray();
Assert.AreEqual(3, types.Length);
Assert.Contains(typeof(Class2), types);
Assert.Contains(typeof(Class1), types);
Assert.Contains(typeof(object), types);
types = type.GetBaseTypes(false).ToArray();
Assert.AreEqual(2, types.Length);
Assert.Contains(typeof(Class1), types);
Assert.Contains(typeof(object), types);
}
#region Test Objects
private class Class1
{
}
private class Class2 : Class1
{
}
#endregion
}
}

View File

@@ -0,0 +1,677 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
[TestFixture]
public class ReflectionUtilitiesTests
{
[Test]
public void EmitCtorEmits()
{
var ctor1 = ReflectionUtilities.EmitConstructor<Func<Class1>>();
Assert.IsInstanceOf<Class1>(ctor1());
var ctor2 = ReflectionUtilities.EmitConstructor<Func<object>>(declaring: typeof(Class1));
Assert.IsInstanceOf<Class1>(ctor2());
var ctor3 = ReflectionUtilities.EmitConstructor<Func<int, Class3>>();
Assert.IsInstanceOf<Class3>(ctor3(42));
var ctor4 = ReflectionUtilities.EmitConstructor<Func<int, object>>(declaring: typeof(Class3));
Assert.IsInstanceOf<Class3>(ctor4(42));
}
[Test]
public void EmitCtorEmitsFromInfo()
{
var ctorInfo = typeof(Class1).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, Array.Empty<Type>(), null);
var ctor1 = ReflectionUtilities.EmitConstructor<Func<Class1>>(ctorInfo);
Assert.IsInstanceOf<Class1>(ctor1());
ctorInfo = typeof(Class1).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, new[] { typeof(int) }, null);
var ctor3 = ReflectionUtilities.EmitConstructor<Func<int, object>>(ctorInfo);
Assert.IsInstanceOf<Class1>(ctor3(42));
Assert.Throws<ArgumentException>(() => ReflectionUtilities.EmitConstructor<Func<string, object>>(ctorInfo));
}
[Test]
public void EmitCtorEmitsPrivateCtor()
{
var ctor = ReflectionUtilities.EmitConstructor<Func<string, Class3>>();
Assert.IsInstanceOf<Class3>(ctor("foo"));
}
[Test]
public void EmitCtorThrowsIfNotFound()
{
Assert.Throws<InvalidOperationException>(() => ReflectionUtilities.EmitConstructor<Func<bool, Class3>>());
}
[Test]
public void EmitCtorThrowsIfInvalid()
{
var ctorInfo = typeof(Class1).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, Array.Empty<Type>(), null);
Assert.Throws<ArgumentException>(() => ReflectionUtilities.EmitConstructor<Func<Class2>>(ctorInfo));
}
[Test]
public void EmitCtorReturnsNull()
{
Assert.IsNull(ReflectionUtilities.EmitConstructor<Func<bool, Class3>>(false));
}
[Test]
public void EmitMethodEmitsInstance()
{
var class1 = new Class1();
var method1 = ReflectionUtilities.EmitMethod<Action<Class1>>("Method1");
method1(class1);
var method2 = ReflectionUtilities.EmitMethod<Action<Class1, int>>("Method2");
method2(class1, 42);
var method3 = ReflectionUtilities.EmitMethod<Func<Class1, int>>("Method3");
Assert.AreEqual(42, method3(class1));
var method4 = ReflectionUtilities.EmitMethod<Func<Class1, string, int>>("Method4");
Assert.AreEqual(42, method4(class1, "42"));
}
[Test]
public void EmitMethodEmitsStatic()
{
var method1 = ReflectionUtilities.EmitMethod<Class1, Action>("SMethod1");
method1();
var method2 = ReflectionUtilities.EmitMethod<Class1, Action<int>>("SMethod2");
method2(42);
var method3 = ReflectionUtilities.EmitMethod<Class1, Func<int>>("SMethod3");
Assert.AreEqual(42, method3());
var method4 = ReflectionUtilities.EmitMethod<Class1, Func<string, int>>("SMethod4");
Assert.AreEqual(42, method4("42"));
}
[Test]
public void EmitMethodEmitsStaticStatic()
{
var method = ReflectionUtilities.EmitMethod<Action>(typeof (StaticClass1), "Method");
method();
}
[Test]
public void EmitMethodEmitsFromInfo()
{
var class1 = new Class1();
var methodInfo = typeof (Class1).GetMethod("Method1", BindingFlags.Instance | BindingFlags.Public);
var method1 = ReflectionUtilities.EmitMethod<Action<Class1>>(methodInfo);
method1(class1);
methodInfo = typeof(Class1).GetMethod("Method2", BindingFlags.Instance | BindingFlags.Public, null, new [] { typeof(int) }, null);
var method2 = ReflectionUtilities.EmitMethod<Action<Class1, int>>(methodInfo);
method2(class1, 42);
methodInfo = typeof(Class1).GetMethod("Method3", BindingFlags.Instance | BindingFlags.Public);
var method3 = ReflectionUtilities.EmitMethod<Func<Class1, int>>(methodInfo);
Assert.AreEqual(42, method3(class1));
methodInfo = typeof(Class1).GetMethod("Method4", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null);
var method4 = ReflectionUtilities.EmitMethod<Func<Class1, string, int>>(methodInfo);
Assert.AreEqual(42, method4(class1, "42"));
methodInfo = typeof(Class1).GetMethod("SMethod1", BindingFlags.Static | BindingFlags.Public);
var smethod1 = ReflectionUtilities.EmitMethod<Action>(methodInfo);
smethod1();
methodInfo = typeof(Class1).GetMethod("SMethod2", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(int) }, null);
var smethod2 = ReflectionUtilities.EmitMethod<Action<int>>(methodInfo);
smethod2(42);
methodInfo = typeof(Class1).GetMethod("SMethod3", BindingFlags.Static | BindingFlags.Public);
var smethod3 = ReflectionUtilities.EmitMethod<Func<int>>(methodInfo);
Assert.AreEqual(42, smethod3());
methodInfo = typeof(Class1).GetMethod("SMethod4", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(string) }, null);
var smethod4 = ReflectionUtilities.EmitMethod<Func<string, int>>(methodInfo);
Assert.AreEqual(42, smethod4("42"));
methodInfo = typeof(StaticClass1).GetMethod("Method", BindingFlags.Static | BindingFlags.Public);
var method = ReflectionUtilities.EmitMethod<Action>(methodInfo);
method();
}
[Test]
public void EmitMethodEmitsPrivateMethod()
{
var class1 = new Class1();
var method1 = ReflectionUtilities.EmitMethod<Action<Class1>>("MethodP1");
method1(class1);
var method2 = ReflectionUtilities.EmitMethod<Class1, Action>("SMethodP1");
method2();
}
[Test]
public void EmitMethodThrowsIfNotFound()
{
Assert.Throws<InvalidOperationException>(() => ReflectionUtilities.EmitMethod<Action<Class1>>("ZZZ"));
Assert.Throws<InvalidOperationException>(() => ReflectionUtilities.EmitMethod<Action<Class1, int, int>>("Method1"));
}
[Test]
public void EmitMethodThrowsIfInvalid()
{
var methodInfo = typeof(Class1).GetMethod("Method1", BindingFlags.Instance | BindingFlags.Public);
Assert.Throws<ArgumentException>(() => ReflectionUtilities.EmitMethod<Action<Class1, int, int>>(methodInfo));
}
[Test]
public void EmitMethodReturnsNull()
{
Assert.IsNull(ReflectionUtilities.EmitMethod<Action<Class1>>("ZZZ", false));
Assert.IsNull(ReflectionUtilities.EmitMethod<Action<Class1, int, int>>("Method1", false));
}
[Test]
public void EmitPropertyEmits()
{
var class1 = new Class1();
var getter1 = ReflectionUtilities.EmitPropertyGetter<Class1, int>("Value1");
Assert.AreEqual(42, getter1(class1));
var getter2 = ReflectionUtilities.EmitPropertyGetter<Class1, int>("Value3");
Assert.AreEqual(42, getter2(class1));
var setter1 = ReflectionUtilities.EmitPropertySetter<Class1, int>("Value2");
setter1(class1, 42);
var setter2 = ReflectionUtilities.EmitPropertySetter<Class1, int>("Value3");
setter2(class1, 42);
(var getter3, var setter3) = ReflectionUtilities.EmitPropertyGetterAndSetter<Class1, int>("Value3");
Assert.AreEqual(42, getter3(class1));
setter3(class1, 42);
}
[Test]
public void EmitPropertyEmitsFromInfo()
{
var class1 = new Class1();
var propertyInfo = typeof (Class1).GetProperty("Value1");
var getter1 = ReflectionUtilities.EmitPropertyGetter<Class1, int>(propertyInfo);
Assert.AreEqual(42, getter1(class1));
propertyInfo = typeof(Class1).GetProperty("Value3");
var getter2 = ReflectionUtilities.EmitPropertyGetter<Class1, int>(propertyInfo);
Assert.AreEqual(42, getter2(class1));
propertyInfo = typeof(Class1).GetProperty("Value2");
var setter1 = ReflectionUtilities.EmitPropertySetter<Class1, int>(propertyInfo);
setter1(class1, 42);
propertyInfo = typeof(Class1).GetProperty("Value3");
var setter2 = ReflectionUtilities.EmitPropertySetter<Class1, int>(propertyInfo);
setter2(class1, 42);
(var getter3, var setter3) = ReflectionUtilities.EmitPropertyGetterAndSetter<Class1, int>(propertyInfo);
Assert.AreEqual(42, getter3(class1));
setter3(class1, 42);
}
[Test]
public void EmitPropertyEmitsPrivateProperty()
{
var class1 = new Class1();
var getter1 = ReflectionUtilities.EmitPropertyGetter<Class1, int>("ValueP1");
Assert.AreEqual(42, getter1(class1));
}
[Test]
public void EmitPropertyThrowsIfNotFound()
{
Assert.Throws<InvalidOperationException>(() => ReflectionUtilities.EmitPropertyGetter<Class1, int>("Zalue1"));
Assert.Throws<InvalidOperationException>(() => ReflectionUtilities.EmitPropertyGetter<Class1, int>("Value2"));
var propertyInfo = typeof(Class1).GetProperty("Value1");
Assert.Throws<ArgumentException>(() => ReflectionUtilities.EmitPropertySetter<Class1, int>(propertyInfo));
}
[Test]
public void EmitPropertyThrowsIfInvalid()
{
Assert.Throws<ArgumentException>(() => ReflectionUtilities.EmitPropertyGetter<Class1, string>("Value1"));
}
[Test]
public void EmitPropertyReturnsNull()
{
Assert.IsNull(ReflectionUtilities.EmitPropertyGetter<Class1, int>("Zalue1", false));
Assert.IsNull(ReflectionUtilities.EmitPropertyGetter<Class1, int>("Value2", false));
}
[Test]
public void PropertySetterCanCastUnsafeValue()
{
// test that we can emit property setters that cast from eg 'object'
var type4 = typeof(Class4);
var propInt4 = type4.GetProperty("IntValue");
var propString4 = type4.GetProperty("StringValue");
var propClassA4 = type4.GetProperty("ClassAValue");
var object4 = new Class4();
var object2A = new Class2A();
// works with a string property
Assert.IsNotNull(propString4);
var setterString4 = ReflectionUtilities.EmitPropertySetterUnsafe<Class4, object>(propString4);
Assert.IsNotNull(setterString4);
setterString4(object4, "foo");
Assert.IsNotNull(object4.StringValue);
Assert.AreEqual("foo", object4.StringValue);
// unsafe is... unsafe
Assert.Throws<InvalidCastException>(() => setterString4(object4, new Class2()));
// works with a reference property
Assert.IsNotNull(propClassA4);
var setterClassA4 = ReflectionUtilities.EmitPropertySetterUnsafe<Class4, object>(propClassA4);
Assert.IsNotNull(setterClassA4);
setterClassA4(object4, object2A);
Assert.IsNotNull(object4.ClassAValue);
Assert.AreEqual(object2A, object4.ClassAValue);
// works with a boxed value type
Assert.IsNotNull(propInt4);
var setterInt4 = ReflectionUtilities.EmitPropertySetterUnsafe<Class4, object>(propInt4);
Assert.IsNotNull(setterInt4);
setterInt4(object4, 42);
Assert.AreEqual(42, object4.IntValue);
// FIXME: the code below runs fine with ReSharper test running within VisualStudio
// but it crashes when running via vstest.console.exe - unless some settings are required?
// converting works
setterInt4(object4, 42.0);
Assert.AreEqual(42, object4.IntValue);
// unsafe is... unsafe
Assert.Throws<FormatException>(() => setterInt4(object4, "foo"));
}
[Test]
public void PropertySetterCanCastObject()
{
// Class5 inherits from Class4 and ClassValue is defined on Class4
var type5 = typeof(Class5);
var propClass4 = type5.GetProperty("ClassValue");
var object2 = new Class2();
// can cast the object type from Class5 to Class4
var setterClass4 = ReflectionUtilities.EmitPropertySetter<Class5, Class2>(propClass4);
var object4 = new Class5();
setterClass4(object4, object2);
Assert.IsNotNull(object4.ClassValue);
Assert.AreSame(object2, object4.ClassValue);
}
[Test]
public void PropertySetterCanCastUnsafeObject()
{
var type5 = typeof(Class5);
var propClass4 = type5.GetProperty("ClassValue");
var object2 = new Class2();
// can cast the object type from object to Class4
var setterClass4 = ReflectionUtilities.EmitPropertySetterUnsafe<object, Class2>(propClass4);
var object4 = new Class5();
setterClass4(object4, object2);
Assert.IsNotNull(object4.ClassValue);
Assert.AreSame(object2, object4.ClassValue);
}
[Test]
public void PropertyGetterCanCastValue()
{
var type4 = typeof(Class4);
var propClassA4 = type4.GetProperty("ClassAValue");
var propInt4 = type4.GetProperty("IntValue");
var object2A = new Class2A();
var object4 = new Class4 { ClassAValue = object2A, IntValue = 159 };
// can cast the return type from Class2A to Class2
var getterClassA4 = ReflectionUtilities.EmitPropertyGetter<Class4, Class2>(propClassA4);
var valueClass4A = getterClassA4(object4);
Assert.IsNotNull(valueClass4A);
Assert.AreSame(object2A, valueClass4A);
// cannot cast the return type from Class2A to Class3!
Assert.Throws<ArgumentException>(()
=> ReflectionUtilities.EmitPropertyGetter<Class4, Class3>(propClassA4));
// can cast and box the return type from int to object
var getterInt4 = ReflectionUtilities.EmitPropertyGetter<Class4, object>(propInt4);
var valueInt4 = getterInt4(object4);
Assert.IsTrue(valueInt4 is int);
Assert.AreEqual(159, valueInt4);
// cannot cast the return type from int to Class3!
Assert.Throws<ArgumentException>(()
=> ReflectionUtilities.EmitPropertyGetter<Class4, Class3>(propInt4));
}
[Test]
public void PropertyGetterCanCastObject()
{
var type5 = typeof(Class5);
var propClass4 = type5.GetProperty("ClassValue");
var object2 = new Class2();
var object4 = new Class5 { ClassValue = object2 };
// can cast the object type from Class5 to Class4
var getterClass4 = ReflectionUtilities.EmitPropertyGetter<Class5, Class2>(propClass4);
var valueClass4 = getterClass4(object4);
Assert.IsNotNull(valueClass4);
Assert.AreSame(object2, valueClass4);
// cannot cast the object type from Class3 to Class4!
Assert.Throws<ArgumentException>(()
=> ReflectionUtilities.EmitPropertyGetter<Class3, Class2>(propClass4));
}
[Test]
public void EmitPropertyCastGetterEmits()
{
// test that we can emit property getters that cast the returned value to 'object'
// test simple class
var type4 = typeof(Class4);
var object4 = new Class4
{
IntValue = 1,
StringValue = "foo",
ClassValue = new Class2(),
};
// works with a string property
var propString4 = type4.GetProperty("StringValue");
Assert.IsNotNull(propString4);
var getterString4 = ReflectionUtilities.EmitPropertyGetter<Class4, object>(propString4);
Assert.IsNotNull(getterString4);
var valueString4 = getterString4(object4);
Assert.IsNotNull(valueString4);
Assert.AreEqual("foo", valueString4);
// works with a reference property
var propClass4 = type4.GetProperty("ClassValue");
Assert.IsNotNull(propClass4);
var getterClass4 = ReflectionUtilities.EmitPropertyGetter<Class4, object>(propClass4);
Assert.IsNotNull(getterClass4);
var valueClass4 = getterClass4(object4);
Assert.IsNotNull(valueClass4);
Assert.IsInstanceOf<Class2>(valueClass4);
// works with a value type property
var propInt4 = type4.GetProperty("IntValue");
Assert.IsNotNull(propInt4);
// ... if explicitly getting a value type
var getterInt4T = ReflectionUtilities.EmitPropertyGetter<Class4, int>(propInt4);
Assert.IsNotNull(getterInt4T);
var valueInt4T = getterInt4T(object4);
Assert.AreEqual(1, valueInt4T);
// ... if using a compiled getter
var valueInt4D = GetIntValue(object4);
Assert.IsNotNull(valueInt4D);
Assert.IsTrue(valueInt4D is int);
Assert.AreEqual(1, valueInt4D);
// ... if getting a non-value type (emit adds a box)
var getterInt4 = ReflectionUtilities.EmitPropertyGetter<Class4, object>(propInt4);
Assert.IsNotNull(getterInt4);
var valueInt4 = getterInt4(object4);
Assert.IsNotNull(valueInt4);
Assert.IsTrue(valueInt4 is int);
Assert.AreEqual(1, valueInt4);
var getters4 = type4
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
.ToDictionary(x => x.Name, x => (object) ReflectionUtilities.EmitPropertyGetter<Class4, object>(x));
Console.WriteLine("Getting object4 values...");
var values4 = getters4.ToDictionary(kvp => kvp.Key, kvp => ((Func<Class4, object>) kvp.Value)(object4));
Console.WriteLine("Writing object4 values...");
foreach ((var name, var value) in values4)
Console.WriteLine($"{name}: {value}");
Assert.AreEqual(4, values4.Count);
Assert.AreEqual("foo", values4["StringValue"]);
Assert.IsInstanceOf<Class2>(values4["ClassValue"]);
Assert.AreEqual(1, values4["IntValue"]);
// test hierarchy
var type5 = typeof(Class5);
var getters5 = type5
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy)
.ToDictionary(x => x.Name, x => (object) ReflectionUtilities.EmitPropertyGetter<Class5, object>(x));
var object5 = new Class5
{
IntValue = 1,
IntValue2 = 1,
StringValue = "foo",
StringValue2 = "foo",
ClassValue = new Class2(),
ClassValue2 = new Class2()
};
Console.WriteLine("Getting object5 values...");
var values5 = getters5.ToDictionary(kvp => kvp.Key, kvp => ((Func<Class5, object>) kvp.Value)(object5));
Console.WriteLine("Writing object5 values...");
foreach ((var name, var value) in values5)
Console.WriteLine($"{name}: {value}");
Assert.AreEqual(7, values5.Count);
Assert.AreEqual("foo", values5["StringValue"]);
Assert.IsInstanceOf<Class2>(values5["ClassValue"]);
Assert.AreEqual(1, values5["IntValue"]);
Assert.AreEqual("foo", values5["StringValue2"]);
Assert.IsInstanceOf<Class2>(values5["ClassValue2"]);
Assert.AreEqual(1, values5["IntValue2"]);
// test object extensions
Console.WriteLine("Getting object5D values...");
var values5D = ObjectJsonExtensions.ToObjectDictionary(object5);
Console.WriteLine("Writing object5D values...");
foreach ((var name, var value) in values5)
Console.WriteLine($"{name}: {value}");
Assert.AreEqual(7, values5.Count);
Assert.AreEqual("foo", values5D["StringValue"]);
Assert.IsInstanceOf<Class2>(values5D["ClassValue"]);
Assert.AreEqual(1, values5D["IntValue"]);
Assert.AreEqual("foo", values5D["StringValue2"]);
Assert.IsInstanceOf<Class2>(values5D["ClassValue2"]);
Assert.AreEqual(1, values5D["intValue2"]); // JsonProperty changes property name
}
[Test]
public void EmitFieldGetterSetterEmits()
{
var getter1 = ReflectionUtilities.EmitFieldGetter<Class1, int>("Field1");
var getter2 = ReflectionUtilities.EmitFieldGetter<Class1, int>("Field2");
var c = new Class1();
Assert.AreEqual(33, getter1(c));
Assert.AreEqual(66, getter2(c));
var setter2 = ReflectionUtilities.EmitFieldSetter<Class1, int>("Field2");
setter2(c, 99);
Assert.AreEqual(99, getter2(c));
// works on readonly fields!
var (getter3, setter3) = ReflectionUtilities.EmitFieldGetterAndSetter<Class1, int>("Field3");
Assert.AreEqual(22, getter3(c));
setter3(c, 44);
Assert.AreEqual(44, getter3(c));
}
// FIXME: missing tests specifying 'returned' on method, property
[Test]
public void DeconstructAnonymousType()
{
var o = new { a = 1, b = "hello" };
var getters = new Dictionary<string, Func<object, object>>();
foreach (var prop in o.GetType().GetProperties())
getters[prop.Name] = ReflectionUtilities.EmitMethodUnsafe<Func<object, object>>(prop.GetMethod);
Assert.AreEqual(2, getters.Count);
Assert.IsTrue(getters.ContainsKey("a"));
Assert.IsTrue(getters.ContainsKey("b"));
Assert.AreEqual(1, getters["a"](o));
Assert.AreEqual("hello", getters["b"](o));
}
#region IL Code
// these functions can be examined in eg DotPeek to understand IL works
// box [mscorlib]System.Int32
public object GetIntValue(Class4 object4) => object4.IntValue;
// unbox.any [mscorlib]System.Int32
public void SetIntValue(Class4 object4, object i) => object4.IntValue = (int) i;
// castclass [mscorlib]System.String
public void SetStringValue(Class4 object4, object s) => object4.StringValue = (string) s;
// conv.i4
public void SetIntValue(Class4 object4, double d) => object4.IntValue = (int) d;
// unbox.any [mscorlib]System.Double
// conv.i4
public void SetIntValue2(Class4 object4, object d) => object4.IntValue = (int) (double) d;
public void SetIntValue3(Class4 object4, object v)
{
if (v is int i)
object4.IntValue = i;
else
object4.IntValue = Convert.ToInt32(v);
}
public void SetIntValue4(Class4 object4, object v)
{
if (v is int i)
object4.IntValue = i;
else
object4.IntValue = (int) Convert.ChangeType(v, typeof(int));
}
// get field
public int GetIntField(Class1 object1) => object1.Field1;
// set field
public void SetIntField(Class1 object1, int i) => object1.Field1 = i;
#endregion
#region Test Objects
public static class StaticClass1
{
public static void Method() { }
}
public class Class1
{
public Class1() { }
public Class1(int i) { }
public void Method1() { }
public void Method2(int i) { }
public int Method3() => 42;
public int Method4(string s) => int.Parse(s);
public string Method5() => "foo";
public static void SMethod1() { }
public static void SMethod2(int i) { }
public static int SMethod3() => 42;
public static int SMethod4(string s) => int.Parse(s);
private void MethodP1() { }
private static void SMethodP1() { }
public int Value1 => 42;
public int Value2 { set { } }
public int Value3 { get { return 42; } set { } }
private int ValueP1 => 42;
public int Field1 = 33;
private int Field2 = 66;
public readonly int Field3 = 22;
}
public class Class2 { }
public class Class2A : Class2 { }
public class Class3
{
public Class3(int i) { }
private Class3(string s) { }
}
public class Class4
{
public int IntValue { get; set; }
public string StringValue { get; set; }
public Class2 ClassValue { get;set; }
public Class2A ClassAValue { get; set; }
}
public class Class5 : Class4
{
[JsonProperty("intValue2")]
public int IntValue2 { get; set; }
public string StringValue2 { get; set; }
public Class2 ClassValue2 { get;set; }
}
#endregion
}
}

View File

@@ -0,0 +1,30 @@
using System;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
[TestFixture]
public class VersionExtensionTests
{
[TestCase(1, 0, 0, 0, "0.2147483647.2147483647.2147483647")]
[TestCase(1, 1, 0, 0, "1.0.2147483647.2147483647")]
[TestCase(1, 1, 1, 0, "1.1.0.2147483647")]
[TestCase(1, 1, 1, 1, "1.1.1.0")]
[TestCase(0, 1, 0, 0, "0.0.2147483647.2147483647")]
[TestCase(0, 1, 1, 0, "0.1.0.2147483647")]
[TestCase(0, 1, 1, 1, "0.1.1.0")]
[TestCase(0, 0, 1, 0, "0.0.0.2147483647")]
[TestCase(0, 0, 1, 1, "0.0.1.0")]
[TestCase(0, 0, 0, 1, "0.0.0.0")]
[TestCase(7, 3, 0, 0, "7.2.2147483647.2147483647")]
public void Subtract_Revision(int major, int minor, int build, int rev, string outcome)
{
var version = new Version(major, minor, build, rev);
var result = version.SubtractRevision();
Assert.AreEqual(new Version(outcome), result);
}
}
}

View File

@@ -0,0 +1,48 @@
using System.Xml;
using System.Xml.Linq;
using NUnit.Framework;
using Umbraco.Core;
namespace Umbraco.Tests.UnitTests.Umbraco.Core
{
[TestFixture]
public class XmlExtensionsTests
{
[Test]
public void XCDataToXmlNode()
{
var cdata = new XElement("test", new XCData("hello world"));
var xdoc = new XmlDocument();
var xmlNode = cdata.GetXmlNode(xdoc);
Assert.AreEqual("hello world", xmlNode.InnerText);
}
[Test]
public void XTextToXmlNode()
{
var cdata = new XElement("test", new XText("hello world"));
var xdoc = new XmlDocument();
var xmlNode = cdata.GetXmlNode(xdoc);
Assert.AreEqual("hello world", xmlNode.InnerText);
}
[Test]
public void ToXmlNodeIsNonDestructive()
{
const string xml = "<root><foo attr=\"123\">hello</foo><bar>world</bar></root>";
var cdata = new XElement("test", new XText("hello world"));
var xdoc = new XmlDocument();
xdoc.LoadXml(xml);
var xmlNode = cdata.GetXmlNode(xdoc);
Assert.AreEqual("hello world", xmlNode.InnerText);
Assert.AreEqual(xml, xdoc.OuterXml);
}
}
}

View File

@@ -15,6 +15,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Lucene.Net.Contrib" Version="3.0.3" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />