mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 23:52:50 -05:00
Turn on file scoped namespaces (#2225)
This commit is contained in:
@ -2,36 +2,35 @@
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Utilities
|
||||
namespace Bit.Core.Test.Utilities;
|
||||
|
||||
public class ClaimsExtensionsTests
|
||||
{
|
||||
public class ClaimsExtensionsTests
|
||||
[Fact]
|
||||
public void HasSSOIdP_Returns_True_When_The_Claims_Has_One_Of_Type_IdP_And_Value_Sso()
|
||||
{
|
||||
[Fact]
|
||||
public void HasSSOIdP_Returns_True_When_The_Claims_Has_One_Of_Type_IdP_And_Value_Sso()
|
||||
{
|
||||
var claims = new List<Claim> { new Claim("idp", "sso") };
|
||||
Assert.True(claims.HasSsoIdP());
|
||||
}
|
||||
var claims = new List<Claim> { new Claim("idp", "sso") };
|
||||
Assert.True(claims.HasSsoIdP());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasSSOIdP_Returns_False_When_The_Claims_Has_One_Of_Type_IdP_And_Value_Is_Not_Sso()
|
||||
{
|
||||
var claims = new List<Claim> { new Claim("idp", "asdfasfd") };
|
||||
Assert.False(claims.HasSsoIdP());
|
||||
}
|
||||
[Fact]
|
||||
public void HasSSOIdP_Returns_False_When_The_Claims_Has_One_Of_Type_IdP_And_Value_Is_Not_Sso()
|
||||
{
|
||||
var claims = new List<Claim> { new Claim("idp", "asdfasfd") };
|
||||
Assert.False(claims.HasSsoIdP());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasSSOIdP_Returns_False_When_The_Claims_Has_No_One_Of_Type_IdP()
|
||||
{
|
||||
var claims = new List<Claim> { new Claim("qweqweq", "sso") };
|
||||
Assert.False(claims.HasSsoIdP());
|
||||
}
|
||||
[Fact]
|
||||
public void HasSSOIdP_Returns_False_When_The_Claims_Has_No_One_Of_Type_IdP()
|
||||
{
|
||||
var claims = new List<Claim> { new Claim("qweqweq", "sso") };
|
||||
Assert.False(claims.HasSsoIdP());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void HasSSOIdP_Returns_False_When_The_Claims_Are_Empty()
|
||||
{
|
||||
var claims = new List<Claim>();
|
||||
Assert.False(claims.HasSsoIdP());
|
||||
}
|
||||
[Fact]
|
||||
public void HasSSOIdP_Returns_False_When_The_Claims_Are_Empty()
|
||||
{
|
||||
var claims = new List<Claim>();
|
||||
Assert.False(claims.HasSsoIdP());
|
||||
}
|
||||
}
|
||||
|
@ -12,434 +12,433 @@ using IdentityModel;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Utilities
|
||||
namespace Bit.Core.Test.Utilities;
|
||||
|
||||
public class CoreHelpersTests
|
||||
{
|
||||
public class CoreHelpersTests
|
||||
public static IEnumerable<object[]> _epochTestCases = new[]
|
||||
{
|
||||
public static IEnumerable<object[]> _epochTestCases = new[]
|
||||
{
|
||||
new object[] {new DateTime(2020, 12, 30, 11, 49, 12, DateTimeKind.Utc), 1609328952000L},
|
||||
};
|
||||
new object[] {new DateTime(2020, 12, 30, 11, 49, 12, DateTimeKind.Utc), 1609328952000L},
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public void GenerateComb_Success()
|
||||
{
|
||||
// Arrange & Act
|
||||
var comb = CoreHelpers.GenerateComb();
|
||||
[Fact]
|
||||
public void GenerateComb_Success()
|
||||
{
|
||||
// Arrange & Act
|
||||
var comb = CoreHelpers.GenerateComb();
|
||||
|
||||
// Assert
|
||||
Assert.NotEqual(Guid.Empty, comb);
|
||||
// TODO: Add more asserts to make sure important aspects of
|
||||
// the comb are working properly
|
||||
// Assert
|
||||
Assert.NotEqual(Guid.Empty, comb);
|
||||
// TODO: Add more asserts to make sure important aspects of
|
||||
// the comb are working properly
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GenerateCombCases = new[]
|
||||
{
|
||||
new object[]
|
||||
{
|
||||
Guid.Parse("a58db474-43d8-42f1-b4ee-0c17647cd0c0"), // Input Guid
|
||||
new DateTime(2022, 3, 12, 12, 12, 0, DateTimeKind.Utc), // Input Time
|
||||
Guid.Parse("a58db474-43d8-42f1-b4ee-ae5600c90cc1"), // Expected Comb
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
Guid.Parse("f776e6ee-511f-4352-bb28-88513002bdeb"),
|
||||
new DateTime(2021, 5, 10, 10, 52, 0, DateTimeKind.Utc),
|
||||
Guid.Parse("f776e6ee-511f-4352-bb28-ad2400b313c1"),
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
Guid.Parse("51a25fc7-3cad-497d-8e2f-8d77011648a1"),
|
||||
new DateTime(1999, 2, 26, 16, 53, 13, DateTimeKind.Utc),
|
||||
Guid.Parse("51a25fc7-3cad-497d-8e2f-8d77011649cd"),
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
Guid.Parse("bfb8f353-3b32-4a9e-bef6-24fe0b54bfb0"),
|
||||
new DateTime(2024, 10, 20, 1, 32, 16, DateTimeKind.Utc),
|
||||
Guid.Parse("bfb8f353-3b32-4a9e-bef6-b20f00195780"),
|
||||
}
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateCombCases))]
|
||||
public void GenerateComb_WithInputs_Success(Guid inputGuid, DateTime inputTime, Guid expectedComb)
|
||||
{
|
||||
var comb = CoreHelpers.GenerateComb(inputGuid, inputTime);
|
||||
|
||||
Assert.Equal(expectedComb, comb);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(2, 5, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 })]
|
||||
[InlineData(2, 3, new[] { 1, 2, 3, 4, 5 })]
|
||||
[InlineData(2, 1, new[] { 1, 2 })]
|
||||
[InlineData(1, 1, new[] { 1 })]
|
||||
[InlineData(2, 2, new[] { 1, 2, 3 })]
|
||||
public void Batch_Success(int batchSize, int totalBatches, int[] collection)
|
||||
{
|
||||
// Arrange
|
||||
var remainder = collection.Length % batchSize;
|
||||
|
||||
// Act
|
||||
var batches = collection.Batch(batchSize);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(totalBatches, batches.Count());
|
||||
|
||||
foreach (var batch in batches.Take(totalBatches - 1))
|
||||
{
|
||||
Assert.Equal(batchSize, batch.Count());
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GenerateCombCases = new[]
|
||||
{
|
||||
new object[]
|
||||
Assert.Equal(batches.Last().Count(), remainder == 0 ? batchSize : remainder);
|
||||
}
|
||||
|
||||
/*
|
||||
[Fact]
|
||||
public void ToGuidIdArrayTVP_Success()
|
||||
{
|
||||
// Arrange
|
||||
var item0 = Guid.NewGuid();
|
||||
var item1 = Guid.NewGuid();
|
||||
|
||||
var ids = new[] { item0, item1 };
|
||||
|
||||
// Act
|
||||
var dt = ids.ToGuidIdArrayTVP();
|
||||
|
||||
// Assert
|
||||
Assert.Single(dt.Columns);
|
||||
Assert.Equal("GuidId", dt.Columns[0].ColumnName);
|
||||
Assert.Equal(2, dt.Rows.Count);
|
||||
Assert.Equal(item0, dt.Rows[0][0]);
|
||||
Assert.Equal(item1, dt.Rows[1][0]);
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: Test the other ToArrayTVP Methods
|
||||
|
||||
[Theory]
|
||||
[InlineData("12345&6789", "123456789")]
|
||||
[InlineData("abcdef", "ABCDEF")]
|
||||
[InlineData("1!@#$%&*()_+", "1")]
|
||||
[InlineData("\u00C6123abc\u00C7", "123ABC")]
|
||||
[InlineData("123\u00C6ABC", "123ABC")]
|
||||
[InlineData("\r\nHello", "E")]
|
||||
[InlineData("\tdef", "DEF")]
|
||||
[InlineData("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV1234567890", "ABCDEFABCDEF1234567890")]
|
||||
public void CleanCertificateThumbprint_Success(string input, string output)
|
||||
{
|
||||
// Arrange & Act
|
||||
var sanitizedInput = CoreHelpers.CleanCertificateThumbprint(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(output, sanitizedInput);
|
||||
}
|
||||
|
||||
// TODO: Add more tests
|
||||
[Theory]
|
||||
[MemberData(nameof(_epochTestCases))]
|
||||
public void ToEpocMilliseconds_Success(DateTime date, long milliseconds)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Equal(milliseconds, CoreHelpers.ToEpocMilliseconds(date));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(_epochTestCases))]
|
||||
public void FromEpocMilliseconds(DateTime date, long milliseconds)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Equal(date, CoreHelpers.FromEpocMilliseconds(milliseconds));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SecureRandomString_Success()
|
||||
{
|
||||
// Arrange & Act
|
||||
var @string = CoreHelpers.SecureRandomString(8);
|
||||
|
||||
// Assert
|
||||
// TODO: Should probably add more Asserts down the line
|
||||
Assert.Equal(8, @string.Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1, "1 Bytes")]
|
||||
[InlineData(-5L, "-5 Bytes")]
|
||||
[InlineData(1023L, "1023 Bytes")]
|
||||
[InlineData(1024L, "1 KB")]
|
||||
[InlineData(1025L, "1 KB")]
|
||||
[InlineData(-1023L, "-1023 Bytes")]
|
||||
[InlineData(-1024L, "-1 KB")]
|
||||
[InlineData(-1025L, "-1 KB")]
|
||||
[InlineData(1048575L, "1024 KB")]
|
||||
[InlineData(1048576L, "1 MB")]
|
||||
[InlineData(1048577L, "1 MB")]
|
||||
[InlineData(-1048575L, "-1024 KB")]
|
||||
[InlineData(-1048576L, "-1 MB")]
|
||||
[InlineData(-1048577L, "-1 MB")]
|
||||
[InlineData(1073741823L, "1024 MB")]
|
||||
[InlineData(1073741824L, "1 GB")]
|
||||
[InlineData(1073741825L, "1 GB")]
|
||||
[InlineData(-1073741823L, "-1024 MB")]
|
||||
[InlineData(-1073741824L, "-1 GB")]
|
||||
[InlineData(-1073741825L, "-1 GB")]
|
||||
[InlineData(long.MaxValue, "8589934592 GB")]
|
||||
public void ReadableBytesSize_Success(long size, string readable)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Equal(readable, CoreHelpers.ReadableBytesSize(size));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloneObject_Success()
|
||||
{
|
||||
var original = new { Message = "Message" };
|
||||
|
||||
var copy = CoreHelpers.CloneObject(original);
|
||||
|
||||
Assert.Equal(original.Message, copy.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendQuery_AddNewParameter_Success()
|
||||
{
|
||||
// Arrange
|
||||
var uri = new Uri("https://bitwarden.com/?param1=value1");
|
||||
|
||||
// Act
|
||||
var newUri = CoreHelpers.ExtendQuery(uri,
|
||||
new Dictionary<string, string> { { "param2", "value2" } });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("https://bitwarden.com/?param1=value1¶m2=value2", newUri.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendQuery_AddTwoNewParameters_Success()
|
||||
{
|
||||
// Arrange
|
||||
var uri = new Uri("https://bitwarden.com/?param1=value1");
|
||||
|
||||
// Act
|
||||
var newUri = CoreHelpers.ExtendQuery(uri,
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
Guid.Parse("a58db474-43d8-42f1-b4ee-0c17647cd0c0"), // Input Guid
|
||||
new DateTime(2022, 3, 12, 12, 12, 0, DateTimeKind.Utc), // Input Time
|
||||
Guid.Parse("a58db474-43d8-42f1-b4ee-ae5600c90cc1"), // Expected Comb
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
Guid.Parse("f776e6ee-511f-4352-bb28-88513002bdeb"),
|
||||
new DateTime(2021, 5, 10, 10, 52, 0, DateTimeKind.Utc),
|
||||
Guid.Parse("f776e6ee-511f-4352-bb28-ad2400b313c1"),
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
Guid.Parse("51a25fc7-3cad-497d-8e2f-8d77011648a1"),
|
||||
new DateTime(1999, 2, 26, 16, 53, 13, DateTimeKind.Utc),
|
||||
Guid.Parse("51a25fc7-3cad-497d-8e2f-8d77011649cd"),
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
Guid.Parse("bfb8f353-3b32-4a9e-bef6-24fe0b54bfb0"),
|
||||
new DateTime(2024, 10, 20, 1, 32, 16, DateTimeKind.Utc),
|
||||
Guid.Parse("bfb8f353-3b32-4a9e-bef6-b20f00195780"),
|
||||
}
|
||||
};
|
||||
{ "param2", "value2" },
|
||||
{ "param3", "value3" }
|
||||
});
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GenerateCombCases))]
|
||||
public void GenerateComb_WithInputs_Success(Guid inputGuid, DateTime inputTime, Guid expectedComb)
|
||||
// Assert
|
||||
Assert.Equal("https://bitwarden.com/?param1=value1¶m2=value2¶m3=value3", newUri.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendQuery_AddExistingParameter_Success()
|
||||
{
|
||||
// Arrange
|
||||
var uri = new Uri("https://bitwarden.com/?param1=value1¶m2=value2");
|
||||
|
||||
// Act
|
||||
var newUri = CoreHelpers.ExtendQuery(uri,
|
||||
new Dictionary<string, string> { { "param1", "test_value" } });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("https://bitwarden.com/?param1=test_value¶m2=value2", newUri.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendQuery_AddNoParameters_Success()
|
||||
{
|
||||
// Arrange
|
||||
const string startingUri = "https://bitwarden.com/?param1=value1";
|
||||
|
||||
var uri = new Uri(startingUri);
|
||||
|
||||
// Act
|
||||
var newUri = CoreHelpers.ExtendQuery(uri, new Dictionary<string, string>());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(startingUri, newUri.ToString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("bücher.com", "xn--bcher-kva.com")]
|
||||
[InlineData("bücher.cömé", "xn--bcher-kva.xn--cm-cja4c")]
|
||||
[InlineData("hello@bücher.com", "hello@xn--bcher-kva.com")]
|
||||
[InlineData("hello@world.cömé", "hello@world.xn--cm-cja4c")]
|
||||
[InlineData("hello@bücher.cömé", "hello@xn--bcher-kva.xn--cm-cja4c")]
|
||||
[InlineData("ascii.com", "ascii.com")]
|
||||
[InlineData("", "")]
|
||||
[InlineData(null, null)]
|
||||
public void PunyEncode_Success(string text, string expected)
|
||||
{
|
||||
var actual = CoreHelpers.PunyEncode(text);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetEmbeddedResourceContentsAsync_Success()
|
||||
{
|
||||
var fileContents = CoreHelpers.GetEmbeddedResourceContentsAsync("data.embeddedResource.txt");
|
||||
Assert.Equal("Contents of embeddedResource.txt\n", fileContents.Replace("\r\n", "\n"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(UserFixture))]
|
||||
public void BuildIdentityClaims_BaseClaims_Success(User user, bool isPremium)
|
||||
{
|
||||
var expected = new Dictionary<string, string>
|
||||
{
|
||||
var comb = CoreHelpers.GenerateComb(inputGuid, inputTime);
|
||||
{ "premium", isPremium ? "true" : "false" },
|
||||
{ JwtClaimTypes.Email, user.Email },
|
||||
{ JwtClaimTypes.EmailVerified, user.EmailVerified ? "true" : "false" },
|
||||
{ JwtClaimTypes.Name, user.Name },
|
||||
{ "sstamp", user.SecurityStamp },
|
||||
}.ToList();
|
||||
|
||||
Assert.Equal(expectedComb, comb);
|
||||
var actual = CoreHelpers.BuildIdentityClaims(user, Array.Empty<CurrentContentOrganization>(),
|
||||
Array.Empty<CurrentContentProvider>(), isPremium);
|
||||
|
||||
foreach (var claim in expected)
|
||||
{
|
||||
Assert.Contains(claim, actual);
|
||||
}
|
||||
Assert.Equal(expected.Count, actual.Count);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(2, 5, new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 })]
|
||||
[InlineData(2, 3, new[] { 1, 2, 3, 4, 5 })]
|
||||
[InlineData(2, 1, new[] { 1, 2 })]
|
||||
[InlineData(1, 1, new[] { 1 })]
|
||||
[InlineData(2, 2, new[] { 1, 2, 3 })]
|
||||
public void Batch_Success(int batchSize, int totalBatches, int[] collection)
|
||||
[Theory, CustomAutoData(typeof(UserFixture))]
|
||||
public void BuildIdentityClaims_NonCustomOrganizationUserType_Success(User user)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
foreach (var organizationUserType in Enum.GetValues<OrganizationUserType>().Except(new[] { OrganizationUserType.Custom }))
|
||||
{
|
||||
// Arrange
|
||||
var remainder = collection.Length % batchSize;
|
||||
|
||||
// Act
|
||||
var batches = collection.Batch(batchSize);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(totalBatches, batches.Count());
|
||||
|
||||
foreach (var batch in batches.Take(totalBatches - 1))
|
||||
{
|
||||
Assert.Equal(batchSize, batch.Count());
|
||||
}
|
||||
|
||||
Assert.Equal(batches.Last().Count(), remainder == 0 ? batchSize : remainder);
|
||||
}
|
||||
|
||||
/*
|
||||
[Fact]
|
||||
public void ToGuidIdArrayTVP_Success()
|
||||
{
|
||||
// Arrange
|
||||
var item0 = Guid.NewGuid();
|
||||
var item1 = Guid.NewGuid();
|
||||
|
||||
var ids = new[] { item0, item1 };
|
||||
|
||||
// Act
|
||||
var dt = ids.ToGuidIdArrayTVP();
|
||||
|
||||
// Assert
|
||||
Assert.Single(dt.Columns);
|
||||
Assert.Equal("GuidId", dt.Columns[0].ColumnName);
|
||||
Assert.Equal(2, dt.Rows.Count);
|
||||
Assert.Equal(item0, dt.Rows[0][0]);
|
||||
Assert.Equal(item1, dt.Rows[1][0]);
|
||||
}
|
||||
*/
|
||||
|
||||
// TODO: Test the other ToArrayTVP Methods
|
||||
|
||||
[Theory]
|
||||
[InlineData("12345&6789", "123456789")]
|
||||
[InlineData("abcdef", "ABCDEF")]
|
||||
[InlineData("1!@#$%&*()_+", "1")]
|
||||
[InlineData("\u00C6123abc\u00C7", "123ABC")]
|
||||
[InlineData("123\u00C6ABC", "123ABC")]
|
||||
[InlineData("\r\nHello", "E")]
|
||||
[InlineData("\tdef", "DEF")]
|
||||
[InlineData("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV1234567890", "ABCDEFABCDEF1234567890")]
|
||||
public void CleanCertificateThumbprint_Success(string input, string output)
|
||||
{
|
||||
// Arrange & Act
|
||||
var sanitizedInput = CoreHelpers.CleanCertificateThumbprint(input);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(output, sanitizedInput);
|
||||
}
|
||||
|
||||
// TODO: Add more tests
|
||||
[Theory]
|
||||
[MemberData(nameof(_epochTestCases))]
|
||||
public void ToEpocMilliseconds_Success(DateTime date, long milliseconds)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Equal(milliseconds, CoreHelpers.ToEpocMilliseconds(date));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(_epochTestCases))]
|
||||
public void FromEpocMilliseconds(DateTime date, long milliseconds)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Equal(date, CoreHelpers.FromEpocMilliseconds(milliseconds));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SecureRandomString_Success()
|
||||
{
|
||||
// Arrange & Act
|
||||
var @string = CoreHelpers.SecureRandomString(8);
|
||||
|
||||
// Assert
|
||||
// TODO: Should probably add more Asserts down the line
|
||||
Assert.Equal(8, @string.Length);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(1, "1 Bytes")]
|
||||
[InlineData(-5L, "-5 Bytes")]
|
||||
[InlineData(1023L, "1023 Bytes")]
|
||||
[InlineData(1024L, "1 KB")]
|
||||
[InlineData(1025L, "1 KB")]
|
||||
[InlineData(-1023L, "-1023 Bytes")]
|
||||
[InlineData(-1024L, "-1 KB")]
|
||||
[InlineData(-1025L, "-1 KB")]
|
||||
[InlineData(1048575L, "1024 KB")]
|
||||
[InlineData(1048576L, "1 MB")]
|
||||
[InlineData(1048577L, "1 MB")]
|
||||
[InlineData(-1048575L, "-1024 KB")]
|
||||
[InlineData(-1048576L, "-1 MB")]
|
||||
[InlineData(-1048577L, "-1 MB")]
|
||||
[InlineData(1073741823L, "1024 MB")]
|
||||
[InlineData(1073741824L, "1 GB")]
|
||||
[InlineData(1073741825L, "1 GB")]
|
||||
[InlineData(-1073741823L, "-1024 MB")]
|
||||
[InlineData(-1073741824L, "-1 GB")]
|
||||
[InlineData(-1073741825L, "-1 GB")]
|
||||
[InlineData(long.MaxValue, "8589934592 GB")]
|
||||
public void ReadableBytesSize_Success(long size, string readable)
|
||||
{
|
||||
// Act & Assert
|
||||
Assert.Equal(readable, CoreHelpers.ReadableBytesSize(size));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CloneObject_Success()
|
||||
{
|
||||
var original = new { Message = "Message" };
|
||||
|
||||
var copy = CoreHelpers.CloneObject(original);
|
||||
|
||||
Assert.Equal(original.Message, copy.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendQuery_AddNewParameter_Success()
|
||||
{
|
||||
// Arrange
|
||||
var uri = new Uri("https://bitwarden.com/?param1=value1");
|
||||
|
||||
// Act
|
||||
var newUri = CoreHelpers.ExtendQuery(uri,
|
||||
new Dictionary<string, string> { { "param2", "value2" } });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("https://bitwarden.com/?param1=value1¶m2=value2", newUri.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendQuery_AddTwoNewParameters_Success()
|
||||
{
|
||||
// Arrange
|
||||
var uri = new Uri("https://bitwarden.com/?param1=value1");
|
||||
|
||||
// Act
|
||||
var newUri = CoreHelpers.ExtendQuery(uri,
|
||||
new Dictionary<string, string>
|
||||
{
|
||||
{ "param2", "value2" },
|
||||
{ "param3", "value3" }
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.Equal("https://bitwarden.com/?param1=value1¶m2=value2¶m3=value3", newUri.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendQuery_AddExistingParameter_Success()
|
||||
{
|
||||
// Arrange
|
||||
var uri = new Uri("https://bitwarden.com/?param1=value1¶m2=value2");
|
||||
|
||||
// Act
|
||||
var newUri = CoreHelpers.ExtendQuery(uri,
|
||||
new Dictionary<string, string> { { "param1", "test_value" } });
|
||||
|
||||
// Assert
|
||||
Assert.Equal("https://bitwarden.com/?param1=test_value¶m2=value2", newUri.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ExtendQuery_AddNoParameters_Success()
|
||||
{
|
||||
// Arrange
|
||||
const string startingUri = "https://bitwarden.com/?param1=value1";
|
||||
|
||||
var uri = new Uri(startingUri);
|
||||
|
||||
// Act
|
||||
var newUri = CoreHelpers.ExtendQuery(uri, new Dictionary<string, string>());
|
||||
|
||||
// Assert
|
||||
Assert.Equal(startingUri, newUri.ToString());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("bücher.com", "xn--bcher-kva.com")]
|
||||
[InlineData("bücher.cömé", "xn--bcher-kva.xn--cm-cja4c")]
|
||||
[InlineData("hello@bücher.com", "hello@xn--bcher-kva.com")]
|
||||
[InlineData("hello@world.cömé", "hello@world.xn--cm-cja4c")]
|
||||
[InlineData("hello@bücher.cömé", "hello@xn--bcher-kva.xn--cm-cja4c")]
|
||||
[InlineData("ascii.com", "ascii.com")]
|
||||
[InlineData("", "")]
|
||||
[InlineData(null, null)]
|
||||
public void PunyEncode_Success(string text, string expected)
|
||||
{
|
||||
var actual = CoreHelpers.PunyEncode(text);
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetEmbeddedResourceContentsAsync_Success()
|
||||
{
|
||||
var fileContents = CoreHelpers.GetEmbeddedResourceContentsAsync("data.embeddedResource.txt");
|
||||
Assert.Equal("Contents of embeddedResource.txt\n", fileContents.Replace("\r\n", "\n"));
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(UserFixture))]
|
||||
public void BuildIdentityClaims_BaseClaims_Success(User user, bool isPremium)
|
||||
{
|
||||
var expected = new Dictionary<string, string>
|
||||
{
|
||||
{ "premium", isPremium ? "true" : "false" },
|
||||
{ JwtClaimTypes.Email, user.Email },
|
||||
{ JwtClaimTypes.EmailVerified, user.EmailVerified ? "true" : "false" },
|
||||
{ JwtClaimTypes.Name, user.Name },
|
||||
{ "sstamp", user.SecurityStamp },
|
||||
}.ToList();
|
||||
|
||||
var actual = CoreHelpers.BuildIdentityClaims(user, Array.Empty<CurrentContentOrganization>(),
|
||||
Array.Empty<CurrentContentProvider>(), isPremium);
|
||||
|
||||
foreach (var claim in expected)
|
||||
{
|
||||
Assert.Contains(claim, actual);
|
||||
}
|
||||
Assert.Equal(expected.Count, actual.Count);
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(UserFixture))]
|
||||
public void BuildIdentityClaims_NonCustomOrganizationUserType_Success(User user)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
foreach (var organizationUserType in Enum.GetValues<OrganizationUserType>().Except(new[] { OrganizationUserType.Custom }))
|
||||
{
|
||||
var org = fixture.Create<CurrentContentOrganization>();
|
||||
org.Type = organizationUserType;
|
||||
|
||||
var expected = new KeyValuePair<string, string>($"org{organizationUserType.ToString().ToLower()}", org.Id.ToString());
|
||||
var actual = CoreHelpers.BuildIdentityClaims(user, new[] { org }, Array.Empty<CurrentContentProvider>(), false);
|
||||
|
||||
Assert.Contains(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(UserFixture))]
|
||||
public void BuildIdentityClaims_CustomOrganizationUserClaims_Success(User user, CurrentContentOrganization org)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
org.Type = OrganizationUserType.Custom;
|
||||
var org = fixture.Create<CurrentContentOrganization>();
|
||||
org.Type = organizationUserType;
|
||||
|
||||
var expected = new KeyValuePair<string, string>($"org{organizationUserType.ToString().ToLower()}", org.Id.ToString());
|
||||
var actual = CoreHelpers.BuildIdentityClaims(user, new[] { org }, Array.Empty<CurrentContentProvider>(), false);
|
||||
foreach (var (permitted, claimName) in org.Permissions.ClaimsMap)
|
||||
{
|
||||
var claim = new KeyValuePair<string, string>(claimName, org.Id.ToString());
|
||||
if (permitted)
|
||||
{
|
||||
|
||||
Assert.Contains(claim, actual);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.DoesNotContain(claim, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(UserFixture))]
|
||||
public void BuildIdentityClaims_ProviderClaims_Success(User user)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
var providers = new List<CurrentContentProvider>();
|
||||
foreach (var providerUserType in Enum.GetValues<ProviderUserType>())
|
||||
{
|
||||
var provider = fixture.Create<CurrentContentProvider>();
|
||||
provider.Type = providerUserType;
|
||||
providers.Add(provider);
|
||||
}
|
||||
|
||||
var claims = new List<KeyValuePair<string, string>>();
|
||||
|
||||
if (providers.Any())
|
||||
{
|
||||
foreach (var group in providers.GroupBy(o => o.Type))
|
||||
{
|
||||
switch (group.Key)
|
||||
{
|
||||
case ProviderUserType.ProviderAdmin:
|
||||
foreach (var provider in group)
|
||||
{
|
||||
claims.Add(new KeyValuePair<string, string>("providerprovideradmin", provider.Id.ToString()));
|
||||
}
|
||||
break;
|
||||
case ProviderUserType.ServiceUser:
|
||||
foreach (var provider in group)
|
||||
{
|
||||
claims.Add(new KeyValuePair<string, string>("providerserviceuser", provider.Id.ToString()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var actual = CoreHelpers.BuildIdentityClaims(user, Array.Empty<CurrentContentOrganization>(), providers, false);
|
||||
foreach (var claim in claims)
|
||||
{
|
||||
Assert.Contains(claim, actual);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TokenIsValidData()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new object[]
|
||||
{
|
||||
"first_part 476669d4-9642-4af8-9b29-9366efad4ed3 test@email.com {0}", // unprotectedTokenTemplate
|
||||
"first_part", // firstPart
|
||||
"test@email.com", // email
|
||||
Guid.Parse("476669d4-9642-4af8-9b29-9366efad4ed3"), // id
|
||||
DateTime.UtcNow.AddHours(-1), // creationTime
|
||||
12, // expirationInHours
|
||||
true, // isValid
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TokenIsValidData))]
|
||||
public void TokenIsValid_Success(string unprotectedTokenTemplate, string firstPart, string userEmail, Guid id, DateTime creationTime, double expirationInHours, bool isValid)
|
||||
{
|
||||
var protector = new TestDataProtector(string.Format(unprotectedTokenTemplate, CoreHelpers.ToEpocMilliseconds(creationTime)));
|
||||
|
||||
Assert.Equal(isValid, CoreHelpers.TokenIsValid(firstPart, protector, "protected_token", userEmail, id, expirationInHours));
|
||||
}
|
||||
|
||||
private class TestDataProtector : IDataProtector
|
||||
{
|
||||
private readonly string _token;
|
||||
public TestDataProtector(string token)
|
||||
{
|
||||
_token = token;
|
||||
}
|
||||
public IDataProtector CreateProtector(string purpose) => throw new NotImplementedException();
|
||||
public byte[] Protect(byte[] plaintext) => throw new NotImplementedException();
|
||||
public byte[] Unprotect(byte[] protectedData)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(_token);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("hi@email.com", "hi@email.com")] // Short email with no room to obfuscate
|
||||
[InlineData("name@email.com", "na**@email.com")] // Can obfuscate
|
||||
[InlineData("reallylongnamethatnooneshouldhave@email", "re*******************************@email")] // Really long email and no .com, .net, etc
|
||||
[InlineData("name@", "name@")] // @ symbol but no domain
|
||||
[InlineData("", "")] // Empty string
|
||||
[InlineData(null, null)] // null
|
||||
public void ObfuscateEmail_Success(string input, string expected)
|
||||
{
|
||||
Assert.Equal(expected, CoreHelpers.ObfuscateEmail(input));
|
||||
Assert.Contains(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(UserFixture))]
|
||||
public void BuildIdentityClaims_CustomOrganizationUserClaims_Success(User user, CurrentContentOrganization org)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
org.Type = OrganizationUserType.Custom;
|
||||
|
||||
var actual = CoreHelpers.BuildIdentityClaims(user, new[] { org }, Array.Empty<CurrentContentProvider>(), false);
|
||||
foreach (var (permitted, claimName) in org.Permissions.ClaimsMap)
|
||||
{
|
||||
var claim = new KeyValuePair<string, string>(claimName, org.Id.ToString());
|
||||
if (permitted)
|
||||
{
|
||||
|
||||
Assert.Contains(claim, actual);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.DoesNotContain(claim, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Theory, CustomAutoData(typeof(UserFixture))]
|
||||
public void BuildIdentityClaims_ProviderClaims_Success(User user)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutions();
|
||||
var providers = new List<CurrentContentProvider>();
|
||||
foreach (var providerUserType in Enum.GetValues<ProviderUserType>())
|
||||
{
|
||||
var provider = fixture.Create<CurrentContentProvider>();
|
||||
provider.Type = providerUserType;
|
||||
providers.Add(provider);
|
||||
}
|
||||
|
||||
var claims = new List<KeyValuePair<string, string>>();
|
||||
|
||||
if (providers.Any())
|
||||
{
|
||||
foreach (var group in providers.GroupBy(o => o.Type))
|
||||
{
|
||||
switch (group.Key)
|
||||
{
|
||||
case ProviderUserType.ProviderAdmin:
|
||||
foreach (var provider in group)
|
||||
{
|
||||
claims.Add(new KeyValuePair<string, string>("providerprovideradmin", provider.Id.ToString()));
|
||||
}
|
||||
break;
|
||||
case ProviderUserType.ServiceUser:
|
||||
foreach (var provider in group)
|
||||
{
|
||||
claims.Add(new KeyValuePair<string, string>("providerserviceuser", provider.Id.ToString()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var actual = CoreHelpers.BuildIdentityClaims(user, Array.Empty<CurrentContentOrganization>(), providers, false);
|
||||
foreach (var claim in claims)
|
||||
{
|
||||
Assert.Contains(claim, actual);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> TokenIsValidData()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new object[]
|
||||
{
|
||||
"first_part 476669d4-9642-4af8-9b29-9366efad4ed3 test@email.com {0}", // unprotectedTokenTemplate
|
||||
"first_part", // firstPart
|
||||
"test@email.com", // email
|
||||
Guid.Parse("476669d4-9642-4af8-9b29-9366efad4ed3"), // id
|
||||
DateTime.UtcNow.AddHours(-1), // creationTime
|
||||
12, // expirationInHours
|
||||
true, // isValid
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TokenIsValidData))]
|
||||
public void TokenIsValid_Success(string unprotectedTokenTemplate, string firstPart, string userEmail, Guid id, DateTime creationTime, double expirationInHours, bool isValid)
|
||||
{
|
||||
var protector = new TestDataProtector(string.Format(unprotectedTokenTemplate, CoreHelpers.ToEpocMilliseconds(creationTime)));
|
||||
|
||||
Assert.Equal(isValid, CoreHelpers.TokenIsValid(firstPart, protector, "protected_token", userEmail, id, expirationInHours));
|
||||
}
|
||||
|
||||
private class TestDataProtector : IDataProtector
|
||||
{
|
||||
private readonly string _token;
|
||||
public TestDataProtector(string token)
|
||||
{
|
||||
_token = token;
|
||||
}
|
||||
public IDataProtector CreateProtector(string purpose) => throw new NotImplementedException();
|
||||
public byte[] Protect(byte[] plaintext) => throw new NotImplementedException();
|
||||
public byte[] Unprotect(byte[] protectedData)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(_token);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("hi@email.com", "hi@email.com")] // Short email with no room to obfuscate
|
||||
[InlineData("name@email.com", "na**@email.com")] // Can obfuscate
|
||||
[InlineData("reallylongnamethatnooneshouldhave@email", "re*******************************@email")] // Really long email and no .com, .net, etc
|
||||
[InlineData("name@", "name@")] // @ symbol but no domain
|
||||
[InlineData("", "")] // Empty string
|
||||
[InlineData(null, null)] // null
|
||||
public void ObfuscateEmail_Success(string input, string expected)
|
||||
{
|
||||
Assert.Equal(expected, CoreHelpers.ObfuscateEmail(input));
|
||||
}
|
||||
}
|
||||
|
@ -1,43 +1,42 @@
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Utilities
|
||||
namespace Bit.Core.Test.Utilities;
|
||||
|
||||
public class EncryptedStringAttributeTests
|
||||
{
|
||||
public class EncryptedStringAttributeTests
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("aXY=|Y3Q=")] // Valid AesCbc256_B64
|
||||
[InlineData("aXY=|Y3Q=|cnNhQ3Q=")] // Valid AesCbc128_HmacSha256_B64
|
||||
[InlineData("Rsa2048_OaepSha256_B64.cnNhQ3Q=")]
|
||||
public void IsValid_ReturnsTrue_WhenValid(string input)
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("aXY=|Y3Q=")] // Valid AesCbc256_B64
|
||||
[InlineData("aXY=|Y3Q=|cnNhQ3Q=")] // Valid AesCbc128_HmacSha256_B64
|
||||
[InlineData("Rsa2048_OaepSha256_B64.cnNhQ3Q=")]
|
||||
public void IsValid_ReturnsTrue_WhenValid(string input)
|
||||
{
|
||||
var sut = new EncryptedStringAttribute();
|
||||
var sut = new EncryptedStringAttribute();
|
||||
|
||||
var actual = sut.IsValid(input);
|
||||
var actual = sut.IsValid(input);
|
||||
|
||||
Assert.True(actual);
|
||||
}
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData(".")]
|
||||
[InlineData("|")]
|
||||
[InlineData("!|!")] // Invalid base 64
|
||||
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.1")] // Invalid length
|
||||
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.|")] // Empty iv & ct
|
||||
[InlineData("AesCbc128_HmacSha256_B64.1")] // Invalid length
|
||||
[InlineData("AesCbc128_HmacSha256_B64.aXY=|Y3Q=|")] // Empty mac
|
||||
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.aXY=|Y3Q=|")] // Empty mac
|
||||
[InlineData("Rsa2048_OaepSha256_B64.1|2")] // Invalid length
|
||||
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.aXY=|")] // Empty mac
|
||||
public void IsValid_ReturnsFalse_WhenInvalid(string input)
|
||||
{
|
||||
var sut = new EncryptedStringAttribute();
|
||||
[Theory]
|
||||
[InlineData("")]
|
||||
[InlineData(".")]
|
||||
[InlineData("|")]
|
||||
[InlineData("!|!")] // Invalid base 64
|
||||
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.1")] // Invalid length
|
||||
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.|")] // Empty iv & ct
|
||||
[InlineData("AesCbc128_HmacSha256_B64.1")] // Invalid length
|
||||
[InlineData("AesCbc128_HmacSha256_B64.aXY=|Y3Q=|")] // Empty mac
|
||||
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.aXY=|Y3Q=|")] // Empty mac
|
||||
[InlineData("Rsa2048_OaepSha256_B64.1|2")] // Invalid length
|
||||
[InlineData("Rsa2048_OaepSha1_HmacSha256_B64.aXY=|")] // Empty mac
|
||||
public void IsValid_ReturnsFalse_WhenInvalid(string input)
|
||||
{
|
||||
var sut = new EncryptedStringAttribute();
|
||||
|
||||
var actual = sut.IsValid(input);
|
||||
var actual = sut.IsValid(input);
|
||||
|
||||
Assert.False(actual);
|
||||
}
|
||||
Assert.False(actual);
|
||||
}
|
||||
}
|
||||
|
@ -2,65 +2,64 @@
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Helpers
|
||||
namespace Bit.Core.Test.Helpers;
|
||||
|
||||
public class JsonHelpersTests
|
||||
{
|
||||
public class JsonHelpersTests
|
||||
private static void CompareJson<T>(T value, JsonSerializerOptions options, Newtonsoft.Json.JsonSerializerSettings settings)
|
||||
{
|
||||
private static void CompareJson<T>(T value, JsonSerializerOptions options, Newtonsoft.Json.JsonSerializerSettings settings)
|
||||
{
|
||||
var stgJson = JsonSerializer.Serialize(value, options);
|
||||
var nsJson = Newtonsoft.Json.JsonConvert.SerializeObject(value, settings);
|
||||
var stgJson = JsonSerializer.Serialize(value, options);
|
||||
var nsJson = Newtonsoft.Json.JsonConvert.SerializeObject(value, settings);
|
||||
|
||||
Assert.Equal(stgJson, nsJson);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void DefaultJsonOptions()
|
||||
{
|
||||
var testObject = new SimpleTestObject
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Test",
|
||||
};
|
||||
|
||||
CompareJson(testObject, JsonHelpers.Default, new Newtonsoft.Json.JsonSerializerSettings());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndentedJsonOptions()
|
||||
{
|
||||
var testObject = new SimpleTestObject
|
||||
{
|
||||
Id = 10,
|
||||
Name = "Test Name"
|
||||
};
|
||||
|
||||
CompareJson(testObject, JsonHelpers.Indented, new Newtonsoft.Json.JsonSerializerSettings
|
||||
{
|
||||
Formatting = Newtonsoft.Json.Formatting.Indented,
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NullValueHandlingJsonOptions()
|
||||
{
|
||||
var testObject = new SimpleTestObject
|
||||
{
|
||||
Id = 14,
|
||||
Name = null,
|
||||
};
|
||||
|
||||
CompareJson(testObject, JsonHelpers.IgnoreWritingNull, new Newtonsoft.Json.JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
|
||||
});
|
||||
}
|
||||
Assert.Equal(stgJson, nsJson);
|
||||
}
|
||||
|
||||
public class SimpleTestObject
|
||||
|
||||
[Fact]
|
||||
public void DefaultJsonOptions()
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
var testObject = new SimpleTestObject
|
||||
{
|
||||
Id = 0,
|
||||
Name = "Test",
|
||||
};
|
||||
|
||||
CompareJson(testObject, JsonHelpers.Default, new Newtonsoft.Json.JsonSerializerSettings());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IndentedJsonOptions()
|
||||
{
|
||||
var testObject = new SimpleTestObject
|
||||
{
|
||||
Id = 10,
|
||||
Name = "Test Name"
|
||||
};
|
||||
|
||||
CompareJson(testObject, JsonHelpers.Indented, new Newtonsoft.Json.JsonSerializerSettings
|
||||
{
|
||||
Formatting = Newtonsoft.Json.Formatting.Indented,
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NullValueHandlingJsonOptions()
|
||||
{
|
||||
var testObject = new SimpleTestObject
|
||||
{
|
||||
Id = 14,
|
||||
Name = null,
|
||||
};
|
||||
|
||||
CompareJson(testObject, JsonHelpers.IgnoreWritingNull, new Newtonsoft.Json.JsonSerializerSettings
|
||||
{
|
||||
NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class SimpleTestObject
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
}
|
||||
|
@ -5,165 +5,164 @@ using Bit.Core.Utilities;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Utilities
|
||||
namespace Bit.Core.Test.Utilities;
|
||||
|
||||
public class PermissiveStringConverterTests
|
||||
{
|
||||
public class PermissiveStringConverterTests
|
||||
private const string numberJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": [ 2, 3 ]}";
|
||||
private const string stringJson = "{ \"StringProp\": \"1\", \"EnumerableStringProp\": [ \"2\", \"3\" ]}";
|
||||
private const string nullAndEmptyJson = "{ \"StringProp\": null, \"EnumerableStringProp\": [] }";
|
||||
private const string singleValueJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": \"Hello!\" }";
|
||||
private const string nullJson = "{ \"StringProp\": null, \"EnumerableStringProp\": null }";
|
||||
private const string boolJson = "{ \"StringProp\": true, \"EnumerableStringProp\": [ false, 1.2]}";
|
||||
private const string objectJsonOne = "{ \"StringProp\": { \"Message\": \"Hi\"}, \"EnumerableStringProp\": []}";
|
||||
private const string objectJsonTwo = "{ \"StringProp\": \"Hi\", \"EnumerableStringProp\": {}}";
|
||||
private readonly string bigNumbersJson =
|
||||
"{ \"StringProp\":" + decimal.MinValue + ", \"EnumerableStringProp\": [" + ulong.MaxValue + ", " + long.MinValue + "]}";
|
||||
|
||||
[Theory]
|
||||
[InlineData(numberJson)]
|
||||
[InlineData(stringJson)]
|
||||
public void Read_Success(string json)
|
||||
{
|
||||
private const string numberJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": [ 2, 3 ]}";
|
||||
private const string stringJson = "{ \"StringProp\": \"1\", \"EnumerableStringProp\": [ \"2\", \"3\" ]}";
|
||||
private const string nullAndEmptyJson = "{ \"StringProp\": null, \"EnumerableStringProp\": [] }";
|
||||
private const string singleValueJson = "{ \"StringProp\": 1, \"EnumerableStringProp\": \"Hello!\" }";
|
||||
private const string nullJson = "{ \"StringProp\": null, \"EnumerableStringProp\": null }";
|
||||
private const string boolJson = "{ \"StringProp\": true, \"EnumerableStringProp\": [ false, 1.2]}";
|
||||
private const string objectJsonOne = "{ \"StringProp\": { \"Message\": \"Hi\"}, \"EnumerableStringProp\": []}";
|
||||
private const string objectJsonTwo = "{ \"StringProp\": \"Hi\", \"EnumerableStringProp\": {}}";
|
||||
private readonly string bigNumbersJson =
|
||||
"{ \"StringProp\":" + decimal.MinValue + ", \"EnumerableStringProp\": [" + ulong.MaxValue + ", " + long.MinValue + "]}";
|
||||
|
||||
[Theory]
|
||||
[InlineData(numberJson)]
|
||||
[InlineData(stringJson)]
|
||||
public void Read_Success(string json)
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(json);
|
||||
Assert.Equal("1", obj.StringProp);
|
||||
Assert.Equal(2, obj.EnumerableStringProp.Count());
|
||||
Assert.Equal("2", obj.EnumerableStringProp.ElementAt(0));
|
||||
Assert.Equal("3", obj.EnumerableStringProp.ElementAt(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_Boolean_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(boolJson);
|
||||
Assert.Equal("True", obj.StringProp);
|
||||
Assert.Equal(2, obj.EnumerableStringProp.Count());
|
||||
Assert.Equal("False", obj.EnumerableStringProp.ElementAt(0));
|
||||
Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_Float_Success_Culture()
|
||||
{
|
||||
var ci = new CultureInfo("sv-SE");
|
||||
Thread.CurrentThread.CurrentCulture = ci;
|
||||
Thread.CurrentThread.CurrentUICulture = ci;
|
||||
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(boolJson);
|
||||
Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_BigNumbers_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(bigNumbersJson);
|
||||
Assert.Equal(decimal.MinValue.ToString(), obj.StringProp);
|
||||
Assert.Equal(2, obj.EnumerableStringProp.Count());
|
||||
Assert.Equal(ulong.MaxValue.ToString(), obj.EnumerableStringProp.ElementAt(0));
|
||||
Assert.Equal(long.MinValue.ToString(), obj.EnumerableStringProp.ElementAt(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_SingleValue_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(singleValueJson);
|
||||
Assert.Equal("1", obj.StringProp);
|
||||
Assert.Single(obj.EnumerableStringProp);
|
||||
Assert.Equal("Hello!", obj.EnumerableStringProp.ElementAt(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_NullAndEmptyJson_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(nullAndEmptyJson);
|
||||
Assert.Null(obj.StringProp);
|
||||
Assert.Empty(obj.EnumerableStringProp);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_Null_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(nullJson);
|
||||
Assert.Null(obj.StringProp);
|
||||
Assert.Null(obj.EnumerableStringProp);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(objectJsonOne)]
|
||||
[InlineData(objectJsonTwo)]
|
||||
public void Read_Object_Throws(string json)
|
||||
{
|
||||
var exception = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<TestObject>(json));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Success()
|
||||
{
|
||||
var json = JsonSerializer.Serialize(new TestObject
|
||||
{
|
||||
StringProp = "1",
|
||||
EnumerableStringProp = new List<string>
|
||||
{
|
||||
"2",
|
||||
"3",
|
||||
},
|
||||
});
|
||||
|
||||
var jsonElement = JsonDocument.Parse(json).RootElement;
|
||||
|
||||
var stringProp = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String);
|
||||
Assert.Equal("1", stringProp.GetString());
|
||||
var list = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array);
|
||||
Assert.Equal(2, list.GetArrayLength());
|
||||
var firstElement = list[0];
|
||||
Assert.Equal(JsonValueKind.String, firstElement.ValueKind);
|
||||
Assert.Equal("2", firstElement.GetString());
|
||||
var secondElement = list[1];
|
||||
Assert.Equal(JsonValueKind.String, secondElement.ValueKind);
|
||||
Assert.Equal("3", secondElement.GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Null()
|
||||
{
|
||||
// When the values are null the converters aren't actually ran and it automatically serializes null
|
||||
var json = JsonSerializer.Serialize(new TestObject
|
||||
{
|
||||
StringProp = null,
|
||||
EnumerableStringProp = null,
|
||||
});
|
||||
|
||||
var jsonElement = JsonDocument.Parse(json).RootElement;
|
||||
|
||||
AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.Null);
|
||||
AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Empty()
|
||||
{
|
||||
// When the values are null the converters aren't actually ran and it automatically serializes null
|
||||
var json = JsonSerializer.Serialize(new TestObject
|
||||
{
|
||||
StringProp = "",
|
||||
EnumerableStringProp = Enumerable.Empty<string>(),
|
||||
});
|
||||
|
||||
var jsonElement = JsonDocument.Parse(json).RootElement;
|
||||
|
||||
var stringVal = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String).GetString();
|
||||
Assert.Equal("", stringVal);
|
||||
var array = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array);
|
||||
Assert.Equal(0, array.GetArrayLength());
|
||||
}
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(json);
|
||||
Assert.Equal("1", obj.StringProp);
|
||||
Assert.Equal(2, obj.EnumerableStringProp.Count());
|
||||
Assert.Equal("2", obj.EnumerableStringProp.ElementAt(0));
|
||||
Assert.Equal("3", obj.EnumerableStringProp.ElementAt(1));
|
||||
}
|
||||
|
||||
public class TestObject
|
||||
[Fact]
|
||||
public void Read_Boolean_Success()
|
||||
{
|
||||
[JsonConverter(typeof(PermissiveStringConverter))]
|
||||
public string StringProp { get; set; }
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(boolJson);
|
||||
Assert.Equal("True", obj.StringProp);
|
||||
Assert.Equal(2, obj.EnumerableStringProp.Count());
|
||||
Assert.Equal("False", obj.EnumerableStringProp.ElementAt(0));
|
||||
Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1));
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(PermissiveStringEnumerableConverter))]
|
||||
public IEnumerable<string> EnumerableStringProp { get; set; }
|
||||
[Fact]
|
||||
public void Read_Float_Success_Culture()
|
||||
{
|
||||
var ci = new CultureInfo("sv-SE");
|
||||
Thread.CurrentThread.CurrentCulture = ci;
|
||||
Thread.CurrentThread.CurrentUICulture = ci;
|
||||
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(boolJson);
|
||||
Assert.Equal("1.2", obj.EnumerableStringProp.ElementAt(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_BigNumbers_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(bigNumbersJson);
|
||||
Assert.Equal(decimal.MinValue.ToString(), obj.StringProp);
|
||||
Assert.Equal(2, obj.EnumerableStringProp.Count());
|
||||
Assert.Equal(ulong.MaxValue.ToString(), obj.EnumerableStringProp.ElementAt(0));
|
||||
Assert.Equal(long.MinValue.ToString(), obj.EnumerableStringProp.ElementAt(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_SingleValue_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(singleValueJson);
|
||||
Assert.Equal("1", obj.StringProp);
|
||||
Assert.Single(obj.EnumerableStringProp);
|
||||
Assert.Equal("Hello!", obj.EnumerableStringProp.ElementAt(0));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_NullAndEmptyJson_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(nullAndEmptyJson);
|
||||
Assert.Null(obj.StringProp);
|
||||
Assert.Empty(obj.EnumerableStringProp);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Read_Null_Success()
|
||||
{
|
||||
var obj = JsonSerializer.Deserialize<TestObject>(nullJson);
|
||||
Assert.Null(obj.StringProp);
|
||||
Assert.Null(obj.EnumerableStringProp);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(objectJsonOne)]
|
||||
[InlineData(objectJsonTwo)]
|
||||
public void Read_Object_Throws(string json)
|
||||
{
|
||||
var exception = Assert.Throws<JsonException>(() => JsonSerializer.Deserialize<TestObject>(json));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Success()
|
||||
{
|
||||
var json = JsonSerializer.Serialize(new TestObject
|
||||
{
|
||||
StringProp = "1",
|
||||
EnumerableStringProp = new List<string>
|
||||
{
|
||||
"2",
|
||||
"3",
|
||||
},
|
||||
});
|
||||
|
||||
var jsonElement = JsonDocument.Parse(json).RootElement;
|
||||
|
||||
var stringProp = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String);
|
||||
Assert.Equal("1", stringProp.GetString());
|
||||
var list = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array);
|
||||
Assert.Equal(2, list.GetArrayLength());
|
||||
var firstElement = list[0];
|
||||
Assert.Equal(JsonValueKind.String, firstElement.ValueKind);
|
||||
Assert.Equal("2", firstElement.GetString());
|
||||
var secondElement = list[1];
|
||||
Assert.Equal(JsonValueKind.String, secondElement.ValueKind);
|
||||
Assert.Equal("3", secondElement.GetString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Null()
|
||||
{
|
||||
// When the values are null the converters aren't actually ran and it automatically serializes null
|
||||
var json = JsonSerializer.Serialize(new TestObject
|
||||
{
|
||||
StringProp = null,
|
||||
EnumerableStringProp = null,
|
||||
});
|
||||
|
||||
var jsonElement = JsonDocument.Parse(json).RootElement;
|
||||
|
||||
AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.Null);
|
||||
AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Null);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Write_Empty()
|
||||
{
|
||||
// When the values are null the converters aren't actually ran and it automatically serializes null
|
||||
var json = JsonSerializer.Serialize(new TestObject
|
||||
{
|
||||
StringProp = "",
|
||||
EnumerableStringProp = Enumerable.Empty<string>(),
|
||||
});
|
||||
|
||||
var jsonElement = JsonDocument.Parse(json).RootElement;
|
||||
|
||||
var stringVal = AssertHelper.AssertJsonProperty(jsonElement, "StringProp", JsonValueKind.String).GetString();
|
||||
Assert.Equal("", stringVal);
|
||||
var array = AssertHelper.AssertJsonProperty(jsonElement, "EnumerableStringProp", JsonValueKind.Array);
|
||||
Assert.Equal(0, array.GetArrayLength());
|
||||
}
|
||||
}
|
||||
|
||||
public class TestObject
|
||||
{
|
||||
[JsonConverter(typeof(PermissiveStringConverter))]
|
||||
public string StringProp { get; set; }
|
||||
|
||||
[JsonConverter(typeof(PermissiveStringEnumerableConverter))]
|
||||
public IEnumerable<string> EnumerableStringProp { get; set; }
|
||||
}
|
||||
|
@ -10,83 +10,82 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Utilities
|
||||
namespace Bit.Core.Test.Utilities;
|
||||
|
||||
public class SelfHostedAttributeTests
|
||||
{
|
||||
public class SelfHostedAttributeTests
|
||||
[Fact]
|
||||
public void NotSelfHosted_Throws_When_SelfHosted()
|
||||
{
|
||||
[Fact]
|
||||
public void NotSelfHosted_Throws_When_SelfHosted()
|
||||
// Arrange
|
||||
var sha = new SelfHostedAttribute { NotSelfHostedOnly = true };
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<BadRequestException>(() => sha.OnActionExecuting(GetContext(selfHosted: true)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NotSelfHosted_Success_When_NotSelfHosted()
|
||||
{
|
||||
// Arrange
|
||||
var sha = new SelfHostedAttribute { NotSelfHostedOnly = true };
|
||||
|
||||
// Act
|
||||
sha.OnActionExecuting(GetContext(selfHosted: false));
|
||||
|
||||
// Assert
|
||||
// The Assert here is just NOT throwing an exception
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void SelfHosted_Success_When_SelfHosted()
|
||||
{
|
||||
// Arrange
|
||||
var sha = new SelfHostedAttribute { SelfHostedOnly = true };
|
||||
|
||||
// Act
|
||||
sha.OnActionExecuting(GetContext(selfHosted: true));
|
||||
|
||||
// Assert
|
||||
// The Assert here is just NOT throwing an exception
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelfHosted_Throws_When_NotSelfHosted()
|
||||
{
|
||||
// Arrange
|
||||
var sha = new SelfHostedAttribute { SelfHostedOnly = true };
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<BadRequestException>(() => sha.OnActionExecuting(GetContext(selfHosted: false)));
|
||||
}
|
||||
|
||||
|
||||
// This generates a ActionExecutingContext with the needed injected
|
||||
// service with the given value.
|
||||
private ActionExecutingContext GetContext(bool selfHosted)
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
|
||||
var globalSettings = new GlobalSettings
|
||||
{
|
||||
// Arrange
|
||||
var sha = new SelfHostedAttribute { NotSelfHostedOnly = true };
|
||||
SelfHosted = selfHosted
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<BadRequestException>(() => sha.OnActionExecuting(GetContext(selfHosted: true)));
|
||||
}
|
||||
services.AddSingleton(globalSettings);
|
||||
|
||||
[Fact]
|
||||
public void NotSelfHosted_Success_When_NotSelfHosted()
|
||||
{
|
||||
// Arrange
|
||||
var sha = new SelfHostedAttribute { NotSelfHostedOnly = true };
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.RequestServices = services.BuildServiceProvider();
|
||||
|
||||
// Act
|
||||
sha.OnActionExecuting(GetContext(selfHosted: false));
|
||||
var context = Substitute.For<ActionExecutingContext>(
|
||||
Substitute.For<ActionContext>(httpContext,
|
||||
new RouteData(),
|
||||
Substitute.For<ActionDescriptor>()),
|
||||
new List<IFilterMetadata>(),
|
||||
new Dictionary<string, object>(),
|
||||
Substitute.For<Controller>());
|
||||
|
||||
// Assert
|
||||
// The Assert here is just NOT throwing an exception
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void SelfHosted_Success_When_SelfHosted()
|
||||
{
|
||||
// Arrange
|
||||
var sha = new SelfHostedAttribute { SelfHostedOnly = true };
|
||||
|
||||
// Act
|
||||
sha.OnActionExecuting(GetContext(selfHosted: true));
|
||||
|
||||
// Assert
|
||||
// The Assert here is just NOT throwing an exception
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelfHosted_Throws_When_NotSelfHosted()
|
||||
{
|
||||
// Arrange
|
||||
var sha = new SelfHostedAttribute { SelfHostedOnly = true };
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<BadRequestException>(() => sha.OnActionExecuting(GetContext(selfHosted: false)));
|
||||
}
|
||||
|
||||
|
||||
// This generates a ActionExecutingContext with the needed injected
|
||||
// service with the given value.
|
||||
private ActionExecutingContext GetContext(bool selfHosted)
|
||||
{
|
||||
IServiceCollection services = new ServiceCollection();
|
||||
|
||||
var globalSettings = new GlobalSettings
|
||||
{
|
||||
SelfHosted = selfHosted
|
||||
};
|
||||
|
||||
services.AddSingleton(globalSettings);
|
||||
|
||||
var httpContext = new DefaultHttpContext();
|
||||
httpContext.RequestServices = services.BuildServiceProvider();
|
||||
|
||||
var context = Substitute.For<ActionExecutingContext>(
|
||||
Substitute.For<ActionContext>(httpContext,
|
||||
new RouteData(),
|
||||
Substitute.For<ActionDescriptor>()),
|
||||
new List<IFilterMetadata>(),
|
||||
new Dictionary<string, object>(),
|
||||
Substitute.For<Controller>());
|
||||
|
||||
return context;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
@ -1,59 +1,58 @@
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Utilities
|
||||
namespace Bit.Core.Test.Utilities;
|
||||
|
||||
public class StrictEmailAttributeTests
|
||||
{
|
||||
public class StrictEmailAttributeTests
|
||||
[Theory]
|
||||
[InlineData("hello@world.com")] // regular email address
|
||||
[InlineData("hello@world.planet.com")] // subdomain
|
||||
[InlineData("hello+1@world.com")] // alias
|
||||
[InlineData("hello.there@world.com")] // period in local-part
|
||||
[InlineData("hello@wörldé.com")] // unicode domain
|
||||
[InlineData("hello@world.cömé")] // unicode top-level domain
|
||||
public void IsValid_ReturnsTrueWhenValid(string email)
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("hello@world.com")] // regular email address
|
||||
[InlineData("hello@world.planet.com")] // subdomain
|
||||
[InlineData("hello+1@world.com")] // alias
|
||||
[InlineData("hello.there@world.com")] // period in local-part
|
||||
[InlineData("hello@wörldé.com")] // unicode domain
|
||||
[InlineData("hello@world.cömé")] // unicode top-level domain
|
||||
public void IsValid_ReturnsTrueWhenValid(string email)
|
||||
{
|
||||
var sut = new StrictEmailAddressAttribute();
|
||||
var sut = new StrictEmailAddressAttribute();
|
||||
|
||||
var actual = sut.IsValid(email);
|
||||
var actual = sut.IsValid(email);
|
||||
|
||||
Assert.True(actual);
|
||||
}
|
||||
Assert.True(actual);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)] // null
|
||||
[InlineData("hello@world.com\t")] // trailing tab char
|
||||
[InlineData("\thello@world.com")] // leading tab char
|
||||
[InlineData("hel\tlo@world.com")] // local-part tab char
|
||||
[InlineData("hello@world.com\b")] // trailing backspace char
|
||||
[InlineData("\" \"hello@world.com")] // leading spaces in quotes
|
||||
[InlineData("hello@world.com\" \"")] // trailing spaces in quotes
|
||||
[InlineData("hel\" \"lo@world.com")] // local-part spaces in quotes
|
||||
[InlineData("hello there@world.com")] // unescaped unquoted spaces
|
||||
[InlineData("Hello <hello@world.com>")] // friendly from
|
||||
[InlineData("<hello@world.com>")] // wrapped angle brackets
|
||||
[InlineData("hello(com)there@world.com")] // comment
|
||||
[InlineData("hello@world.com.")] // trailing period
|
||||
[InlineData(".hello@world.com")] // leading period
|
||||
[InlineData("hello@world.com;")] // trailing semicolon
|
||||
[InlineData(";hello@world.com")] // leading semicolon
|
||||
[InlineData("hello@world.com; hello@world.com")] // semicolon separated list
|
||||
[InlineData("hello@world.com, hello@world.com")] // comma separated list
|
||||
[InlineData("hellothere@worldcom")] // dotless domain
|
||||
[InlineData("hello.there@worldcom")] // dotless domain
|
||||
[InlineData("hellothere@.worldcom")] // domain beginning with dot
|
||||
[InlineData("hellothere@worldcom.")] // domain ending in dot
|
||||
[InlineData("hellothere@world.com-")] // domain ending in hyphen
|
||||
[InlineData("hellö@world.com")] // unicode at end of local-part
|
||||
[InlineData("héllo@world.com")] // unicode in middle of local-part
|
||||
public void IsValid_ReturnsFalseWhenInvalid(string email)
|
||||
{
|
||||
var sut = new StrictEmailAddressAttribute();
|
||||
[Theory]
|
||||
[InlineData(null)] // null
|
||||
[InlineData("hello@world.com\t")] // trailing tab char
|
||||
[InlineData("\thello@world.com")] // leading tab char
|
||||
[InlineData("hel\tlo@world.com")] // local-part tab char
|
||||
[InlineData("hello@world.com\b")] // trailing backspace char
|
||||
[InlineData("\" \"hello@world.com")] // leading spaces in quotes
|
||||
[InlineData("hello@world.com\" \"")] // trailing spaces in quotes
|
||||
[InlineData("hel\" \"lo@world.com")] // local-part spaces in quotes
|
||||
[InlineData("hello there@world.com")] // unescaped unquoted spaces
|
||||
[InlineData("Hello <hello@world.com>")] // friendly from
|
||||
[InlineData("<hello@world.com>")] // wrapped angle brackets
|
||||
[InlineData("hello(com)there@world.com")] // comment
|
||||
[InlineData("hello@world.com.")] // trailing period
|
||||
[InlineData(".hello@world.com")] // leading period
|
||||
[InlineData("hello@world.com;")] // trailing semicolon
|
||||
[InlineData(";hello@world.com")] // leading semicolon
|
||||
[InlineData("hello@world.com; hello@world.com")] // semicolon separated list
|
||||
[InlineData("hello@world.com, hello@world.com")] // comma separated list
|
||||
[InlineData("hellothere@worldcom")] // dotless domain
|
||||
[InlineData("hello.there@worldcom")] // dotless domain
|
||||
[InlineData("hellothere@.worldcom")] // domain beginning with dot
|
||||
[InlineData("hellothere@worldcom.")] // domain ending in dot
|
||||
[InlineData("hellothere@world.com-")] // domain ending in hyphen
|
||||
[InlineData("hellö@world.com")] // unicode at end of local-part
|
||||
[InlineData("héllo@world.com")] // unicode in middle of local-part
|
||||
public void IsValid_ReturnsFalseWhenInvalid(string email)
|
||||
{
|
||||
var sut = new StrictEmailAddressAttribute();
|
||||
|
||||
var actual = sut.IsValid(email);
|
||||
var actual = sut.IsValid(email);
|
||||
|
||||
Assert.False(actual);
|
||||
}
|
||||
Assert.False(actual);
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +1,53 @@
|
||||
using Bit.Core.Utilities;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.Utilities
|
||||
namespace Bit.Core.Test.Utilities;
|
||||
|
||||
public class StrictEmailAddressListAttributeTests
|
||||
{
|
||||
public class StrictEmailAddressListAttributeTests
|
||||
public static List<object[]> EmailList => new()
|
||||
{
|
||||
public static List<object[]> EmailList => new()
|
||||
{
|
||||
new object[] { new List<string> { "test@domain.com", "test@sub.domain.com", "hello@world.planet.com" }, true },
|
||||
new object[] { new List<string> { "/hello@world.com", "hello@##world.pla net.com", "''thello@world.com" }, false },
|
||||
new object[] { new List<string> { "/hello.com", "test@domain.com", "''thello@world.com" }, false },
|
||||
new object[] { new List<string> { "héllö@world.com", "hello@world.planet.com", "hello@world.planet.com" }, false },
|
||||
new object[] { new List<string> { }, false },
|
||||
new object[] { new List<string>
|
||||
{
|
||||
"test1@domain.com", "test2@domain.com", "test3@domain.com", "test4@domain.com", "test5@domain.com",
|
||||
"test6@domain.com", "test7@domain.com", "test8@domain.com", "test9@domain.com", "test10@domain.com",
|
||||
"test11@domain.com", "test12@domain.com", "test13@domain.com", "test14@domain.com", "test15@domain.com",
|
||||
"test16@domain.com", "test17@domain.com", "test18@domain.com", "test19@domain.com", "test20@domain.com",
|
||||
"test21@domain.com", "test22@domain.com", "test23@domain.com", "test24@domain.com", "test25@domain.com",
|
||||
}, false },
|
||||
new object[] { new List<string>
|
||||
{
|
||||
"test1domaincomtest2domaincomtest3domaincomtest4domaincomtest5domaincomtest6domaincomtest7domaincomtest8domaincomtest9domaincomtest10domaincomtest1domaincomtest2domaincomtest3domaincomtest4domaincomtest5domaincomtest6domaincomtest7domaincomtest8domaincomtest9domaincomtest10domaincom@test.com",
|
||||
"test@domain.com"
|
||||
}, false } // > 256 character email
|
||||
new object[] { new List<string> { "test@domain.com", "test@sub.domain.com", "hello@world.planet.com" }, true },
|
||||
new object[] { new List<string> { "/hello@world.com", "hello@##world.pla net.com", "''thello@world.com" }, false },
|
||||
new object[] { new List<string> { "/hello.com", "test@domain.com", "''thello@world.com" }, false },
|
||||
new object[] { new List<string> { "héllö@world.com", "hello@world.planet.com", "hello@world.planet.com" }, false },
|
||||
new object[] { new List<string> { }, false },
|
||||
new object[] { new List<string>
|
||||
{
|
||||
"test1@domain.com", "test2@domain.com", "test3@domain.com", "test4@domain.com", "test5@domain.com",
|
||||
"test6@domain.com", "test7@domain.com", "test8@domain.com", "test9@domain.com", "test10@domain.com",
|
||||
"test11@domain.com", "test12@domain.com", "test13@domain.com", "test14@domain.com", "test15@domain.com",
|
||||
"test16@domain.com", "test17@domain.com", "test18@domain.com", "test19@domain.com", "test20@domain.com",
|
||||
"test21@domain.com", "test22@domain.com", "test23@domain.com", "test24@domain.com", "test25@domain.com",
|
||||
}, false },
|
||||
new object[] { new List<string>
|
||||
{
|
||||
"test1domaincomtest2domaincomtest3domaincomtest4domaincomtest5domaincomtest6domaincomtest7domaincomtest8domaincomtest9domaincomtest10domaincomtest1domaincomtest2domaincomtest3domaincomtest4domaincomtest5domaincomtest6domaincomtest7domaincomtest8domaincomtest9domaincomtest10domaincom@test.com",
|
||||
"test@domain.com"
|
||||
}, false } // > 256 character email
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(EmailList))]
|
||||
public void IsListValid_ReturnsTrue_WhenValid(List<string> emailList, bool valid)
|
||||
{
|
||||
var sut = new StrictEmailAddressListAttribute();
|
||||
[Theory]
|
||||
[MemberData(nameof(EmailList))]
|
||||
public void IsListValid_ReturnsTrue_WhenValid(List<string> emailList, bool valid)
|
||||
{
|
||||
var sut = new StrictEmailAddressListAttribute();
|
||||
|
||||
var actual = sut.IsValid(emailList);
|
||||
var actual = sut.IsValid(emailList);
|
||||
|
||||
Assert.Equal(actual, valid);
|
||||
}
|
||||
Assert.Equal(actual, valid);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("single@email.com", false)]
|
||||
[InlineData(null, false)]
|
||||
public void IsValid_ReturnsTrue_WhenValid(string email, bool valid)
|
||||
{
|
||||
var sut = new StrictEmailAddressListAttribute();
|
||||
[Theory]
|
||||
[InlineData("single@email.com", false)]
|
||||
[InlineData(null, false)]
|
||||
public void IsValid_ReturnsTrue_WhenValid(string email, bool valid)
|
||||
{
|
||||
var sut = new StrictEmailAddressListAttribute();
|
||||
|
||||
var actual = sut.IsValid(email);
|
||||
var actual = sut.IsValid(email);
|
||||
|
||||
Assert.Equal(actual, valid);
|
||||
}
|
||||
Assert.Equal(actual, valid);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user