diff --git a/Directory.Build.props b/Directory.Build.props
index 4e9bc56..23700e2 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -8,8 +8,8 @@
en
Copyright © ONIXLabs 2020
https://github.com/onix-labs/onixlabs-dotnet
- 11.1.0
- 11.1.0
- 11.1.0
+ 11.2.0
+ 11.2.0
+ 11.2.0
diff --git a/OnixLabs.Core.UnitTests/StringExtensionTests.cs b/OnixLabs.Core.UnitTests/StringExtensionTests.cs
index ce2fdbb..7cbd138 100644
--- a/OnixLabs.Core.UnitTests/StringExtensionTests.cs
+++ b/OnixLabs.Core.UnitTests/StringExtensionTests.cs
@@ -20,6 +20,38 @@ namespace OnixLabs.Core.UnitTests;
public sealed class StringExtensionTests
{
+ [Theory(DisplayName = "String.NthIndexOf should return the expected result")]
+ [InlineData("First:Second:Third:Fourth", ':', 0, -1)]
+ [InlineData("First:Second:Third:Fourth", ':', 1, 5)]
+ [InlineData("First:Second:Third:Fourth", ':', 2, 12)]
+ [InlineData("First:Second:Third:Fourth", ':', 3, 18)]
+ [InlineData("First:Second:Third:Fourth", ':', 4, -1)]
+ [InlineData("First:Second:Third:Fourth", ':', 100, -1)]
+ public void NthIndexOfCharShouldProduceExpectedResult(string value, char seekValue, int count, int expected)
+ {
+ // When
+ int actual = value.NthIndexOf(seekValue, count);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "String.NthIndexOf should return the expected result")]
+ [InlineData("First_split_Second_split_Third_split_Fourth", "_split_", 0, -1)]
+ [InlineData("First_split_Second_split_Third_split_Fourth", "_split_", 1, 5)]
+ [InlineData("First_split_Second_split_Third_split_Fourth", "_split_", 2, 18)]
+ [InlineData("First_split_Second_split_Third_split_Fourth", "_split_", 3, 30)]
+ [InlineData("First_split_Second_split_Third_split_Fourth", "_split_", 4, -1)]
+ [InlineData("First_split_Second_split_Third_split_Fourth", "_split_", 100, -1)]
+ public void NthIndexOfStringShouldProduceExpectedResult(string value, string seekValue, int count, int expected)
+ {
+ // When
+ int actual = value.NthIndexOf(seekValue, count);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
[Theory(DisplayName = "String.Repeat should return the expected result")]
[InlineData("0", 10, "0000000000")]
[InlineData("Abc1", 3, "Abc1Abc1Abc1")]
@@ -128,6 +160,72 @@ public void SubstringAfterLastShouldProduceExpectedResultString(string value, st
Assert.Equal(expected, actual);
}
+ [Theory(DisplayName = "String.SubstringBeforeNth(char) should return the expected substring or default value")]
+ [InlineData("One:Two:Three:Four", ':', 1, null, "One")]
+ [InlineData("One:Two:Three:Four", ':', 2, null, "One:Two")]
+ [InlineData("One:Two:Three:Four", ':', 3, null, "One:Two:Three")]
+ [InlineData("One:Two:Three:Four", ':', 4, null, "One:Two:Three:Four")]
+ [InlineData("One:Two:Three:Four", ':', 4, "NOT_FOUND", "NOT_FOUND")]
+ [InlineData("One:Two:Three", ':', 0, null, "One:Two:Three")]
+ [InlineData("One:Two:Three", ':', -1, null, "One:Two:Three")]
+ public void SubstringBeforeNthCharShouldProduceExpectedResult(string value, char delimiter, int nth, string? defaultValue, string expected)
+ {
+ // When
+ string actual = value.SubstringBeforeNth(delimiter, nth, defaultValue);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "String.SubstringBeforeNth(string) should return the expected substring or default value")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 1, null, "One")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 2, null, "One_split_Two")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 3, null, "One_split_Two_split_Three")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 4, null, "One_split_Two_split_Three_split_Four")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 4, "NOT_FOUND", "NOT_FOUND")]
+ [InlineData("NoDelimiterHere", "_split_", 1, null, "NoDelimiterHere")]
+ public void SubstringBeforeNthStringShouldProduceExpectedResult(string value, string delimiter, int nth, string? defaultValue, string expected)
+ {
+ // When
+ string actual = value.SubstringBeforeNth(delimiter, nth, defaultValue);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "String.SubstringAfterNth(char) should return the expected substring or default value")]
+ [InlineData("One:Two:Three:Four", ':', 1, null, "Two:Three:Four")]
+ [InlineData("One:Two:Three:Four", ':', 2, null, "Three:Four")]
+ [InlineData("One:Two:Three:Four", ':', 3, null, "Four")]
+ [InlineData("One:Two:Three:Four", ':', 4, null, "One:Two:Three:Four")]
+ [InlineData("One:Two:Three:Four", ':', 4, "NOT_FOUND", "NOT_FOUND")]
+ [InlineData("One:Two:Three", ':', 0, null, "One:Two:Three")]
+ [InlineData("One:Two:Three", ':', -1, null, "One:Two:Three")]
+ public void SubstringAfterNthCharShouldProduceExpectedResult(string value, char delimiter, int nth, string? defaultValue, string expected)
+ {
+ // When
+ string actual = value.SubstringAfterNth(delimiter, nth, defaultValue);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "String.SubstringAfterNth(string) should return the expected substring or default value")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 1, null, "Two_split_Three_split_Four")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 2, null, "Three_split_Four")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 3, null, "Four")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 4, null, "One_split_Two_split_Three_split_Four")]
+ [InlineData("One_split_Two_split_Three_split_Four", "_split_", 4, "NOT_FOUND", "NOT_FOUND")]
+ [InlineData("NoDelimiterHere", "_split_", 1, null, "NoDelimiterHere")]
+ public void SubstringAfterNthStringShouldProduceExpectedResult(string value, string delimiter, int nth, string? defaultValue, string expected)
+ {
+ // When
+ string actual = value.SubstringAfterNth(delimiter, nth, defaultValue);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
[Theory(DisplayName = "String.ToByteArray should produce the byte array equivalent of the current string")]
[InlineData("Hello, World!", new byte[] { 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21 })]
public void ToByteArrayShouldProduceExpectedResult(string value, byte[] expected)
diff --git a/OnixLabs.Core/Extensions.String.cs b/OnixLabs.Core/Extensions.String.cs
index f0d0a25..adccb0b 100644
--- a/OnixLabs.Core/Extensions.String.cs
+++ b/OnixLabs.Core/Extensions.String.cs
@@ -42,13 +42,78 @@ public static class StringExtensions
///
private const DateTimeStyles DefaultStyles = DateTimeStyles.None;
+ ///
+ /// Obtains the zero-based index of the nth occurrence of the specified character in this instance.
+ /// If the specified occurrence does not exist, returns -1.
+ ///
+ /// The string to search.
+ /// The character to seek.
+ /// The number of occurrences to skip before returning an index.
+ ///
+ /// Returns the zero-based index position of the nth occurrence of , if found; otherwise, -1.
+ ///
+ public static int NthIndexOf(this string value, char seekValue, int count)
+ {
+ if (string.IsNullOrEmpty(value) || count <= 0) return -1;
+
+ int occurrences = 0;
+
+ for (int i = 0; i < value.Length; i++)
+ {
+ if (value[i] != seekValue) continue;
+
+ occurrences++;
+
+ if (occurrences != count) continue;
+
+ return i;
+ }
+
+ return NotFound;
+ }
+
+ ///
+ /// Obtains the zero-based index of the nth occurrence of the specified character in this instance.
+ /// If the specified occurrence does not exist, returns -1.
+ ///
+ /// The string to search.
+ /// The substring to seek.
+ /// The number of occurrences to skip before returning an index.
+ /// The comparison that will be used to compare the current value and the seek value.
+ ///
+ /// Returns the zero-based index position of the nth occurrence of , if found; otherwise, -1.
+ ///
+ public static int NthIndexOf(this string value, string seekValue, int count, StringComparison comparison = DefaultComparison)
+ {
+ if (string.IsNullOrEmpty(value) || string.IsNullOrEmpty(seekValue) || count <= 0) return -1;
+
+ int occurrences = 0;
+ int startIndex = 0;
+
+ while (true)
+ {
+ int index = value.IndexOf(seekValue, startIndex, comparison);
+
+ if (index == -1) return -1;
+
+ occurrences++;
+
+ if (occurrences == count) return index;
+
+ startIndex = index + seekValue.Length;
+
+ if (startIndex >= value.Length) return NotFound;
+ }
+ }
+
///
/// Repeats the current by the specified number of repetitions.
///
/// The instance to repeat.
/// The number of repetitions of the current instance.
/// Returns a new instance representing the repetition of the current instance.
- public static string Repeat(this string value, int count) => count > 0 ? string.Join(string.Empty, Enumerable.Repeat(value, count)) : string.Empty;
+ public static string Repeat(this string value, int count) =>
+ count > 0 ? string.Join(string.Empty, Enumerable.Repeat(value, count)) : string.Empty;
///
/// Obtains a sub-string before the specified index within the current instance.
@@ -64,7 +129,8 @@ public static class StringExtensions
/// If the default value is , then the current instance will be returned.
///
// ReSharper disable once HeapView.ObjectAllocation
- private static string SubstringBeforeIndex(this string value, int index, string? defaultValue = null) => index <= NotFound ? defaultValue ?? value : value[..index];
+ private static string SubstringBeforeIndex(this string value, int index, string? defaultValue = null) =>
+ index <= NotFound ? defaultValue ?? value : value[..index];
///
/// Obtains a sub-string after the specified index within the current instance.
@@ -81,7 +147,8 @@ public static class StringExtensions
/// If the default value is , then the current instance will be returned.
///
// ReSharper disable once HeapView.ObjectAllocation
- private static string SubstringAfterIndex(this string value, int index, int offset, string? defaultValue = null) => index <= NotFound ? defaultValue ?? value : value[(index + offset)..value.Length];
+ private static string SubstringAfterIndex(this string value, int index, int offset, string? defaultValue = null) =>
+ index <= NotFound ? defaultValue ?? value : value[(index + offset)..value.Length];
///
/// Obtains a sub-string before the first occurrence of the specified delimiter within the current instance.
@@ -235,6 +302,95 @@ public static string SubstringAfterLast(this string value, char delimiter, strin
public static string SubstringAfterLast(this string value, string delimiter, string? defaultValue = null, StringComparison comparison = DefaultComparison) =>
value.SubstringAfterIndex(value.LastIndexOf(delimiter, comparison), 1, defaultValue);
+ ///
+ /// Obtains a sub-string before the nth occurrence of the specified character within the current instance.
+ /// If the nth occurrence is not found, returns the or the entire string if default is null.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The character to find the nth occurrence of.
+ /// The nth occurrence to find.
+ ///
+ /// The value to return if the nth occurrence is not found.
+ /// If the default value is , the current instance is returned.
+ ///
+ ///
+ /// A sub-string before the nth occurrence of if found; otherwise,
+ /// or the entire string if default is null.
+ ///
+ public static string SubstringBeforeNth(this string value, char seekValue, int count, string? defaultValue = null)
+ {
+ int index = value.NthIndexOf(seekValue, count);
+ return value.SubstringBeforeIndex(index, defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string before the nth occurrence of the specified substring within the current instance.
+ /// If the nth occurrence is not found, returns the or the entire string if default is null.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The substring to find the nth occurrence of.
+ /// The nth occurrence to find.
+ ///
+ /// The value to return if the nth occurrence is not found.
+ /// If the default value is , the current instance is returned.
+ ///
+ /// The comparison that will be used to compare the current value and the seek value.
+ ///
+ /// A sub-string before the nth occurrence of if found; otherwise,
+ /// or the entire string if default is null.
+ ///
+ public static string SubstringBeforeNth(this string value, string seekValue, int count, string? defaultValue = null, StringComparison comparison = DefaultComparison)
+ {
+ int index = value.NthIndexOf(seekValue, count, comparison);
+ return value.SubstringBeforeIndex(index, defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string after the nth occurrence of the specified character within the current instance.
+ /// If the nth occurrence is not found, returns the or the entire string if default is null.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The character to find the nth occurrence of.
+ /// The nth occurrence to find.
+ ///
+ /// The value to return if the nth occurrence is not found.
+ /// If the default value is , the current instance is returned.
+ ///
+ ///
+ /// A sub-string after the nth occurrence of if found; otherwise,
+ /// or the entire string if default is null.
+ ///
+ public static string SubstringAfterNth(this string value, char seekValue, int count, string? defaultValue = null)
+ {
+ int index = value.NthIndexOf(seekValue, count);
+ // Move 1 character after the nth occurrence index.
+ return value.SubstringAfterIndex(index, 1, defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string after the nth occurrence of the specified substring within the current instance.
+ /// If the nth occurrence is not found, returns the or the entire string if default is null.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The substring to find the nth occurrence of.
+ /// The nth occurrence to find.
+ ///
+ /// The value to return if the nth occurrence is not found.
+ /// If the default value is , the current instance is returned.
+ ///
+ /// The comparison that will be used to compare the current value and the seek value.
+ ///
+ /// A sub-string after the nth occurrence of if found; otherwise,
+ /// or the entire string if default is null.
+ ///
+ public static string SubstringAfterNth(this string value, string seekValue, int count, string? defaultValue = null, StringComparison comparison = DefaultComparison)
+ {
+ int index = value.NthIndexOf(seekValue, count, comparison);
+ // Move by the length of the found substring after the nth occurrence index.
+ int offset = (index != NotFound && !string.IsNullOrEmpty(seekValue)) ? seekValue.Length : 0;
+ return value.SubstringAfterIndex(index, offset, defaultValue);
+ }
+
///
/// Converts the current instance into a new instance.
///
@@ -336,7 +492,8 @@ public static bool TryCopyTo(this string value, Span destination, out int
/// The that should precede the current instance.
/// The that should succeed the current instance.
/// Returns a new instance representing the current instance, wrapped between the specified before and after instances.
- public static string Wrap(this string value, char before, char after) => string.Concat(before.ToString(), value, after.ToString());
+ public static string Wrap(this string value, char before, char after) =>
+ string.Concat(before.ToString(), value, after.ToString());
///
/// Wraps the current instance between the specified before and after instances.
@@ -345,5 +502,6 @@ public static bool TryCopyTo(this string value, Span destination, out int
/// The that should precede the current instance.
/// The that should succeed the current instance.
/// Returns a new instance representing the current instance, wrapped between the specified before and after instances.
- public static string Wrap(this string value, string before, string after) => string.Concat(before, value, after);
+ public static string Wrap(this string value, string before, string after) =>
+ string.Concat(before, value, after);
}
diff --git a/OnixLabs.Playground/Program.cs b/OnixLabs.Playground/Program.cs
index 55fdc74..d629839 100644
--- a/OnixLabs.Playground/Program.cs
+++ b/OnixLabs.Playground/Program.cs
@@ -12,19 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-using System;
-using OnixLabs.Security.Cryptography;
-
namespace OnixLabs.Playground;
internal static class Program
{
private static void Main()
{
- string value = "SHA256:043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89";
-
- NamedHash hash = NamedHash.Parse(value);
-
- Console.WriteLine(hash);
}
}
diff --git a/OnixLabs.Security.Cryptography.UnitTests/HashTests.cs b/OnixLabs.Security.Cryptography.UnitTests/HashTests.cs
index 4024f98..34b2408 100644
--- a/OnixLabs.Security.Cryptography.UnitTests/HashTests.cs
+++ b/OnixLabs.Security.Cryptography.UnitTests/HashTests.cs
@@ -36,6 +36,7 @@ public void HashShouldBeConstructableFromBytes()
// Then
Assert.Equal(expected, actual);
+ Assert.Equal(16, candidate.Length);
}
[Fact(DisplayName = "Hash should be constructable from byte and length")]
@@ -52,6 +53,7 @@ public void HashShouldBeConstructableFromByteAndLength()
// Then
Assert.Equal(expected, actual);
+ Assert.Equal(16, candidate.Length);
}
[Fact(DisplayName = "Hash value should not be modified when altering the original byte array")]
@@ -68,6 +70,7 @@ public void HashValueShouldNotBeModifiedWhenAlteringTheOriginalByteArray()
// Then
Assert.Equal(expected, actual);
+ Assert.Equal(4, candidate.Length);
}
[Fact(DisplayName = "Hash value should not be modified when altering the obtained byte array")]
@@ -83,6 +86,7 @@ public void HashValueShouldNotBeModifiedWhenAlteringTheObtainedByteArray()
// Then
Assert.Equal(expected, actual);
+ Assert.Equal(4, candidate.Length);
}
[Fact(DisplayName = "Identical default hash values should be considered equal")]
@@ -98,6 +102,9 @@ public void IdenticalDefaultHashValuesShouldBeConsideredEqual()
Assert.True(left.Equals(right));
Assert.True(left == right);
Assert.False(left != right);
+
+ Assert.Equal(0, left.Length);
+ Assert.Equal(0, right.Length);
}
[Fact(DisplayName = "Identical hash values should be considered equal")]
@@ -113,6 +120,9 @@ public void IdenticalHashValuesShouldBeConsideredEqual()
Assert.True(left.Equals(right));
Assert.True(left == right);
Assert.False(left != right);
+
+ Assert.Equal(4, left.Length);
+ Assert.Equal(4, right.Length);
}
[Fact(DisplayName = "Different hash values should not be considered equal")]
@@ -128,6 +138,9 @@ public void DifferentHashValuesShouldNotBeConsideredEqual()
Assert.False(left.Equals(right));
Assert.False(left == right);
Assert.True(left != right);
+
+ Assert.Equal(4, left.Length);
+ Assert.Equal(4, right.Length);
}
[Fact(DisplayName = "Identical hash values should produce identical hash codes")]
@@ -143,6 +156,9 @@ public void IdenticalHashValuesShouldProduceIdenticalHashCodes()
// Then
Assert.Equal(leftHashCode, rightHashCode);
+
+ Assert.Equal(4, left.Length);
+ Assert.Equal(4, right.Length);
}
[Fact(DisplayName = "Different hash values should produce different hash codes")]
@@ -158,6 +174,9 @@ public void DifferentHashValuesShouldProduceDifferentHashCodes()
// Then
Assert.NotEqual(leftHashCode, rightHashCode);
+
+ Assert.Equal(4, left.Length);
+ Assert.Equal(4, right.Length);
}
[Fact(DisplayName = "Hashes should produce a negative-one sort order when the left-hand hash is lesser than the right-hand hash")]
@@ -173,6 +192,9 @@ public void HashesShouldProduceANegativeOneSortOrderWhenTheLeftHandHashIsLesserT
// Then
Assert.Equal(expected, actual);
+
+ Assert.Equal(1, left.Length);
+ Assert.Equal(1, right.Length);
}
[Fact(DisplayName = "Hashes should produce a positive-one sort order when the left-hand hash is greater than the right-hand hash")]
@@ -188,6 +210,9 @@ public void HashesShouldProduceAPositiveOneSortOrderWhenTheLeftHandHashIsGreater
// Then
Assert.Equal(expected, actual);
+
+ Assert.Equal(1, left.Length);
+ Assert.Equal(1, right.Length);
}
[Fact(DisplayName = "Hashes should produce a zero sort order when the left-hand hash is equal to the right-hand hash")]
@@ -203,6 +228,9 @@ public void HashesShouldProduceAZeroSortOrderWhenTheLeftHandHashIsEqualToTheRigh
// Then
Assert.Equal(expected, actual);
+
+ Assert.Equal(1, left.Length);
+ Assert.Equal(1, right.Length);
}
[Theory(DisplayName = "Hash.Compute should produce the expected hash using a byte array")]
diff --git a/OnixLabs.Security.Cryptography.UnitTests/SaltTests.cs b/OnixLabs.Security.Cryptography.UnitTests/SaltTests.cs
index 49de23c..6274431 100644
--- a/OnixLabs.Security.Cryptography.UnitTests/SaltTests.cs
+++ b/OnixLabs.Security.Cryptography.UnitTests/SaltTests.cs
@@ -32,6 +32,7 @@ public void SaltShouldBeConstructableFromBytes()
// Then
Assert.Equal(expected, actual);
+ Assert.Equal(16, candidate.Length);
}
[Fact(DisplayName = "Salt value should not be modified when altering the original byte array")]
@@ -48,6 +49,7 @@ public void SaltValueShouldNotBeModifiedWhenAlteringTheOriginalByteArray()
// Then
Assert.Equal(expected, actual);
+ Assert.Equal(4, candidate.Length);
}
[Fact(DisplayName = "Salt value should not be modified when altering the obtained byte array")]
@@ -63,6 +65,7 @@ public void SaltValueShouldNotBeModifiedWhenAlteringTheObtainedByteArray()
// Then
Assert.Equal(expected, actual);
+ Assert.Equal(4, candidate.Length);
}
[Fact(DisplayName = "Identical default salt values should be considered equal")]
@@ -78,6 +81,9 @@ public void IdenticalDefaultSaltValuesShouldBeConsideredEqual()
Assert.True(left.Equals(right));
Assert.True(left == right);
Assert.False(left != right);
+
+ Assert.Equal(0, left.Length);
+ Assert.Equal(0, right.Length);
}
[Fact(DisplayName = "Identical salt values should be considered equal")]
@@ -93,6 +99,9 @@ public void IdenticalSaltValuesShouldBeConsideredEqual()
Assert.True(left.Equals(right));
Assert.True(left == right);
Assert.False(left != right);
+
+ Assert.Equal(4, left.Length);
+ Assert.Equal(4, right.Length);
}
[Fact(DisplayName = "Different salt values should not be considered equal")]
@@ -108,6 +117,9 @@ public void DifferentSaltValuesShouldNotBeConsideredEqual()
Assert.False(left.Equals(right));
Assert.False(left == right);
Assert.True(left != right);
+
+ Assert.Equal(4, left.Length);
+ Assert.Equal(4, right.Length);
}
[Fact(DisplayName = "Identical salt values should produce identical hash codes")]
@@ -123,6 +135,9 @@ public void IdenticalSaltValuesShouldProduceIdenticalSaltCodes()
// Then
Assert.Equal(leftHashCode, rightHashCode);
+
+ Assert.Equal(4, left.Length);
+ Assert.Equal(4, right.Length);
}
[Fact(DisplayName = "Different salt values should produce different hash codes")]
@@ -138,6 +153,9 @@ public void DifferentSaltValuesShouldProduceDifferentSaltCodes()
// Then
Assert.NotEqual(leftHashCode, rightHashCode);
+
+ Assert.Equal(4, left.Length);
+ Assert.Equal(4, right.Length);
}
[Fact(DisplayName = "Salt.Create should produce a salt of the specified length")]
@@ -149,6 +167,8 @@ public void SaltCreateShouldProduceASaltOfTheSpecifiedLength()
// Then
Assert.Equal(expected, candidate.AsReadOnlySpan().Length);
+
+ Assert.Equal(32, candidate.Length);
}
[Fact(DisplayName = "Salt.CreateNonZero should produce a salt of the specified length of non-zero bytes")]
@@ -161,5 +181,7 @@ public void SaltCreateNonZeroShouldProduceASaltOfTheSpecifiedLengthOfNonZeroByte
// Then
Assert.Equal(expected, candidate.AsReadOnlySpan().Length);
Assert.True(candidate.AsReadOnlySpan().ToArray().None(value => value is 0));
+
+ Assert.Equal(32, candidate.Length);
}
}
diff --git a/OnixLabs.Security.Cryptography/Hash.cs b/OnixLabs.Security.Cryptography/Hash.cs
index dbb38b1..171e342 100644
--- a/OnixLabs.Security.Cryptography/Hash.cs
+++ b/OnixLabs.Security.Cryptography/Hash.cs
@@ -23,7 +23,7 @@ namespace OnixLabs.Security.Cryptography;
/// Represents a cryptographic hash.
///
/// The underlying value of the cryptographic hash.
-public readonly partial struct Hash(ReadOnlySpan value) : ICryptoPrimitive, IValueComparable, ISpanParsable, ISpanBinaryConvertible
+public readonly partial struct Hash(ReadOnlySpan value) : ICryptoPrimitive, IValueComparable, ISpanParsable
{
///
/// Initializes a new instance of the struct.
@@ -42,4 +42,9 @@ public Hash(byte value, int length) : this(Enumerable.Repeat(value, length).ToAr
}
private readonly byte[] value = value.ToArray();
+
+ ///
+ /// Gets the length of the current in bytes.
+ ///
+ public int Length => value?.Length ?? 0;
}
diff --git a/OnixLabs.Security.Cryptography/MerkleTree.cs b/OnixLabs.Security.Cryptography/MerkleTree.cs
index 56b561b..7da96eb 100644
--- a/OnixLabs.Security.Cryptography/MerkleTree.cs
+++ b/OnixLabs.Security.Cryptography/MerkleTree.cs
@@ -13,14 +13,13 @@
// limitations under the License.
using System.Security.Cryptography;
-using OnixLabs.Core;
namespace OnixLabs.Security.Cryptography;
///
/// Represents a Merkle tree.
///
-public abstract partial class MerkleTree : ICryptoPrimitive, ISpanBinaryConvertible
+public abstract partial class MerkleTree : ICryptoPrimitive
{
///
/// Initializes a new instance of the class.
diff --git a/OnixLabs.Security.Cryptography/Salt.cs b/OnixLabs.Security.Cryptography/Salt.cs
index 1ca47db..e86db09 100644
--- a/OnixLabs.Security.Cryptography/Salt.cs
+++ b/OnixLabs.Security.Cryptography/Salt.cs
@@ -22,7 +22,7 @@ namespace OnixLabs.Security.Cryptography;
/// Represents a cryptographically secure random number, otherwise known as a salt value.
///
/// The underlying value of the salt.
-public readonly partial struct Salt(ReadOnlySpan value) : ICryptoPrimitive, ISpanBinaryConvertible
+public readonly partial struct Salt(ReadOnlySpan value) : ICryptoPrimitive
{
///
/// Initializes a new instance of the struct.
@@ -32,4 +32,9 @@ public readonly partial struct Salt(ReadOnlySpan value) : ICryptoPrimitive
public Salt(ReadOnlySequence value) : this(ReadOnlySpan.Empty) => value.CopyTo(out this.value);
private readonly byte[] value = value.ToArray();
+
+ ///
+ /// Gets the length of the current in bytes.
+ ///
+ public int Length => value?.Length ?? 0;
}