diff --git a/.editorconfig b/.editorconfig
index df8f9a8..1c42688 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,4 +1,13 @@
root = true
[*]
-max_line_length = 140
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = space
+indent_size = 4
+continuation_indent_size = 4
+max_line_length = 140
+
+# ReSharper properties
+resharper_csharp_wrap_lines = false
diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index fdee6ea..32f8ed7 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -19,7 +19,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 6.0.x
+ dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
diff --git a/.idea/.idea.onixlabs-dotnet/.idea/vcs.xml b/.idea/.idea.onixlabs-dotnet/.idea/vcs.xml
index 94a25f7..35eb1dd 100644
--- a/.idea/.idea.onixlabs-dotnet/.idea/vcs.xml
+++ b/.idea/.idea.onixlabs-dotnet/.idea/vcs.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/.run/Build & Test.run.xml b/.run/Build & Test.run.xml
new file mode 100644
index 0000000..35305ea
--- /dev/null
+++ b/.run/Build & Test.run.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/Run Playground.run.xml b/.run/Run Playground.run.xml
new file mode 100644
index 0000000..611820d
--- /dev/null
+++ b/.run/Run Playground.run.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OnixLabs.Core.UnitTests/MockData/Color.cs b/OnixLabs.Core.UnitTests.Data/Color.cs
similarity index 90%
rename from OnixLabs.Core.UnitTests/MockData/Color.cs
rename to OnixLabs.Core.UnitTests.Data/Color.cs
index 891e675..ec7f714 100644
--- a/OnixLabs.Core.UnitTests/MockData/Color.cs
+++ b/OnixLabs.Core.UnitTests.Data/Color.cs
@@ -1,18 +1,18 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-namespace OnixLabs.Core.UnitTests.MockData;
+namespace OnixLabs.Core.UnitTests.Data;
public sealed class Color : Enumeration
{
diff --git a/OnixLabs.Core.UnitTests.Data/Element.cs b/OnixLabs.Core.UnitTests.Data/Element.cs
new file mode 100644
index 0000000..1066640
--- /dev/null
+++ b/OnixLabs.Core.UnitTests.Data/Element.cs
@@ -0,0 +1,23 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace OnixLabs.Core.UnitTests.Data;
+
+public sealed class Element(int hashCode = 0)
+{
+ public bool Called { get; set; }
+ private int HashCode { get; } = hashCode;
+
+ public override int GetHashCode() => HashCode;
+}
diff --git a/OnixLabs.Core.UnitTests.Data/Numeric.cs b/OnixLabs.Core.UnitTests.Data/Numeric.cs
new file mode 100644
index 0000000..dc20316
--- /dev/null
+++ b/OnixLabs.Core.UnitTests.Data/Numeric.cs
@@ -0,0 +1,30 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Numerics;
+
+namespace OnixLabs.Core.UnitTests.Data;
+
+public sealed class Numeric(T value) : IEquatable> where T : INumber
+{
+ public T Value { get; } = value;
+
+ public bool Equals(Numeric? other) => other is not null && other.Value == Value;
+
+ public override bool Equals(object? obj) => obj is Numeric other && Equals(other);
+
+ public override int GetHashCode() => HashCode.Combine(Value);
+
+ public override string ToString() => this.ToRecordString();
+}
diff --git a/OnixLabs.Core.UnitTests.Data/OnixLabs.Core.UnitTests.Data.csproj b/OnixLabs.Core.UnitTests.Data/OnixLabs.Core.UnitTests.Data.csproj
new file mode 100644
index 0000000..da413fb
--- /dev/null
+++ b/OnixLabs.Core.UnitTests.Data/OnixLabs.Core.UnitTests.Data.csproj
@@ -0,0 +1,29 @@
+
+
+ net8.0
+ enable
+ enable
+
+ false
+
+ 12
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
diff --git a/OnixLabs.Core.UnitTests.Data/Record.cs b/OnixLabs.Core.UnitTests.Data/Record.cs
new file mode 100644
index 0000000..ff6927a
--- /dev/null
+++ b/OnixLabs.Core.UnitTests.Data/Record.cs
@@ -0,0 +1,17 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace OnixLabs.Core.UnitTests.Data;
+
+public sealed record Record(string Text, int Number, T Value);
diff --git a/OnixLabs.Core.UnitTests/ArrayExtensionTests.cs b/OnixLabs.Core.UnitTests/ArrayExtensionTests.cs
new file mode 100644
index 0000000..e53e0df
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/ArrayExtensionTests.cs
@@ -0,0 +1,65 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests;
+
+public sealed class ArrayExtensionTests
+{
+ [Fact(DisplayName = "Array.Copy should produce a copy of an array")]
+ public void CopyShouldProduceExpectedResult()
+ {
+ // Given
+ int[] array = [1, 2, 3, 4, 5];
+ int[] expected = [1, 2, 3, 4, 5];
+
+ // When
+ int[] actual = array.Copy();
+
+ // Then
+ Assert.Equal(expected, actual);
+ Assert.False(ReferenceEquals(array, actual));
+ }
+
+ [Fact(DisplayName = "Array.Copy with index and count parameters should produce a copy of an array")]
+ public void CopyWithParametersShouldProduceExpectedResult()
+ {
+ // Given
+ int[] array = [1, 2, 3, 4, 5];
+ int[] expected = [3, 4, 5];
+
+ // When
+ int[] actual = array.Copy(2, 3);
+
+ // Then
+ Assert.Equal(expected, actual);
+ Assert.False(ReferenceEquals(array, actual));
+ }
+
+ [Fact(DisplayName = "Array.ConcatenateWith should produce a concatenation of two arrays")]
+ public void ConcatenateWithShouldProduceExpectedResult()
+ {
+ // Given
+ int[] left = [1, 2, 3, 4, 5];
+ int[] right = [6, 7, 8, 9, 10];
+ int[] expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
+
+ // When
+ int[] actual = left.ConcatenateWith(right);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/EnumerationTests.cs b/OnixLabs.Core.UnitTests/EnumerationTests.cs
index 4d3dfd2..5ed15a8 100644
--- a/OnixLabs.Core.UnitTests/EnumerationTests.cs
+++ b/OnixLabs.Core.UnitTests/EnumerationTests.cs
@@ -1,11 +1,11 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -13,7 +13,7 @@
// limitations under the License.
using System.Collections.Generic;
-using OnixLabs.Core.UnitTests.MockData;
+using OnixLabs.Core.UnitTests.Data;
using Xunit;
namespace OnixLabs.Core.UnitTests;
@@ -23,32 +23,32 @@ public sealed class EnumerationTests
[Fact(DisplayName = "Enumerations should be equal")]
public void EnumerationsShouldBeEqual()
{
- // Arrange
+ // Given
Color a = Color.Red;
Color b = Color.Red;
- // Assert
+ // Then
Assert.Equal(a, b);
}
[Fact(DisplayName = "Enumerations should not be equal")]
public void EnumerationsShouldNotBeEqual()
{
- // Arrange
+ // Given
Color a = Color.Red;
Color b = Color.Blue;
- // Assert
+ // Then
Assert.NotEqual(a, b);
}
[Fact(DisplayName = "Enumeration should return all enumeration instances")]
public void EnumerationsShouldReturnAllEnumerationInstances()
{
- // Arrange
+ // Given
IEnumerable colors = Color.GetAll();
- // Assert
+ // Then
Assert.Contains(colors, item => item == Color.Red);
Assert.Contains(colors, item => item == Color.Green);
Assert.Contains(colors, item => item == Color.Blue);
@@ -57,30 +57,30 @@ public void EnumerationsShouldReturnAllEnumerationInstances()
[Fact(DisplayName = "Enumeration.FromName should return the expected enumeration entry")]
public void EnumerationFromNameShouldReturnTheExpectedEnumerationEntry()
{
- // Arrange
+ // Given
Color color = Color.FromName("Green");
- // Assert
+ // Then
Assert.Equal(Color.Green, color);
}
[Fact(DisplayName = "Enumeration.FromValue should return the expected enumeration entry")]
public void EnumerationFromValueShouldReturnTheExpectedEnumerationEntry()
{
- // Arrange
+ // Given
Color color = Color.FromValue(2);
- // Assert
+ // Then
Assert.Equal(Color.Green, color);
}
[Fact(DisplayName = "Enumeration.GetAll should return all enumeration entries")]
public void EnumerationGetAllShouldReturnAllEnumerationEntries()
{
- // Arrange
+ // Given
IEnumerable entries = Color.GetAll();
- // Assert
+ // Then
Assert.Contains(Color.Blue, entries);
Assert.Contains(Color.Green, entries);
Assert.Contains(Color.Red, entries);
@@ -89,10 +89,10 @@ public void EnumerationGetAllShouldReturnAllEnumerationEntries()
[Fact(DisplayName = "Enumeration.GetEntries should return all enumeration entries")]
public void EnumerationGetEntriesShouldReturnAllEnumerationEntries()
{
- // Arrange
+ // Given
IEnumerable<(int Value, string Name)> entries = Color.GetEntries();
- // Assert
+ // Then
Assert.Contains(Color.Blue.ToEntry(), entries);
Assert.Contains(Color.Green.ToEntry(), entries);
Assert.Contains(Color.Red.ToEntry(), entries);
@@ -101,10 +101,10 @@ public void EnumerationGetEntriesShouldReturnAllEnumerationEntries()
[Fact(DisplayName = "Enumeration.GetNames should return all enumeration names")]
public void EnumerationGetNamesShouldReturnAllEnumerationNames()
{
- // Arrange
+ // Given
IEnumerable entries = Color.GetNames();
- // Assert
+ // Then
Assert.Contains(Color.Blue.Name, entries);
Assert.Contains(Color.Green.Name, entries);
Assert.Contains(Color.Red.Name, entries);
@@ -113,12 +113,40 @@ public void EnumerationGetNamesShouldReturnAllEnumerationNames()
[Fact(DisplayName = "Enumeration.GetValues should return all enumeration values")]
public void EnumerationGetValuesShouldReturnAllEnumerationValues()
{
- // Arrange
+ // Given
IEnumerable entries = Color.GetValues();
- // Assert
+ // Then
Assert.Contains(Color.Blue.Value, entries);
Assert.Contains(Color.Green.Value, entries);
Assert.Contains(Color.Red.Value, entries);
}
-}
\ No newline at end of file
+
+ [Fact(DisplayName = "Enumeration.CompareTo as Enumeration should return the correct value")]
+ public void EnumerationCompareToAsEnumerationShouldReturnTheCorrectValue()
+ {
+ // Given
+ Color left = Color.Red;
+ Color right = Color.Blue;
+
+ // When
+ int actual = left.CompareTo(right);
+
+ // Then
+ Assert.Equal(-1, actual);
+ }
+
+ [Fact(DisplayName = "Enumeration.CompareTo as Object should return the correct value")]
+ public void EnumerationCompareToAsObjectShouldReturnTheCorrectValue()
+ {
+ // Given
+ Color left = Color.Red;
+ object right = Color.Blue;
+
+ // When
+ int actual = left.CompareTo(right);
+
+ // Then
+ Assert.Equal(-1, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Linq/IEnumerableExtensionTests.cs b/OnixLabs.Core.UnitTests/Linq/IEnumerableExtensionTests.cs
new file mode 100644
index 0000000..84280fe
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Linq/IEnumerableExtensionTests.cs
@@ -0,0 +1,490 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using OnixLabs.Core.Linq;
+using OnixLabs.Core.UnitTests.Data;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Linq;
+
+// ReSharper disable InconsistentNaming
+public sealed class IEnumerableExtensionTests
+{
+ [Fact(DisplayName = "IEnumerable.AllEqualBy should return true when all items are equal by the same property")]
+ public void AllEqualByShouldProduceExpectedResultTrue()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("abc", 123, Guid.NewGuid());
+ Record element3 = new("abc", 123, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+
+ // When
+ bool result = elements.AllEqualBy(element => element.Text);
+
+ // Then
+ Assert.True(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.AllEqualBy should return false when all items are not equal by the same property")]
+ public void AllEqualByShouldProduceExpectedResultFalse()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("abc", 123, Guid.NewGuid());
+ Record element3 = new("xyz", 123, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+
+ // When
+ bool result = elements.AllEqualBy(element => element.Text);
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.AnyEqualBy should return true when any items are equal by the same property")]
+ public void AnyEqualByShouldProduceExpectedResultTrue()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("abc", 123, Guid.NewGuid());
+ Record element3 = new("xyz", 123, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+
+ // When
+ bool result = elements.AnyEqualBy(element => element.Text);
+
+ // Then
+ Assert.True(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.AnyEqualBy should return false when any items are not equal by the same property")]
+ public void AnyEqualByShouldProduceExpectedResultFalse()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("def", 123, Guid.NewGuid());
+ Record element3 = new("xyz", 123, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+
+ // When
+ bool result = elements.AnyEqualBy(element => element.Text);
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.CountNot should produce the expected result.")]
+ public void CountNotShouldProduceExpectedResult()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("def", 123, Guid.NewGuid());
+ Record element3 = new("xyz", 456, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+ const int expected = 2;
+
+ // When
+ int actual = elements.CountNot(element => element.Number == 456);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.ForEach should iterate over every element in the enumerable")]
+ public void ForEachShouldProduceExpectedResult()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element(), new Element(), new Element() };
+
+ // When
+ enumerable.ForEach(element => element.Called = true);
+
+ // Then
+ Assert.All(enumerable, element => Assert.True(element.Called));
+ }
+
+ [Fact(DisplayName = "IEnumerable.GetContentHashCode should produce equal hash codes")]
+ public void GetContentHashCodeShouldProduceExpectedResultEqual()
+ {
+ // Given
+ IEnumerable enumerable1 = new[] { new Element(1), new Element(2), new Element(3) };
+ IEnumerable enumerable2 = new[] { new Element(1), new Element(2), new Element(3) };
+
+ // When
+ int hashCode1 = enumerable1.GetContentHashCode();
+ int hashCode2 = enumerable2.GetContentHashCode();
+
+ // Then
+ Assert.Equal(hashCode1, hashCode2);
+ }
+
+ [Fact(DisplayName = "IEnumerable.GetContentHashCode should produce different hash codes")]
+ public void GetContentHashCodeShouldProduceExpectedResultDifferent()
+ {
+ // Given
+ IEnumerable enumerable1 = new[] { new Element(1), new Element(2), new Element(3) };
+ IEnumerable enumerable2 = new[] { new Element(3), new Element(2), new Element(1) };
+
+ // When
+ int hashCode1 = enumerable1.GetContentHashCode();
+ int hashCode2 = enumerable2.GetContentHashCode();
+
+ // Then
+ Assert.NotEqual(hashCode1, hashCode2);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsEmpty should return true when the enumerable is empty")]
+ public void IsEmptyShouldProduceExpectedResultTrue()
+ {
+ // Given
+ IEnumerable enumerable = Enumerable.Empty();
+
+ // When
+ bool result = enumerable.IsEmpty();
+
+ // Then
+ Assert.True(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsEmpty should return false when the enumerable is not empty")]
+ public void IsEmptyShouldProduceExpectedResultFalse()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element() };
+
+ // When
+ bool result = enumerable.IsEmpty();
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsNotEmpty should return true when the enumerable is not empty")]
+ public void IsNotEmptyShouldProduceExpectedResultTrue()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element() };
+
+ // When
+ bool result = enumerable.IsNotEmpty();
+
+ // Then
+ Assert.True(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsNotEmpty should return false when the enumerable is empty")]
+ public void IsNotEmptyShouldProduceExpectedResultFalse()
+ {
+ // Given
+ IEnumerable enumerable = Enumerable.Empty();
+
+ // When
+ bool result = enumerable.IsNotEmpty();
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsSingle should return true when the enumerable contains a single element")]
+ public void IsSingleShouldProduceExpectedResultTrue()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element() };
+
+ // When
+ bool result = enumerable.IsSingle();
+
+ // Then
+ Assert.True(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsSingle should return false when the enumerable is empty")]
+ public void IsSingleShouldProduceExpectedResultFalseWhenEmpty()
+ {
+ // Given
+ IEnumerable enumerable = Enumerable.Empty();
+
+ // When
+ bool result = enumerable.IsSingle();
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsSingle should return false when the enumerable contains more than one element")]
+ public void IsSingleShouldProduceExpectedResultFalseWhenMoreThanOneElement()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element(), new Element() };
+
+ // When
+ bool result = enumerable.IsSingle();
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsCountEven should return true when the enumerable contains an even number of elements")]
+ public void IsCountEvenShouldProduceExpectedResultTrue()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element(), new Element() };
+
+ // When
+ bool result = enumerable.IsCountEven();
+
+ // Then
+ Assert.True(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsCountEven should return false when the enumerable contains an odd number of elements")]
+ public void IsCountEvenShouldProduceExpectedResultFalse()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element() };
+
+ // When
+ bool result = enumerable.IsCountEven();
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsCountOdd should return true when the enumerable contains an odd number of elements")]
+ public void IsCountOddShouldProduceExpectedResultTrue()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element() };
+
+ // When
+ bool result = enumerable.IsCountOdd();
+
+ // Then
+ Assert.True(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.IsCountOdd should return false when the enumerable contains an even number of elements")]
+ public void IsCountOddShouldProduceExpectedResultFalse()
+ {
+ // Given
+ IEnumerable enumerable = new[] { new Element(), new Element() };
+
+ // When
+ bool result = enumerable.IsCountOdd();
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.JoinToString should produce the expected result with the default separator")]
+ public void JoinToStringShouldProduceExpectedResultWithDefaultSeparator()
+ {
+ // Given
+ IEnumerable enumerable = new object[] { 1, 2, 3, 4.5, true, false };
+ const string expected = "1, 2, 3, 4.5, True, False";
+
+ // When
+ string actual = enumerable.JoinToString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.JoinToString should produce the expected result with a custom separator")]
+ public void JoinToStringShouldProduceExpectedResultWithCustomSeparator()
+ {
+ // Given
+ IEnumerable enumerable = new object[] { 1, 2, 3, 4.5, true, false };
+ const string expected = "1 *$ 2 *$ 3 *$ 4.5 *$ True *$ False";
+
+ // When
+ string actual = enumerable.JoinToString(" *$ ");
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.None should return true when none of the elements satisfy the specified predicate condition")]
+ public void NoneShouldProduceExpectedResultTrue()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("def", 456, Guid.NewGuid());
+ Record element3 = new("xyz", 789, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+
+ // When
+ bool result = elements.None(element => element.Number == 0);
+
+ // Then
+ Assert.True(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.None should return false when any of the elements satisfy the specified predicate condition")]
+ public void NoneShouldProduceExpectedResultFalseAny()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("def", 456, Guid.NewGuid());
+ Record element3 = new("xyz", 0, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+
+ // When
+ bool result = elements.None(element => element.Number == 0);
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.None should return false when all of the elements satisfy the specified predicate condition")]
+ public void NoneShouldProduceExpectedResultFalseAll()
+ {
+ // Given
+ Record element1 = new("abc", 0, Guid.NewGuid());
+ Record element2 = new("def", 0, Guid.NewGuid());
+ Record element3 = new("xyz", 0, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+
+ // When
+ bool result = elements.None(element => element.Number == 0);
+
+ // Then
+ Assert.False(result);
+ }
+
+ [Fact(DisplayName = "IEnumerable.Sum should produce the expected result")]
+ public void SumShouldProduceExpectedResult()
+ {
+ // Given
+ IEnumerable elements = [12.34m, 34.56m, 56.78m];
+ const decimal expected = 103.68m;
+
+ // When
+ decimal actual = elements.Sum();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.Sum with selector should produce the expected result")]
+ public void SumWithSelectorShouldProduceExpectedResult()
+ {
+ // Given
+ Numeric element1 = new(1234.567m);
+ Numeric element2 = new(890.1234m);
+ Numeric element3 = new(56.78901m);
+ IEnumerable> elements = [element1, element2, element3];
+ const decimal expected = 2181.47941m;
+
+ // When
+ decimal actual = elements.SumBy(element => element.Value);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.WhereNot should produce the expected result")]
+ public void WhereNotShouldProduceExpectedResult()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("def", 456, Guid.NewGuid());
+ Record element3 = new("xyz", 789, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, element3 };
+ IEnumerable> expected = new[] { element2, element3 };
+
+ // When
+ IEnumerable> actual = elements.WhereNot(element => element.Number == 123);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.WhereNotNull should produce the expected result")]
+ public void WhereNotNullShouldProduceExpectedResult()
+ {
+ // Given
+ Record element1 = new("abc", 123, Guid.NewGuid());
+ Record element2 = new("def", 456, Guid.NewGuid());
+ IEnumerable> elements = new[] { element1, element2, null };
+ IEnumerable> expected = new[] { element1, element2 };
+
+ // When
+ IEnumerable> actual = elements.WhereNotNull();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.ToCollectionString should produce expected result (Object)")]
+ public void ToCollectionStringShouldProduceExpectedResultObject()
+ {
+ // Given
+ object[] values = [123, "abc", true, 123.456];
+ const string expected = "[123, abc, True, 123.456]";
+
+ // When
+ string actual = values.ToCollectionString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.ToCollectionString should produce expected result (String)")]
+ public void ToCollectionStringShouldProduceExpectedResultString()
+ {
+ // Given
+ string[] values = ["abc", "xyz", "123"];
+ const string expected = "[abc, xyz, 123]";
+
+ // When
+ string actual = values.ToCollectionString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.ToCollectionString should produce expected result (Int32)")]
+ public void ToCollectionStringShouldProduceExpectedResultInt32()
+ {
+ // Given
+ int[] values = [0, 1, 12, 123, 1234, -1, -12, -123, -1234];
+ const string expected = "[0, 1, 12, 123, 1234, -1, -12, -123, -1234]";
+
+ // When
+ string actual = values.ToCollectionString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "IEnumerable.ToCollectionString should produce expected result (Int32, IFormattable)")]
+ public void ToCollectionStringShouldProduceExpectedResultInt32IFormattable()
+ {
+ // Given
+ int[] values = [0, 1, 12, 123, 1234, -1, -12, -123, -1234];
+ const string expected = "[£0.00, £1.00, £12.00, £123.00, £1,234.00, -£1.00, -£12.00, -£123.00, -£1,234.00]";
+
+ // When
+ string actual = values.ToCollectionString("C", CultureInfo.GetCultureInfo("en-GB"));
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/ObjectExtensionTests.cs b/OnixLabs.Core.UnitTests/ObjectExtensionTests.cs
new file mode 100644
index 0000000..4492516
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/ObjectExtensionTests.cs
@@ -0,0 +1,36 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using OnixLabs.Core.UnitTests.Data;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests;
+
+public sealed class ObjectExtensionTests
+{
+ [Fact(DisplayName = "Object.ToRecordString should produce a record formatted string")]
+ public void ToRecordStringShouldProduceExpectedResult()
+ {
+ // Given
+ Record record = new("abc", 123, Guid.NewGuid());
+ string expected = record.ToString();
+
+ // When
+ string actual = record.ToRecordString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/OnixLabs.Core.UnitTests.csproj b/OnixLabs.Core.UnitTests/OnixLabs.Core.UnitTests.csproj
index 0ec43ac..2a9f528 100644
--- a/OnixLabs.Core.UnitTests/OnixLabs.Core.UnitTests.csproj
+++ b/OnixLabs.Core.UnitTests/OnixLabs.Core.UnitTests.csproj
@@ -1,28 +1,26 @@
-
- net6.0
-
+ net8.0
false
-
- 10
+ 12
-
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
-
+
+
+
+
+
-
diff --git a/OnixLabs.Core.UnitTests/PreconditionTests.cs b/OnixLabs.Core.UnitTests/PreconditionTests.cs
index 8331dc2..0cb7b4b 100644
--- a/OnixLabs.Core.UnitTests/PreconditionTests.cs
+++ b/OnixLabs.Core.UnitTests/PreconditionTests.cs
@@ -1,11 +1,11 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -14,21 +14,58 @@
using System;
using Xunit;
-using static OnixLabs.Core.Preconditions;
namespace OnixLabs.Core.UnitTests;
public sealed class PreconditionTests
{
[Fact(DisplayName = "Check should throw an ArgumentException when the condition is false")]
- public void CheckShouldThrowAnArgumentExceptionWhenTheConditionIsFalse()
+ public void CheckShouldProduceExpectedResult()
{
- Assert.Throws(() => Check(false));
+ // When
+ InvalidOperationException exception = Assert.Throws(() => Check(false));
+
+ // Then
+ Assert.Equal("Check failed.", exception.Message);
}
[Fact(DisplayName = "CheckNotNull should throw an ArgumentNullException when the condition is null")]
- public void CheckNotNullShouldThrowAnArgumentNullExceptionWhenTheConditionIsNull()
+ public void CheckNotNullShouldProduceExpectedResult()
+ {
+ // When
+ InvalidOperationException exception = Assert.Throws(() => CheckNotNull(null));
+
+ // Then
+ Assert.Equal("Argument must not be null.", exception.Message);
+ }
+
+ [Fact(DisplayName = "Require should throw an ArgumentException when the condition is false")]
+ public void RequireShouldProduceExpectedResult()
+ {
+ // When
+ ArgumentException exception = Assert.Throws(() => Require(false));
+
+ // Then
+ Assert.Equal("Argument requirement failed.", exception.Message);
+ }
+
+ [Fact(DisplayName = "RequireWithinRange should throw an ArgumentOutOfRangeException when the condition is false")]
+ public void RequireWithinRangeShouldProduceExpectedResult()
{
- Assert.Throws(() => CheckNotNull(null));
+ // When
+ ArgumentOutOfRangeException exception = Assert.Throws(() => RequireWithinRange(false));
+
+ // Then
+ Assert.Equal("Argument is out of range.", exception.Message);
+ }
+
+ [Fact(DisplayName = "RequireNotNull should throw an ArgumentNullException when the condition is null")]
+ public void RequireNotNullShouldProduceExpectedResult()
+ {
+ // When
+ ArgumentNullException exception = Assert.Throws(() => RequireNotNull(null));
+
+ // Then
+ Assert.Equal("Argument must not be null.", exception.Message);
}
}
diff --git a/OnixLabs.Core.UnitTests/Reflection/TypeExtensionTests.cs b/OnixLabs.Core.UnitTests/Reflection/TypeExtensionTests.cs
new file mode 100644
index 0000000..063e94d
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Reflection/TypeExtensionTests.cs
@@ -0,0 +1,36 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using OnixLabs.Core.Reflection;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Reflection;
+
+public sealed class TypeExtensionTests
+{
+ [Theory(DisplayName = "Type.GetName should produce the expected result")]
+ [InlineData(typeof(object), "Object")]
+ [InlineData(typeof(List<>), "List")]
+ [InlineData(typeof(Dictionary<,>), "Dictionary")]
+ public void TypeGetNameShouldProduceExpectedResult(Type type, string expected)
+ {
+ // When
+ string actual = type.GetName();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/StringExtensionTests.cs b/OnixLabs.Core.UnitTests/StringExtensionTests.cs
index 2908b43..aea70b5 100644
--- a/OnixLabs.Core.UnitTests/StringExtensionTests.cs
+++ b/OnixLabs.Core.UnitTests/StringExtensionTests.cs
@@ -1,139 +1,202 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+using System;
+using System.Globalization;
using Xunit;
namespace OnixLabs.Core.UnitTests;
public sealed class StringExtensionTests
{
- [Theory(DisplayName = "SubstringBefore should return the expected result (char)")]
+ [Theory(DisplayName = "String.Repeat should return the expected result")]
+ [InlineData("0", 10, "0000000000")]
+ [InlineData("Abc1", 3, "Abc1Abc1Abc1")]
+ public void RepeatShouldProduceExpectedResult(string value, int count, string expected)
+ {
+ // When
+ string actual = value.Repeat(count);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "String.SubstringBeforeFirst should return the string before the first delimiter")]
[InlineData("First:Second", "First", ':')]
[InlineData("12345+678910", "12345", '+')]
- public void SubstringBeforeShouldReturnTheExpectedResultChar(string value, string expected, char delimiter)
+ public void SubstringBeforeFirstShouldProduceExpectedResultChar(string value, string expected, char delimiter)
{
- // Arrange / Act
- string actual = value.SubstringBefore(delimiter);
+ // When
+ string actual = value.SubstringBeforeFirst(delimiter);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "SubstringBefore should return the expected result (string)")]
+ [Theory(DisplayName = "String.SubstringBeforeFirst should return the string before the first delimiter")]
[InlineData("First:Second", "First", ":")]
[InlineData("12345+678910", "12345", "+")]
- public void SubstringBeforeShouldReturnTheExpectedResultString(string value, string expected, string delimiter)
+ public void SubstringBeforeFirstShouldProduceExpectedResultString(string value, string expected, string delimiter)
{
- // Arrange / Act
- string actual = value.SubstringBefore(delimiter);
+ // When
+ string actual = value.SubstringBeforeFirst(delimiter);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "SubstringBeforeLast should return the expected result (char)")]
+ [Theory(DisplayName = "String.SubstringBeforeLast should return the string before the last char delimiter")]
[InlineData("First:Second:Third", "First:Second", ':')]
[InlineData("12345+678910+12345", "12345+678910", '+')]
- public void SubstringBeforeLastShouldReturnTheExpectedResultChar(string value, string expected, char delimiter)
+ public void SubstringBeforeLastShouldProduceExpectedResultChar(string value, string expected, char delimiter)
{
- // Arrange / Act
+ // When
string actual = value.SubstringBeforeLast(delimiter);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "SubstringBeforeLast should return the expected result (string)")]
+ [Theory(DisplayName = "String.SubstringBeforeLast should return the string before the last string delimiter")]
[InlineData("First:Second:Third", "First:Second", ":")]
[InlineData("12345+678910+12345", "12345+678910", "+")]
- public void SubstringBeforeLastShouldReturnTheExpectedResultString(string value, string expected, string delimiter)
+ public void SubstringBeforeLastShouldProduceExpectedResultString(string value, string expected, string delimiter)
{
- // Arrange / Act
+ // When
string actual = value.SubstringBeforeLast(delimiter);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "SubstringAfter should return the expected result (char)")]
+ [Theory(DisplayName = "String.SubstringAfterFirst should return the string after the first char delimiter")]
[InlineData("First:Second", "Second", ':')]
[InlineData("12345+678910", "678910", '+')]
- public void SubstringAfterShouldReturnTheExpectedResultChar(string value, string expected, char delimiter)
+ public void SubstringAfterFirstShouldProduceExpectedResultChar(string value, string expected, char delimiter)
{
- // Arrange / Act
- string actual = value.SubstringAfter(delimiter);
+ // When
+ string actual = value.SubstringAfterFirst(delimiter);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "SubstringAfter should return the expected result (string)")]
+ [Theory(DisplayName = "String.SubstringAfterFirst should return the string after the first string delimiter")]
[InlineData("First:Second", "Second", ":")]
[InlineData("12345+678910", "678910", "+")]
- public void SubstringAfterShouldReturnTheExpectedResultString(string value, string expected, string delimiter)
+ public void SubstringAfterFirstShouldProduceExpectedResultString(string value, string expected, string delimiter)
{
- // Arrange / Act
- string actual = value.SubstringAfter(delimiter);
+ // When
+ string actual = value.SubstringAfterFirst(delimiter);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "SubstringAfterLast should return the expected result (char)")]
+ [Theory(DisplayName = "String.SubstringAfterLast should return the string after the last char delimiter")]
[InlineData("First:Second:Third", "Third", ':')]
[InlineData("12345+678910+12345", "12345", '+')]
- public void SubstringAfterLastShouldReturnTheExpectedResultChar(string value, string expected, char delimiter)
+ public void SubstringAfterLastShouldProduceExpectedResultChar(string value, string expected, char delimiter)
{
- // Arrange / Act
+ // When
string actual = value.SubstringAfterLast(delimiter);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "SubstringAfterLast should return the expected result (string)")]
+ [Theory(DisplayName = "String.SubstringAfterLast should return the the string after the last string delimiter")]
[InlineData("First:Second:Third", "Third", ":")]
[InlineData("12345+678910+12345", "12345", "+")]
- public void SubstringAfterLastShouldReturnTheExpectedResultString(string value, string expected, string delimiter)
+ public void SubstringAfterLastShouldProduceExpectedResultString(string value, string expected, string delimiter)
{
- // Arrange / Act
+ // When
string actual = value.SubstringAfterLast(delimiter);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "ToByteArray should return the expected result")]
- [InlineData("Hello, World!", new byte[] {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21})]
- public void ToByteArrayShouldReturnTheExpectedResult(string value, byte[] expected)
+ [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)
{
- // Arrange / Act
+ // When
byte[] actual = value.ToByteArray();
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "Wrap should return the expected result")]
+ [Theory(DisplayName = "String.ToDateTime should return the DateTime equivalent of the current string")]
+ [InlineData("0001-01-01T00:00:00Z", 1, 1, 1, 0, 0, 0)]
+ [InlineData("1970-01-01T00:00:00Z", 1970, 1, 1, 0, 0, 0)]
+ [InlineData("9999-12-31T23:59:59Z", 9999, 12, 31, 23, 59, 59)]
+ public void ToDateTimeShouldProduceExpectedResult(string value, int year, int month, int day, int hour, int minute, int second)
+ {
+ // When
+ // AdjustToUniversal is essential, otherwise the tests may pass locally but fail on a build server in another time-zone.
+ DateTime actual = value.ToDateTime(styles: DateTimeStyles.AdjustToUniversal);
+
+ // Then
+ Assert.Equal(year, actual.Year);
+ Assert.Equal(month, actual.Month);
+ Assert.Equal(day, actual.Day);
+ Assert.Equal(hour, actual.Hour);
+ Assert.Equal(minute, actual.Minute);
+ Assert.Equal(second, actual.Second);
+ }
+
+ [Theory(DisplayName = "String.ToDateOnly should return the DateOnly equivalent of the current string")]
+ [InlineData("0001-01-01", 1, 1, 1)]
+ [InlineData("1970-01-01", 1970, 1, 1)]
+ [InlineData("9999-12-31", 9999, 12, 31)]
+ public void ToDateOnlyShouldProduceExpectedResult(string value, int year, int month, int day)
+ {
+ // When
+ DateOnly actual = value.ToDateOnly();
+
+ // Then
+ Assert.Equal(year, actual.Year);
+ Assert.Equal(month, actual.Month);
+ Assert.Equal(day, actual.Day);
+ }
+
+ [Theory(DisplayName = "String.ToTimeOnly should return the TimeOnly equivalent of the current string")]
+ [InlineData("00:00:00", 0, 0, 0)]
+ [InlineData("01:01:01", 1, 1, 1)]
+ [InlineData("23:59:59", 23, 59, 59)]
+ public void ToTimeOnlyShouldProduceExpectedResult(string value, int hour, int minute, int second)
+ {
+ // When
+ TimeOnly actual = value.ToTimeOnly();
+
+ // Then
+ Assert.Equal(hour, actual.Hour);
+ Assert.Equal(minute, actual.Minute);
+ Assert.Equal(second, actual.Second);
+ }
+
+ [Theory(DisplayName = "String.Wrap should wrap the current string value between the before and after string values")]
[InlineData("<", "value", ">", "")]
[InlineData("BEFORE:", "value", ":AFTER", "BEFORE:value:AFTER")]
- public void WrapShouldReturnTheExpectedResult(string before, string value, string after, string expected)
+ public void WrapShouldProduceExpectedResult(string before, string value, string after, string expected)
{
- // Arrange / Act
+ // When
string actual = value.Wrap(before, after);
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
}
diff --git a/OnixLabs.Core.UnitTests/Text/Base16CodecInvariantTests.cs b/OnixLabs.Core.UnitTests/Text/Base16CodecInvariantTests.cs
new file mode 100644
index 0000000..1e99222
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base16CodecInvariantTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base16CodecInvariantTests
+{
+ [Theory(DisplayName = "Base16Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","4142434445464748494a4b4c4d4e4f505152535455565758595a")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","6162636465666768696a6b6c6d6e6f707172737475767778797a")]
+ [InlineData("0123456789","30313233343536373839")]
+ public void Base16CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base16;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base16FormatProvider.Invariant);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base16Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("4142434445464748494a4b4c4d4e4f505152535455565758595a","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("6162636465666768696a6b6c6d6e6f707172737475767778797a","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("30313233343536373839","0123456789")]
+ public void Base16CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base16;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base16FormatProvider.Invariant);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base16CodecLowercaseTests.cs b/OnixLabs.Core.UnitTests/Text/Base16CodecLowercaseTests.cs
new file mode 100644
index 0000000..a7a26c5
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base16CodecLowercaseTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base16CodecLowercaseTests
+{
+ [Theory(DisplayName = "Base16Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","4142434445464748494a4b4c4d4e4f505152535455565758595a")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","6162636465666768696a6b6c6d6e6f707172737475767778797a")]
+ [InlineData("0123456789","30313233343536373839")]
+ public void Base16CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base16;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base16FormatProvider.Lowercase);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base16Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("4142434445464748494a4b4c4d4e4f505152535455565758595a","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("6162636465666768696a6b6c6d6e6f707172737475767778797a","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("30313233343536373839","0123456789")]
+ public void Base16CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base16;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base16FormatProvider.Lowercase);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base16CodecUppercaseTests.cs b/OnixLabs.Core.UnitTests/Text/Base16CodecUppercaseTests.cs
new file mode 100644
index 0000000..4176c93
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base16CodecUppercaseTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base16CodecUppercaseTests
+{
+ [Theory(DisplayName = "Base16Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","4142434445464748494A4B4C4D4E4F505152535455565758595A")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","6162636465666768696A6B6C6D6E6F707172737475767778797A")]
+ [InlineData("0123456789","30313233343536373839")]
+ public void Base16CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base16;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base16FormatProvider.Uppercase);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base16Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("4142434445464748494A4B4C4D4E4F505152535455565758595A","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("6162636465666768696A6B6C6D6E6F707172737475767778797A","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("30313233343536373839","0123456789")]
+ public void Base16CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base16;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base16FormatProvider.Uppercase);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base16Tests.cs b/OnixLabs.Core.UnitTests/Text/Base16Tests.cs
index 2d5cc56..b7216ef 100644
--- a/OnixLabs.Core.UnitTests/Text/Base16Tests.cs
+++ b/OnixLabs.Core.UnitTests/Text/Base16Tests.cs
@@ -1,17 +1,18 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+using System.Text;
using OnixLabs.Core.Text;
using Xunit;
@@ -19,50 +20,100 @@ namespace OnixLabs.Core.UnitTests.Text;
public sealed class Base16Tests
{
- [Fact(DisplayName = "Identical Base16 values produce identical hash codes.")]
- public void IdenticalBase16ValuesProduceIdenticalHashCodes()
+ [Fact(DisplayName = "Base16 should not change when modifying the original byte array")]
+ public void Base16ShouldNotChangeWhenModifyingOriginalByteArray()
{
- // Arrange
- Base16 a = Base16.FromString("abcdefghijklmnopqrstuvwxyz");
- Base16 b = Base16.FromString("abcdefghijklmnopqrstuvwxyz");
+ // Given
+ byte[] bytes = "ABCabc123".ToByteArray();
+ Base16 candidate = new(bytes);
+ const string expected = "414243616263313233";
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
+ // When
+ bytes[0] = 0;
+ string actual = candidate.ToString();
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
+ // Then
+ Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "Base16_FromString should produce the expected Base-16 value.")]
- [InlineData("31323334353637383930", "1234567890")]
- [InlineData("4142434445464748494a4b4c4d4e4f505152535455565758595a", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("6162636465666768696a6b6c6d6e6f707172737475767778797a", "abcdefghijklmnopqrstuvwxyz")]
- public void Base16FromStringShouldProduceTheExpectedBase16Value(string expected, string value)
+ [Fact(DisplayName = "Base16 should not change when modifying the obtained byte array")]
+ public void Base16ShouldNotChangeWhenModifyingObtainedByteArray()
{
- // Arrange
- Base16 candidate = Base16.FromString(value);
+ // Given
+ Base16 candidate = new("ABCabc123".ToByteArray());
+ const string expected = "414243616263313233";
- // Act
+ // When
+ byte[] bytes = candidate.ToByteArray();
+ bytes[0] = 0;
string actual = candidate.ToString();
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "Base16_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "31323334353637383930")]
- [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "4142434445464748494a4b4c4d4e4f505152535455565758595a")]
- [InlineData("abcdefghijklmnopqrstuvwxyz", "6162636465666768696a6b6c6d6e6f707172737475767778797a")]
- public void Base16ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
+ [Fact(DisplayName = "Base16 values should be identical")]
+ public void Base16ValuesShouldBeIdentical()
{
- // Arrange
+ // Given
+ Base16 a = new([0, 255]);
+ Base16 b = new([0, 255]);
+
+ // Then
+ Assert.Equal(a, b);
+ Assert.Equal(a.GetHashCode(), b.GetHashCode());
+ Assert.True(a.Equals(b));
+ Assert.True(a == b);
+ Assert.False(a != b);
+ }
+
+ [Fact(DisplayName = "Base16 values should not be identical")]
+ public void Base16ValuesShouldNotBeIdentical()
+ {
+ // Given
+ Base16 a = new([0, 255]);
+ Base16 b = new([1, 127]);
+
+ // Then
+ Assert.NotEqual(a, b);
+ Assert.NotEqual(a.GetHashCode(), b.GetHashCode());
+ Assert.False(a.Equals(b));
+ Assert.False(a == b);
+ Assert.True(a != b);
+ }
+
+ [Theory(DisplayName = "Base16.Parse should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("4142434445464748494a4b4c4d4e4f505152535455565758595a","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("6162636465666768696a6b6c6d6e6f707172737475767778797a","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("30313233343536373839","0123456789")]
+ public void Base16ParseShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
Base16 candidate = Base16.Parse(value);
- // Act
- string actual = candidate.ToPlainTextString();
+ // When
+ string actual = Encoding.UTF8.GetString(candidate.ToByteArray());
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base16.ToString should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","4142434445464748494a4b4c4d4e4f505152535455565758595a")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","6162636465666768696a6b6c6d6e6f707172737475767778797a")]
+ [InlineData("0123456789","30313233343536373839")]
+ public void Base16ToStringShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ byte[] bytes = Encoding.UTF8.GetBytes(value);
+ Base16 candidate = new(bytes);
+
+ // When
+ string actual = candidate.ToString();
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32Base32HexAlphabetTests.cs b/OnixLabs.Core.UnitTests/Text/Base32Base32HexAlphabetTests.cs
deleted file mode 100644
index 0754051..0000000
--- a/OnixLabs.Core.UnitTests/Text/Base32Base32HexAlphabetTests.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OnixLabs.Core.Text;
-using Xunit;
-
-namespace OnixLabs.Core.UnitTests.Text;
-
-public sealed class Base32Base32HexAlphabetTests
-{
- [Fact(DisplayName = "Identical Base32 values produce identical hash codes.")]
- public void IdenticalBase32ValuesProduceIdenticalHashCodes()
- {
- // Arrange
- Base32 a = Base32.FromString("abcdefghijklmnopqrstuvwxyz", Base32Alphabet.Base32Hex);
- Base32 b = Base32.FromString("abcdefghijklmnopqrstuvwxyz", Base32Alphabet.Base32Hex);
-
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
-
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
- }
-
- [Theory(DisplayName = "Base32_FromString without padding should produce the expected Base-32 value.")]
- [InlineData("64P36D1L6ORJGE9G", "1234567890")]
- [InlineData("85146H258P3KGIAA9D64QJIFA18L4KQKALB5EM2PB8======", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("C5H66P35CPJMGQBADDM6QRJFE1ON4SRKELR7EU3PF8======", "abcdefghijklmnopqrstuvwxyz")]
- public void Base32FromStringWithPaddingShouldProduceTheExpectedBase32Value(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.FromString(value, Base32Alphabet.Base32Hex, true);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base32_FromString without padding should produce the expected Base-32 value.")]
- [InlineData("64P36D1L6ORJGE9G", "1234567890")]
- [InlineData("85146H258P3KGIAA9D64QJIFA18L4KQKALB5EM2PB8", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("C5H66P35CPJMGQBADDM6QRJFE1ON4SRKELR7EU3PF8", "abcdefghijklmnopqrstuvwxyz")]
- public void Base32FromStringWithoutPaddingShouldProduceTheExpectedBase32Value(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.FromString(value, Base32Alphabet.Base32Hex, false);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base32_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "64P36D1L6ORJGE9G")]
- [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "85146H258P3KGIAA9D64QJIFA18L4KQKALB5EM2PB8")]
- [InlineData("abcdefghijklmnopqrstuvwxyz", "C5H66P35CPJMGQBADDM6QRJFE1ON4SRKELR7EU3PF8")]
- public void Base32ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.Parse(value, Base32Alphabet.Base32Hex);
-
- // Act
- string actual = candidate.ToPlainTextString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecBase32HexTests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecBase32HexTests.cs
new file mode 100644
index 0000000..a5abccb
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecBase32HexTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecBase32HexTests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","85146H258P3KGIAA9D64QJIFA18L4KQKALB5EM2PB8")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","C5H66P35CPJMGQBADDM6QRJFE1ON4SRKELR7EU3PF8")]
+ [InlineData("0123456789","60OJ4CPK6KR3EE1P")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.Base32Hex);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("85146H258P3KGIAA9D64QJIFA18L4KQKALB5EM2PB8","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("C5H66P35CPJMGQBADDM6QRJFE1ON4SRKELR7EU3PF8","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("60OJ4CPK6KR3EE1P","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.Base32Hex);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecCrockfordTests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecCrockfordTests.cs
new file mode 100644
index 0000000..b75133f
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecCrockfordTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecCrockfordTests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","85146H258S3MGJAA9D64TKJFA18N4MTMANB5EP2SB8")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","C5H66S35CSKPGTBADDP6TVKFE1RQ4WVMENV7EY3SF8")]
+ [InlineData("0123456789","60RK4CSM6MV3EE1S")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.Crockford);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("85146H258S3MGJAA9D64TKJFA18N4MTMANB5EP2SB8","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("C5H66S35CSKPGTBADDP6TVKFE1RQ4WVMENV7EY3SF8","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("60RK4CSM6MV3EE1S","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.Crockford);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecGeoHashTests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecGeoHashTests.cs
new file mode 100644
index 0000000..1aa3b0e
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecGeoHashTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecGeoHashTests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","85146j258t3nhkbb9e64umkgb18p4nunbpc5fq2tc8")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","d5j66t35dtmqhucbeeq6uvmgf1sr4wvnfpv7fy3tg8")]
+ [InlineData("0123456789","60sm4dtn6nv3ff1t")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.GeoHash);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("85146j258t3nhkbb9e64umkgb18p4nunbpc5fq2tc8","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("d5j66t35dtmqhucbeeq6uvmgf1sr4wvnfpv7fy3tg8","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("60sm4dtn6nv3ff1t","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.GeoHash);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedBase32HexTests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedBase32HexTests.cs
new file mode 100644
index 0000000..d1b68db
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedBase32HexTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecPaddedBase32HexTests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","85146H258P3KGIAA9D64QJIFA18L4KQKALB5EM2PB8======")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","C5H66P35CPJMGQBADDM6QRJFE1ON4SRKELR7EU3PF8======")]
+ [InlineData("0123456789","60OJ4CPK6KR3EE1P")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.PaddedBase32Hex);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("85146H258P3KGIAA9D64QJIFA18L4KQKALB5EM2PB8======","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("C5H66P35CPJMGQBADDM6QRJFE1ON4SRKELR7EU3PF8======","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("60OJ4CPK6KR3EE1P","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.PaddedBase32Hex);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedCrockfordTests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedCrockfordTests.cs
new file mode 100644
index 0000000..ba48e0f
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedCrockfordTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecPaddedCrockfordTests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","85146H258S3MGJAA9D64TKJFA18N4MTMANB5EP2SB8======")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","C5H66S35CSKPGTBADDP6TVKFE1RQ4WVMENV7EY3SF8======")]
+ [InlineData("0123456789","60RK4CSM6MV3EE1S")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.PaddedCrockford);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("85146H258S3MGJAA9D64TKJFA18N4MTMANB5EP2SB8======","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("C5H66S35CSKPGTBADDP6TVKFE1RQ4WVMENV7EY3SF8======","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("60RK4CSM6MV3EE1S","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.PaddedCrockford);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedGeoHashTests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedGeoHashTests.cs
new file mode 100644
index 0000000..07c820b
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedGeoHashTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecPaddedGeoHashTests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","85146j258t3nhkbb9e64umkgb18p4nunbpc5fq2tc8======")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","d5j66t35dtmqhucbeeq6uvmgf1sr4wvnfpv7fy3tg8======")]
+ [InlineData("0123456789","60sm4dtn6nv3ff1t")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.PaddedGeoHash);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("85146j258t3nhkbb9e64umkgb18p4nunbpc5fq2tc8======","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("d5j66t35dtmqhucbeeq6uvmgf1sr4wvnfpv7fy3tg8======","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("60sm4dtn6nv3ff1t","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.PaddedGeoHash);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedRfc4648Tests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedRfc4648Tests.cs
new file mode 100644
index 0000000..da0ba10
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedRfc4648Tests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecPaddedRfc4648Tests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI======")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI======")]
+ [InlineData("0123456789","GAYTEMZUGU3DOOBZ")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.PaddedRfc4648);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI======","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI======","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("GAYTEMZUGU3DOOBZ","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.PaddedRfc4648);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedZBase32Tests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedZBase32Tests.cs
new file mode 100644
index 0000000..80838c9
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecPaddedZBase32Tests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecPaddedZBase32Tests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","efbrgtnfe3dwo1kkjpgr4u1xkbeirw4wkimfqsn3me======")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","cftgg3dfc3uso4mkppsg45uxqbazrh5wqi58q6d3xe======")]
+ [InlineData("0123456789","gyaurc3wgw5dqqb3")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.PaddedZBase32);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("efbrgtnfe3dwo1kkjpgr4u1xkbeirw4wkimfqsn3me======","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("cftgg3dfc3uso4mkppsg45uxqbazrh5wqi58q6d3xe======","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("gyaurc3wgw5dqqb3","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.PaddedZBase32);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecRfc4648Tests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecRfc4648Tests.cs
new file mode 100644
index 0000000..6a15981
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecRfc4648Tests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecRfc4648Tests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI")]
+ [InlineData("0123456789","GAYTEMZUGU3DOOBZ")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("GAYTEMZUGU3DOOBZ","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CodecZBase32Tests.cs b/OnixLabs.Core.UnitTests/Text/Base32CodecZBase32Tests.cs
new file mode 100644
index 0000000..23d1832
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32CodecZBase32Tests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32CodecZBase32Tests
+{
+ [Theory(DisplayName = "Base32Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","efbrgtnfe3dwo1kkjpgr4u1xkbeirw4wkimfqsn3me")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","cftgg3dfc3uso4mkppsg45uxqbazrh5wqi58q6d3xe")]
+ [InlineData("0123456789","gyaurc3wgw5dqqb3")]
+ public void Base32CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base32FormatProvider.ZBase32);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("efbrgtnfe3dwo1kkjpgr4u1xkbeirw4wkimfqsn3me","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("cftgg3dfc3uso4mkppsg45uxqbazrh5wqi58q6d3xe","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("gyaurc3wgw5dqqb3","0123456789")]
+ public void Base32CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base32;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base32FormatProvider.ZBase32);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32CrockfordAlphabetTests.cs b/OnixLabs.Core.UnitTests/Text/Base32CrockfordAlphabetTests.cs
deleted file mode 100644
index ad3c782..0000000
--- a/OnixLabs.Core.UnitTests/Text/Base32CrockfordAlphabetTests.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OnixLabs.Core.Text;
-using Xunit;
-
-namespace OnixLabs.Core.UnitTests.Text;
-
-public sealed class Base32CrockfordAlphabetTests
-{
- [Fact(DisplayName = "Identical Base32 values produce identical hash codes.")]
- public void IdenticalBase32ValuesProduceIdenticalHashCodes()
- {
- // Arrange
- Base32 a = Base32.FromString("abcdefghijklmnopqrstuvwxyz", Base32Alphabet.Crockford);
- Base32 b = Base32.FromString("abcdefghijklmnopqrstuvwxyz", Base32Alphabet.Crockford);
-
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
-
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
- }
-
- [Theory(DisplayName = "Base32_FromString without padding should produce the expected Base-32 value.")]
- [InlineData("64S36D1N6RVKGE9G", "1234567890")]
- [InlineData("85146H258S3MGJAA9D64TKJFA18N4MTMANB5EP2SB8======", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("C5H66S35CSKPGTBADDP6TVKFE1RQ4WVMENV7EY3SF8======", "abcdefghijklmnopqrstuvwxyz")]
- public void Base32FromStringWithPaddingShouldProduceTheExpectedBase32Value(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.FromString(value, Base32Alphabet.Crockford, true);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base32_FromString without padding should produce the expected Base-32 value.")]
- [InlineData("64S36D1N6RVKGE9G", "1234567890")]
- [InlineData("85146H258S3MGJAA9D64TKJFA18N4MTMANB5EP2SB8", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("C5H66S35CSKPGTBADDP6TVKFE1RQ4WVMENV7EY3SF8", "abcdefghijklmnopqrstuvwxyz")]
- public void Base32FromStringWithoutPaddingShouldProduceTheExpectedBase32Value(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.FromString(value, Base32Alphabet.Crockford, false);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base32_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "64S36D1N6RVKGE9G")]
- [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "85146H258S3MGJAA9D64TKJFA18N4MTMANB5EP2SB8")]
- [InlineData("abcdefghijklmnopqrstuvwxyz", "C5H66S35CSKPGTBADDP6TVKFE1RQ4WVMENV7EY3SF8")]
- public void Base32ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.Parse(value, Base32Alphabet.Crockford);
-
- // Act
- string actual = candidate.ToPlainTextString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32DefaultAlphabetTests.cs b/OnixLabs.Core.UnitTests/Text/Base32DefaultAlphabetTests.cs
deleted file mode 100644
index 64be871..0000000
--- a/OnixLabs.Core.UnitTests/Text/Base32DefaultAlphabetTests.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OnixLabs.Core.Text;
-using Xunit;
-
-namespace OnixLabs.Core.UnitTests.Text;
-
-public sealed class Base32DefaultAlphabetTests
-{
- [Fact(DisplayName = "Identical Base32 values produce identical hash codes.")]
- public void IdenticalBase32ValuesProduceIdenticalHashCodes()
- {
- // Arrange
- Base32 a = Base32.FromString("abcdefghijklmnopqrstuvwxyz", Base32Alphabet.Default);
- Base32 b = Base32.FromString("abcdefghijklmnopqrstuvwxyz", Base32Alphabet.Default);
-
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
-
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
- }
-
- [Theory(DisplayName = "Base32_FromString without padding should produce the expected Base-32 value.")]
- [InlineData("GEZDGNBVGY3TQOJQ", "1234567890")]
- [InlineData("IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI======", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI======", "abcdefghijklmnopqrstuvwxyz")]
- public void Base32FromStringWithPaddingShouldProduceTheExpectedBase32Value(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.FromString(value, Base32Alphabet.Default, true);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base32_FromString without padding should produce the expected Base-32 value.")]
- [InlineData("GEZDGNBVGY3TQOJQ", "1234567890")]
- [InlineData("IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI", "abcdefghijklmnopqrstuvwxyz")]
- public void Base32FromStringWithoutPaddingShouldProduceTheExpectedBase32Value(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.FromString(value, Base32Alphabet.Default, false);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base32_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "GEZDGNBVGY3TQOJQ")]
- [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI")]
- [InlineData("abcdefghijklmnopqrstuvwxyz", "MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI")]
- public void Base32ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.Parse(value, Base32Alphabet.Default);
-
- // Act
- string actual = candidate.ToPlainTextString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32Tests.cs b/OnixLabs.Core.UnitTests/Text/Base32Tests.cs
new file mode 100644
index 0000000..5ff7d84
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base32Tests.cs
@@ -0,0 +1,119 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base32Tests
+{
+ [Fact(DisplayName = "Base32 should not change when modifying the original byte array")]
+ public void Base32ShouldNotChangeWhenModifyingOriginalByteArray()
+ {
+ // Given
+ byte[] bytes = "ABCabc123".ToByteArray();
+ Base32 candidate = new(bytes);
+ const string expected = "IFBEGYLCMMYTEMY";
+
+ // When
+ bytes[0] = 0;
+ string actual = candidate.ToString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "Base32 should not change when modifying the obtained byte array")]
+ public void Base32ShouldNotChangeWhenModifyingObtainedByteArray()
+ {
+ // Given
+ Base32 candidate = new("ABCabc123".ToByteArray());
+ const string expected = "IFBEGYLCMMYTEMY";
+
+ // When
+ byte[] bytes = candidate.ToByteArray();
+ bytes[0] = 0;
+ string actual = candidate.ToString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "Base32 values should be identical")]
+ public void Base32ValuesShouldBeIdentical()
+ {
+ // Given
+ Base32 a = new([0, 255]);
+ Base32 b = new([0, 255]);
+
+ // Then
+ Assert.Equal(a, b);
+ Assert.Equal(a.GetHashCode(), b.GetHashCode());
+ Assert.True(a.Equals(b));
+ Assert.True(a == b);
+ Assert.False(a != b);
+ }
+
+ [Fact(DisplayName = "Base32 values should not be identical")]
+ public void Base32ValuesShouldNotBeIdentical()
+ {
+ // Given
+ Base32 a = new([0, 255]);
+ Base32 b = new([1, 127]);
+
+ // Then
+ Assert.NotEqual(a, b);
+ Assert.NotEqual(a.GetHashCode(), b.GetHashCode());
+ Assert.False(a.Equals(b));
+ Assert.False(a == b);
+ Assert.True(a != b);
+ }
+
+ [Theory(DisplayName = "Base32.Parse should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("GAYTEMZUGU3DOOBZ","0123456789")]
+ public void Base32ParseShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ Base32 candidate = Base32.Parse(value);
+
+ // When
+ string actual = Encoding.UTF8.GetString(candidate.ToByteArray());
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base32.ToString should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","MFRGGZDFMZTWQ2LKNNWG23TPOBYXE43UOV3HO6DZPI")]
+ [InlineData("0123456789","GAYTEMZUGU3DOOBZ")]
+ public void Base32ToStringShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ byte[] bytes = Encoding.UTF8.GetBytes(value);
+ Base32 candidate = new(bytes);
+
+ // When
+ string actual = candidate.ToString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base32ZBase32AlphabetTests.cs b/OnixLabs.Core.UnitTests/Text/Base32ZBase32AlphabetTests.cs
deleted file mode 100644
index 9fcf4a5..0000000
--- a/OnixLabs.Core.UnitTests/Text/Base32ZBase32AlphabetTests.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OnixLabs.Core.Text;
-using Xunit;
-
-namespace OnixLabs.Core.UnitTests.Text;
-
-public sealed class Base32ZBase32AlphabetTests
-{
- [Fact(DisplayName = "Identical Base32 values produce identical hash codes.")]
- public void IdenticalBase32ValuesProduceIdenticalHashCodes()
- {
- // Arrange
- Base32 a = Base32.FromString("abcdefghijklmnopqrstuvwxyz", Base32Alphabet.ZBase32);
- Base32 b = Base32.FromString("abcdefghijklmnopqrstuvwxyz", Base32Alphabet.ZBase32);
-
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
-
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
- }
-
- [Theory(DisplayName = "Base32_FromString without padding should produce the expected Base-32 value.")]
- [InlineData("gr3dgpbiga5uoqjo", "1234567890")]
- [InlineData("efbrgtnfe3dwo1kkjpgr4u1xkbeirw4wkimfqsn3me======", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("cftgg3dfc3uso4mkppsg45uxqbazrh5wqi58q6d3xe======", "abcdefghijklmnopqrstuvwxyz")]
- public void Base32FromStringWithPaddingShouldProduceTheExpectedBase32Value(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.FromString(value, Base32Alphabet.ZBase32, true);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base32_FromString without padding should produce the expected Base-32 value.")]
- [InlineData("gr3dgpbiga5uoqjo", "1234567890")]
- [InlineData("efbrgtnfe3dwo1kkjpgr4u1xkbeirw4wkimfqsn3me", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("cftgg3dfc3uso4mkppsg45uxqbazrh5wqi58q6d3xe", "abcdefghijklmnopqrstuvwxyz")]
- public void Base32FromStringWithoutPaddingShouldProduceTheExpectedBase32Value(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.FromString(value, Base32Alphabet.ZBase32, false);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base32_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "gr3dgpbiga5uoqjo")]
- [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "efbrgtnfe3dwo1kkjpgr4u1xkbeirw4wkimfqsn3me")]
- [InlineData("abcdefghijklmnopqrstuvwxyz", "cftgg3dfc3uso4mkppsg45uxqbazrh5wqi58q6d3xe")]
- public void Base32ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
- {
- // Arrange
- Base32 candidate = Base32.Parse(value, Base32Alphabet.ZBase32);
-
- // Act
- string actual = candidate.ToPlainTextString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-}
diff --git a/OnixLabs.Core.UnitTests/Text/Base58CodecBitcoinTests.cs b/OnixLabs.Core.UnitTests/Text/Base58CodecBitcoinTests.cs
new file mode 100644
index 0000000..b0b0d1c
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base58CodecBitcoinTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base58CodecBitcoinTests
+{
+ [Theory(DisplayName = "Base58Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","2zuFXTJSTRK6ESktqhM2QDBkCnH1U46CnxaD")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f")]
+ [InlineData("0123456789","3i37NcgooY8f1S")]
+ public void Base58CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base58;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base58FormatProvider.Bitcoin);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base58Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("2zuFXTJSTRK6ESktqhM2QDBkCnH1U46CnxaD","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("3i37NcgooY8f1S","0123456789")]
+ public void Base58CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base58;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base58FormatProvider.Bitcoin);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base58CodecFlickrTests.cs b/OnixLabs.Core.UnitTests/Text/Base58CodecFlickrTests.cs
new file mode 100644
index 0000000..9e148fd
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base58CodecFlickrTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base58CodecFlickrTests
+{
+ [Theory(DisplayName = "Base58Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","2ZUfwsirsqj6erKTQGm2pdbKcMh1t46cMXzd")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","3YXt3U1HFx8vKFTJj92EAipcC4byHHs1V25E")]
+ [InlineData("0123456789","3H37nBFNNx8E1r")]
+ public void Base58CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base58;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base58FormatProvider.Flickr);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base58Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("2ZUfwsirsqj6erKTQGm2pdbKcMh1t46cMXzd","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("3YXt3U1HFx8vKFTJj92EAipcC4byHHs1V25E","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("3H37nBFNNx8E1r","0123456789")]
+ public void Base58CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base58;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base58FormatProvider.Flickr);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base58CodecRippleTests.cs b/OnixLabs.Core.UnitTests/Text/Base58CodecRippleTests.cs
new file mode 100644
index 0000000..562835d
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base58CodecRippleTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base58CodecRippleTests
+{
+ [Theory(DisplayName = "Base58Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "pzuEXTJSTRKaNSktq6MpQDBkU8Hr7haU8x2D")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "syx7sur5gY3WkgtjK9pCbJQUdhBZ55TrvpnC")]
+ [InlineData("0123456789", "s5sf4cgooY3CrS")]
+ public void Base58CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base58;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes, Base58FormatProvider.Ripple);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base58Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("pzuEXTJSTRKaNSktq6MpQDBkU8Hr7haU8x2D", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("syx7sur5gY3WkgtjK9pCbJQUdhBZ55TrvpnC", "abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("s5sf4cgooY3CrS", "0123456789")]
+ public void Base58CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base58;
+
+ // When
+ byte[] bytes = codec.Decode(value, Base58FormatProvider.Ripple);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base58DefaultAlphabetTests.cs b/OnixLabs.Core.UnitTests/Text/Base58DefaultAlphabetTests.cs
deleted file mode 100644
index f59cb61..0000000
--- a/OnixLabs.Core.UnitTests/Text/Base58DefaultAlphabetTests.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OnixLabs.Core.Text;
-using Xunit;
-
-namespace OnixLabs.Core.UnitTests.Text;
-
-public sealed class Base58DefaultAlphabetTests
-{
- [Fact(DisplayName = "Identical Base58 values produce identical hash codes.")]
- public void IdenticalBase58ValuesProduceIdenticalHashCodes()
- {
- // Arrange
- Base58 a = Base58.FromString("abcdefghijklmnopqrstuvwxyz", Base58Alphabet.Default);
- Base58 b = Base58.FromString("abcdefghijklmnopqrstuvwxyz", Base58Alphabet.Default);
-
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
-
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
- }
-
- [Theory(DisplayName = "Base58_FromString should produce the expected Base-58 value.")]
- [InlineData("3mJr7AoUCHxNqd", "1234567890")]
- [InlineData("2zuFXTJSTRK6ESktqhM2QDBkCnH1U46CnxaD", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f", "abcdefghijklmnopqrstuvwxyz")]
- public void Base58FromStringShouldProduceTheExpectedBase58Value(string expected, string value)
- {
- // Arrange
- Base58 candidate = Base58.FromString(value, Base58Alphabet.Default);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base58_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "3mJr7AoUCHxNqd")]
- [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "2zuFXTJSTRK6ESktqhM2QDBkCnH1U46CnxaD")]
- [InlineData("abcdefghijklmnopqrstuvwxyz", "3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f")]
- public void Base58ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
- {
- // Arrange
- Base58 candidate = Base58.Parse(value, Base58Alphabet.Default);
-
- // Act
- string actual = candidate.ToPlainTextString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-}
diff --git a/OnixLabs.Core.UnitTests/Text/Base58FlickrAlphabetTests.cs b/OnixLabs.Core.UnitTests/Text/Base58FlickrAlphabetTests.cs
deleted file mode 100644
index 64cc7e2..0000000
--- a/OnixLabs.Core.UnitTests/Text/Base58FlickrAlphabetTests.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OnixLabs.Core.Text;
-using Xunit;
-
-namespace OnixLabs.Core.UnitTests.Text;
-
-public sealed class Base58FlickrAlphabetTests
-{
- [Fact(DisplayName = "Identical Base58 values produce identical hash codes.")]
- public void IdenticalBase58ValuesProduceIdenticalHashCodes()
- {
- // Arrange
- Base58 a = Base58.FromString("abcdefghijklmnopqrstuvwxyz", Base58Alphabet.Flickr);
- Base58 b = Base58.FromString("abcdefghijklmnopqrstuvwxyz", Base58Alphabet.Flickr);
-
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
-
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
- }
-
- [Theory(DisplayName = "Base58_FromString should produce the expected Base-58 value.")]
- [InlineData("3LiR7aNtchXnQC", "1234567890")]
- [InlineData("2ZUfwsirsqj6erKTQGm2pdbKcMh1t46cMXzd", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("3YXt3U1HFx8vKFTJj92EAipcC4byHHs1V25E", "abcdefghijklmnopqrstuvwxyz")]
- public void Base58FromStringShouldProduceTheExpectedBase58Value(string expected, string value)
- {
- // Arrange
- Base58 candidate = Base58.FromString(value, Base58Alphabet.Flickr);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base58_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "3LiR7aNtchXnQC")]
- [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "2ZUfwsirsqj6erKTQGm2pdbKcMh1t46cMXzd")]
- [InlineData("abcdefghijklmnopqrstuvwxyz", "3YXt3U1HFx8vKFTJj92EAipcC4byHHs1V25E")]
- public void Base58ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
- {
- // Arrange
- Base58 candidate = Base58.Parse(value, Base58Alphabet.Flickr);
-
- // Act
- string actual = candidate.ToPlainTextString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-}
diff --git a/OnixLabs.Core.UnitTests/Text/Base58RippleAlphabetTests.cs b/OnixLabs.Core.UnitTests/Text/Base58RippleAlphabetTests.cs
deleted file mode 100644
index 381776c..0000000
--- a/OnixLabs.Core.UnitTests/Text/Base58RippleAlphabetTests.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using OnixLabs.Core.Text;
-using Xunit;
-
-namespace OnixLabs.Core.UnitTests.Text;
-
-public sealed class Base58RippleAlphabetTests
-{
- [Fact(DisplayName = "Identical Base58 values produce identical hash codes.")]
- public void IdenticalBase58ValuesProduceIdenticalHashCodes()
- {
- // Arrange
- Base58 a = Base58.FromString("abcdefghijklmnopqrstuvwxyz", Base58Alphabet.Ripple);
- Base58 b = Base58.FromString("abcdefghijklmnopqrstuvwxyz", Base58Alphabet.Ripple);
-
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
-
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
- }
-
- [Theory(DisplayName = "Base58_FromString should produce the expected Base-58 value.")]
- [InlineData("smJifwo7UHx4qd", "1234567890")]
- [InlineData("pzuEXTJSTRKaNSktq6MpQDBkU8Hr7haU8x2D", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
- [InlineData("syx7sur5gY3WkgtjK9pCbJQUdhBZ55TrvpnC", "abcdefghijklmnopqrstuvwxyz")]
- public void Base58FromStringShouldProduceTheExpectedBase58Value(string expected, string value)
- {
- // Arrange
- Base58 candidate = Base58.FromString(value, Base58Alphabet.Ripple);
-
- // Act
- string actual = candidate.ToString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-
- [Theory(DisplayName = "Base58_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "smJifwo7UHx4qd")]
- [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "pzuEXTJSTRKaNSktq6MpQDBkU8Hr7haU8x2D")]
- [InlineData("abcdefghijklmnopqrstuvwxyz", "syx7sur5gY3WkgtjK9pCbJQUdhBZ55TrvpnC")]
- public void Base58ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
- {
- // Arrange
- Base58 candidate = Base58.Parse(value, Base58Alphabet.Ripple);
-
- // Act
- string actual = candidate.ToPlainTextString();
-
- // Assert
- Assert.Equal(expected, actual);
- }
-}
diff --git a/OnixLabs.Core.UnitTests/Text/Base58Tests.cs b/OnixLabs.Core.UnitTests/Text/Base58Tests.cs
new file mode 100644
index 0000000..de00880
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base58Tests.cs
@@ -0,0 +1,119 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base58Tests
+{
+ [Fact(DisplayName = "Base58 should not change when modifying the original byte array")]
+ public void Base58ShouldNotChangeWhenModifyingOriginalByteArray()
+ {
+ // Given
+ byte[] bytes = "ABCabc123".ToByteArray();
+ Base58 candidate = new(bytes);
+ const string expected = "qBLgTCSW82Hg";
+
+ // When
+ bytes[0] = 0;
+ string actual = candidate.ToString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "Base58 should not change when modifying the obtained byte array")]
+ public void Base58ShouldNotChangeWhenModifyingObtainedByteArray()
+ {
+ // Given
+ Base58 candidate = new("ABCabc123".ToByteArray());
+ const string expected = "qBLgTCSW82Hg";
+
+ // When
+ byte[] bytes = candidate.ToByteArray();
+ bytes[0] = 0;
+ string actual = candidate.ToString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "Base58 values should be identical")]
+ public void Base58ValuesShouldBeIdentical()
+ {
+ // Given
+ Base58 a = new([0, 255]);
+ Base58 b = new([0, 255]);
+
+ // Then
+ Assert.Equal(a, b);
+ Assert.Equal(a.GetHashCode(), b.GetHashCode());
+ Assert.True(a.Equals(b));
+ Assert.True(a == b);
+ Assert.False(a != b);
+ }
+
+ [Fact(DisplayName = "Base58 values should not be identical")]
+ public void Base58ValuesShouldNotBeIdentical()
+ {
+ // Given
+ Base58 a = new([0, 255]);
+ Base58 b = new([1, 127]);
+
+ // Then
+ Assert.NotEqual(a, b);
+ Assert.NotEqual(a.GetHashCode(), b.GetHashCode());
+ Assert.False(a.Equals(b));
+ Assert.False(a == b);
+ Assert.True(a != b);
+ }
+
+ [Theory(DisplayName = "Base58.Parse should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("2zuFXTJSTRK6ESktqhM2QDBkCnH1U46CnxaD","ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f","abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("3i37NcgooY8f1S","0123456789")]
+ public void Base58ParseShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ Base58 candidate = Base58.Parse(value);
+
+ // When
+ string actual = Encoding.UTF8.GetString(candidate.ToByteArray());
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base58.ToString should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ","2zuFXTJSTRK6ESktqhM2QDBkCnH1U46CnxaD")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz","3yxU3u1igY8WkgtjK92fbJQCd4BZiiT1v25f")]
+ [InlineData("0123456789","3i37NcgooY8f1S")]
+ public void Base58ToStringShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ byte[] bytes = Encoding.UTF8.GetBytes(value);
+ Base58 candidate = new(bytes);
+
+ // When
+ string actual = candidate.ToString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base64CodecTests.cs b/OnixLabs.Core.UnitTests/Text/Base64CodecTests.cs
new file mode 100644
index 0000000..fea69f2
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/Base64CodecTests.cs
@@ -0,0 +1,58 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class Base64CodecTests
+{
+ [Theory(DisplayName = "Base64Codec.Encode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=")]
+ [InlineData("abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=")]
+ [InlineData("0123456789", "MDEyMzQ1Njc4OQ==")]
+ public void Base64CodecEncodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base64;
+ byte[] bytes = value.ToByteArray();
+
+ // When
+ string actual = codec.Encode(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Theory(DisplayName = "Base64Codec.Decode should produce the expected result")]
+ [InlineData("", "")]
+ [InlineData("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
+ [InlineData("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", "abcdefghijklmnopqrstuvwxyz")]
+ [InlineData("MDEyMzQ1Njc4OQ==", "0123456789")]
+ public void Base64CodecDecodeShouldProduceExpectedResult(string value, string expected)
+ {
+ // Given
+ IBaseCodec codec = IBaseCodec.Base64;
+
+ // When
+ byte[] bytes = codec.Decode(value);
+ string actual = Encoding.UTF8.GetString(bytes);
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+}
diff --git a/OnixLabs.Core.UnitTests/Text/Base64Tests.cs b/OnixLabs.Core.UnitTests/Text/Base64Tests.cs
index d9da9b7..7b98b04 100644
--- a/OnixLabs.Core.UnitTests/Text/Base64Tests.cs
+++ b/OnixLabs.Core.UnitTests/Text/Base64Tests.cs
@@ -1,17 +1,18 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+using System.Text;
using OnixLabs.Core.Text;
using Xunit;
@@ -19,50 +20,100 @@ namespace OnixLabs.Core.UnitTests.Text;
public sealed class Base64Tests
{
- [Fact(DisplayName = "Identical Base64 values produce identical hash codes.")]
- public void IdenticalBase64ValuesProduceIdenticalHashCodes()
+ [Fact(DisplayName = "Base64 should not change when modifying the original byte array")]
+ public void Base64ShouldNotChangeWhenModifyingOriginalByteArray()
{
- // Arrange
- Base64 a = Base64.FromString("abcdefghijklmnopqrstuvwxyz");
- Base64 b = Base64.FromString("abcdefghijklmnopqrstuvwxyz");
+ // Given
+ byte[] bytes = "ABCabc123".ToByteArray();
+ Base64 candidate = new(bytes);
+ const string expected = "QUJDYWJjMTIz";
- // Act
- int hashCodeA = a.GetHashCode();
- int hashCodeB = b.GetHashCode();
+ // When
+ bytes[0] = 0;
+ string actual = candidate.ToString();
- // Assert
- Assert.Equal(hashCodeA, hashCodeB);
+ // Then
+ Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "Base64_FromString should produce the expected Base-64 value.")]
- [InlineData("MTIzNDU2Nzg5MA==", "1234567890")]
+ [Fact(DisplayName = "Base64 should not change when modifying the obtained byte array")]
+ public void Base64ShouldNotChangeWhenModifyingObtainedByteArray()
+ {
+ // Given
+ Base64 candidate = new("ABCabc123".ToByteArray());
+ const string expected = "QUJDYWJjMTIz";
+
+ // When
+ byte[] bytes = candidate.ToByteArray();
+ bytes[0] = 0;
+ string actual = candidate.ToString();
+
+ // Then
+ Assert.Equal(expected, actual);
+ }
+
+ [Fact(DisplayName = "Base64 values should be identical")]
+ public void Base64ValuesShouldBeIdentical()
+ {
+ // Given
+ Base64 a = new([0, 255]);
+ Base64 b = new([0, 255]);
+
+ // Then
+ Assert.Equal(a, b);
+ Assert.Equal(a.GetHashCode(), b.GetHashCode());
+ Assert.True(a.Equals(b));
+ Assert.True(a == b);
+ Assert.False(a != b);
+ }
+
+ [Fact(DisplayName = "Base64 values should not be identical")]
+ public void Base64ValuesShouldNotBeIdentical()
+ {
+ // Given
+ Base64 a = new([0, 255]);
+ Base64 b = new([1, 127]);
+
+ // Then
+ Assert.NotEqual(a, b);
+ Assert.NotEqual(a.GetHashCode(), b.GetHashCode());
+ Assert.False(a.Equals(b));
+ Assert.False(a == b);
+ Assert.True(a != b);
+ }
+
+ [Theory(DisplayName = "Base64.Parse should produce the expected result")]
+ [InlineData("", "")]
[InlineData("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")]
[InlineData("YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=", "abcdefghijklmnopqrstuvwxyz")]
- public void Base64FromStringShouldProduceTheExpectedBase64Value(string expected, string value)
+ [InlineData("MDEyMzQ1Njc4OQ==", "0123456789")]
+ public void Base64ParseShouldProduceExpectedResult(string value, string expected)
{
- // Arrange
- Base64 candidate = Base64.FromString(value);
+ // Given
+ Base64 candidate = Base64.Parse(value);
- // Act
- string actual = candidate.ToString();
+ // When
+ string actual = Encoding.UTF8.GetString(candidate.ToByteArray());
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
- [Theory(DisplayName = "Base64_Parse should produce the expected plain text value.")]
- [InlineData("1234567890", "MTIzNDU2Nzg5MA==")]
+ [Theory(DisplayName = "Base64.ToString should produce the expected result")]
+ [InlineData("", "")]
[InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo=")]
[InlineData("abcdefghijklmnopqrstuvwxyz", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=")]
- public void Base64ParseShouldProduceTheExpectedPlainTextValue(string expected, string value)
+ [InlineData("0123456789", "MDEyMzQ1Njc4OQ==")]
+ public void Base64ToStringShouldProduceExpectedResult(string value, string expected)
{
- // Arrange
- Base64 candidate = Base64.Parse(value);
+ // Given
+ byte[] bytes = Encoding.UTF8.GetBytes(value);
+ Base64 candidate = new(bytes);
- // Act
- string actual = candidate.ToPlainTextString();
+ // When
+ string actual = candidate.ToString();
- // Assert
+ // Then
Assert.Equal(expected, actual);
}
}
diff --git a/OnixLabs.Core.UnitTests/Text/StringBuilderExtensionTests.cs b/OnixLabs.Core.UnitTests/Text/StringBuilderExtensionTests.cs
new file mode 100644
index 0000000..868765d
--- /dev/null
+++ b/OnixLabs.Core.UnitTests/Text/StringBuilderExtensionTests.cs
@@ -0,0 +1,152 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Text;
+using OnixLabs.Core.Text;
+using Xunit;
+
+namespace OnixLabs.Core.UnitTests.Text;
+
+public sealed class StringBuilderExtensionTests
+{
+ [Fact(DisplayName = "StringBuilder.Append should produce the expected result")]
+ public void StringBuilderAppendShouldProduceTheExpectedResult()
+ {
+ // Given
+ StringBuilder builder = new("ABC");
+
+ // When
+ builder.Append("XYZ", 123, false);
+
+ // Then
+ Assert.Equal("ABCXYZ123False", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.Prepend should produce the expected result")]
+ public void StringBuilderPrependShouldProduceTheExpectedResult()
+ {
+ // Given
+ StringBuilder builder = new("ABC");
+
+ // When
+ builder.Prepend("XYZ", 123, false);
+
+ // Then
+ Assert.Equal("XYZ123FalseABC", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.Trim should produce the expected result (char)")]
+ public void StringBuilderTrimShouldProduceTheExpectedResultChar()
+ {
+ // Given
+ StringBuilder builder = new("###ABC###");
+
+ // When
+ builder.Trim('#');
+
+ // Then
+ Assert.Equal("ABC", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.TrimEnd should produce the expected result (char)")]
+ public void StringBuilderTrimEndShouldProduceTheExpectedResultChar()
+ {
+ // Given
+ StringBuilder builder = new("###ABC###");
+
+ // When
+ builder.TrimEnd('#');
+
+ // Then
+ Assert.Equal("###ABC", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.TrimStart should produce the expected result (char)")]
+ public void StringBuilderTrimStartShouldProduceTheExpectedResultChar()
+ {
+ // Given
+ StringBuilder builder = new("###ABC###");
+
+ // When
+ builder.TrimStart('#');
+
+ // Then
+ Assert.Equal("ABC###", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.Trim should produce the expected result (string)")]
+ public void StringBuilderTrimShouldProduceTheExpectedResultString()
+ {
+ // Given
+ StringBuilder builder = new("#-#ABC#-#");
+
+ // When
+ builder.Trim("#-#");
+
+ // Then
+ Assert.Equal("ABC", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.TrimEnd should produce the expected result (string)")]
+ public void StringBuilderTrimEndShouldProduceTheExpectedResultString()
+ {
+ // Given
+ StringBuilder builder = new("#-#ABC#-#");
+
+ // When
+ builder.TrimEnd("#-#");
+
+ // Then
+ Assert.Equal("#-#ABC", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.TrimStart should produce the expected result (string)")]
+ public void StringBuilderTrimStartShouldProduceTheExpectedResultString()
+ {
+ // Given
+ StringBuilder builder = new("#-#ABC#-#");
+
+ // When
+ builder.TrimStart("#-#");
+
+ // Then
+ Assert.Equal("ABC#-#", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.Wrap should produce the expected result (char)")]
+ public void StringBuilderWrapShouldProduceTheExpectedResultChar()
+ {
+ // Given
+ StringBuilder builder = new("ABC");
+
+ // When
+ builder.Wrap('(', ')');
+
+ // Then
+ Assert.Equal("(ABC)", builder.ToString());
+ }
+
+ [Fact(DisplayName = "StringBuilder.Wrap should produce the expected result (string)")]
+ public void StringBuilderWrapShouldProduceTheExpectedResultString()
+ {
+ // Given
+ StringBuilder builder = new("ABC");
+
+ // When
+ builder.Wrap("123", "XYZ");
+
+ // Then
+ Assert.Equal("123ABCXYZ", builder.ToString());
+ }
+}
diff --git a/OnixLabs.Core/Enumeration.Comparable.cs b/OnixLabs.Core/Enumeration.Comparable.cs
index 964c534..8275d76 100644
--- a/OnixLabs.Core/Enumeration.Comparable.cs
+++ b/OnixLabs.Core/Enumeration.Comparable.cs
@@ -1,33 +1,31 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-using System;
-
namespace OnixLabs.Core;
-public abstract partial class Enumeration : IComparable, IComparable
+public abstract partial class Enumeration
{
///
/// Compares the current instance with another object of the same type and returns an integer that indicates
/// whether the current instance precedes, follows, or occurs in the same position in the sort order as the
/// other object.
///
- /// An object to compare with this instance.
+ /// An object to compare with the current instance.
/// Returns a value that indicates the relative order of the objects being compared.
- public int CompareTo(object? obj)
+ public int CompareTo(T? other)
{
- return CompareTo(obj as T);
+ return Value.CompareTo(other?.Value);
}
///
@@ -35,10 +33,10 @@ public int CompareTo(object? obj)
/// whether the current instance precedes, follows, or occurs in the same position in the sort order as the
/// other object.
///
- /// An object to compare with this instance.
+ /// An object to compare with the current instance.
/// Returns a value that indicates the relative order of the objects being compared.
- public int CompareTo(T? other)
+ public int CompareTo(object? obj)
{
- return Value.CompareTo(other?.Value);
+ return this.CompareToObject(obj);
}
}
diff --git a/OnixLabs.Core/Enumeration.Equatable.cs b/OnixLabs.Core/Enumeration.Equatable.cs
index 93b2602..0cb68f1 100644
--- a/OnixLabs.Core/Enumeration.Equatable.cs
+++ b/OnixLabs.Core/Enumeration.Equatable.cs
@@ -1,11 +1,11 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,35 +16,13 @@
namespace OnixLabs.Core;
-public abstract partial class Enumeration : IEquatable
+public abstract partial class Enumeration
{
///
- /// Performs an equality check between two object instances.
+ /// Checks whether the current object is equal to another object of the same type.
///
- /// Instance a.
- /// Instance b.
- /// True if the instances are equal; otherwise, false.
- public static bool operator ==(Enumeration a, Enumeration b)
- {
- return Equals(a, b);
- }
-
- ///
- /// Performs an inequality check between two object instances.
- ///
- /// Instance a.
- /// Instance b.
- /// True if the instances are not equal; otherwise, false.
- public static bool operator !=(Enumeration a, Enumeration b)
- {
- return !Equals(a, b);
- }
-
- ///
- /// Indicates whether the current object is equal to another object of the same type.
- ///
- /// An object to compare with this object.
- /// Returns true if the current object is equal to the other parameter; otherwise, false.
+ /// An object to compare with the current object.
+ /// Returns if the current object is equal to the other parameter; otherwise, .
public bool Equals(T? other)
{
return ReferenceEquals(this, other)
@@ -55,21 +33,43 @@ public bool Equals(T? other)
}
///
- /// Checks for equality between this instance and another object.
+ /// Checks for equality between the current instance and another object.
///
/// The object to check for equality.
- /// true if the object is equal to this instance; otherwise, false.
- public sealed override bool Equals(object? obj)
+ /// Returns if the object is equal to the current instance; otherwise, .
+ public override bool Equals(object? obj)
{
return Equals(obj as T);
}
///
- /// Serves as a hash code function for this instance.
+ /// Serves as a hash code function for the current instance.
///
- /// A hash code for this instance.
+ /// Returns a hash code for the current instance.
public override int GetHashCode()
{
return HashCode.Combine(GetType(), Name, Value);
}
+
+ ///
+ /// Performs an equality comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is equal to the right-hand instance; otherwise, .
+ public static bool operator ==(Enumeration left, Enumeration right)
+ {
+ return Equals(left, right);
+ }
+
+ ///
+ /// Performs an inequality comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is not equal to the right-hand instance; otherwise, .
+ public static bool operator !=(Enumeration left, Enumeration right)
+ {
+ return !Equals(left, right);
+ }
}
diff --git a/OnixLabs.Core/Enumeration.From.cs b/OnixLabs.Core/Enumeration.From.cs
index ea7c1d9..467e18c 100644
--- a/OnixLabs.Core/Enumeration.From.cs
+++ b/OnixLabs.Core/Enumeration.From.cs
@@ -1,11 +1,11 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,7 +16,6 @@
using System.Collections.Generic;
using System.Linq;
using OnixLabs.Core.Linq;
-using static OnixLabs.Core.Preconditions;
namespace OnixLabs.Core;
@@ -32,8 +31,8 @@ public static T FromName(string name)
{
IEnumerable results = GetAll().Where(entry => entry.Name == name).ToArray();
- Check(results.IsNotEmpty(), $"Enumeration entry for name '{name}' not found in {typeof(T).Name}.");
- Check(results.IsSingle(), $"Multiple enumeration entries for name '{name}' found in {typeof(T).Name}.");
+ Require(results.IsNotEmpty(), $"Enumeration entry for name '{name}' not found in {typeof(T).Name}.", nameof(name));
+ Require(results.IsSingle(), $"Multiple enumeration entries for name '{name}' found in {typeof(T).Name}.", nameof(name));
return results.Single();
}
@@ -48,8 +47,8 @@ public static T FromValue(int value)
{
IEnumerable results = GetAll().Where(entry => entry.Value == value).ToArray();
- Check(results.IsNotEmpty(), $"Enumeration entry for value '{value}' not found in {typeof(T).Name}.");
- Check(results.IsSingle(), $"Multiple enumeration entries for value '{value}' found in {typeof(T).Name}.");
+ Require(results.IsNotEmpty(), $"Enumeration entry for value '{value}' not found in {typeof(T).Name}.", nameof(value));
+ Require(results.IsSingle(), $"Multiple enumeration entries for value '{value}' found in {typeof(T).Name}.", nameof(value));
return results.Single();
}
diff --git a/OnixLabs.Core/Enumeration.Get.cs b/OnixLabs.Core/Enumeration.Get.cs
index 7261703..8acee6d 100644
--- a/OnixLabs.Core/Enumeration.Get.cs
+++ b/OnixLabs.Core/Enumeration.Get.cs
@@ -1,21 +1,21 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-using System.Collections.Immutable;
+using System.Collections.Frozen;
+using System.Collections.Generic;
using System.Linq;
using System.Reflection;
-using OnixLabs.Core.Linq;
namespace OnixLabs.Core;
@@ -25,39 +25,39 @@ public abstract partial class Enumeration
/// Gets all of the enumeration entries for the current type.
///
/// Returns all of the enumeration entries for the current type.
- public static ImmutableHashSet GetAll()
+ public static IReadOnlySet GetAll()
{
return typeof(T)
.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)
.Select(field => field.GetValue(null))
- .WhereIs()
- .ToImmutableHashSet();
+ .OfType()
+ .ToFrozenSet();
}
///
/// Gets all of the enumeration entries for the current type.
///
/// Returns all of the enumeration entries for the current type.
- public static ImmutableHashSet<(int Value, string Name)> GetEntries()
+ public static IReadOnlySet<(int Value, string Name)> GetEntries()
{
- return GetAll().Select(entry => entry.ToEntry()).ToImmutableHashSet();
+ return GetAll().Select(entry => entry.ToEntry()).ToFrozenSet();
}
///
/// Gets all of the enumeration names for the current type.
///
/// Returns all of the enumeration names for the current type.
- public static ImmutableHashSet GetNames()
+ public static IReadOnlySet GetNames()
{
- return GetAll().Select(entry => entry.Name).ToImmutableHashSet();
+ return GetAll().Select(entry => entry.Name).ToFrozenSet();
}
///
/// Gets all of the enumeration values for the current type.
///
/// Returns all of the enumeration values for the current type.
- public static ImmutableHashSet GetValues()
+ public static IReadOnlySet GetValues()
{
- return GetAll().Select(entry => entry.Value).ToImmutableHashSet();
+ return GetAll().Select(entry => entry.Value).ToFrozenSet();
}
-}
\ No newline at end of file
+}
diff --git a/OnixLabs.Core/Enumeration.To.cs b/OnixLabs.Core/Enumeration.To.cs
index 5432deb..800f49d 100644
--- a/OnixLabs.Core/Enumeration.To.cs
+++ b/OnixLabs.Core/Enumeration.To.cs
@@ -1,11 +1,11 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,7 +19,7 @@ namespace OnixLabs.Core;
public abstract partial class Enumeration
{
///
- /// Returns a that represents the current object.
+ /// Returns a that represents the current object.
///
/// Returns a tuple that represents the current object.
public (int Value, string Name) ToEntry()
@@ -28,11 +28,11 @@ public abstract partial class Enumeration
}
///
- /// Returns a that represents the current object.
+ /// Returns a that represents the current object.
///
- /// A that represents the current object.
+ /// Returns a that represents the current object.
public override string ToString()
{
return Name;
}
-}
\ No newline at end of file
+}
diff --git a/OnixLabs.Core/Enumeration.cs b/OnixLabs.Core/Enumeration.cs
index cf98ae2..7d9f063 100644
--- a/OnixLabs.Core/Enumeration.cs
+++ b/OnixLabs.Core/Enumeration.cs
@@ -1,43 +1,36 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+using System;
+
namespace OnixLabs.Core;
///
-/// Represents the base class for implementing enumeration classes.
+/// Represents the base class for implementing enumerations.
///
+/// The value of the enumeration entry.
+/// The name of the enumeration entry.
/// The underlying enumeration type.
-public abstract partial class Enumeration where T : Enumeration
+public abstract partial class Enumeration(int value, string name) : IEquatable, IComparable, IComparable where T : Enumeration
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// The value of the enumeration entry.
- /// The name of the enumeration entry.
- protected Enumeration(int value, string name)
- {
- Value = value;
- Name = name;
- }
-
///
/// Gets the name of the enumeration entry.
///
- public string Name { get; }
+ public string Name { get; } = name;
///
/// Gets the value of the enumeration entry.
///
- public int Value { get; }
+ public int Value { get; } = value;
}
diff --git a/OnixLabs.Core/ArrayExtensions.cs b/OnixLabs.Core/Extensions.Array.cs
similarity index 55%
rename from OnixLabs.Core/ArrayExtensions.cs
rename to OnixLabs.Core/Extensions.Array.cs
index 67d6b4c..643c00b 100644
--- a/OnixLabs.Core/ArrayExtensions.cs
+++ b/OnixLabs.Core/Extensions.Array.cs
@@ -1,18 +1,17 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-using System;
using System.ComponentModel;
namespace OnixLabs.Core;
@@ -24,47 +23,38 @@ namespace OnixLabs.Core;
public static class ArrayExtensions
{
///
- /// Copies this array.
+ /// Creates a copy of the current .
///
- /// The array to copy.
+ /// The current to copy.
/// The underlying type of the array.
- /// Returns an exact copy of this array.
+ /// Returns an exact copy of the current .
public static T[] Copy(this T[] array)
{
- return Copy(array, 0, array.Length);
+ return [..array];
}
///
- /// Copies this array.
+ /// Creates a copy of the current .
///
- /// The array to copy.
+ /// The current to copy.
/// The index of the array to begin copying from.
/// The number of elements of the array to copy.
/// The underlying type of the array.
- /// Returns an exact copy of this array.
+ /// Returns an exact copy of the current .
public static T[] Copy(this T[] array, int index, int count)
{
- T[] result = new T[count];
- Array.Copy(array, index, result, 0, count);
-
- return result;
+ return [..array[index..(index + count)]];
}
///
- /// Concatenates this array with another array.
+ /// Concatenates the current with another .
///
- /// The source array to concatenate with the other array.
- /// The other array to concatenate with the source array.
- /// The underlying type of the array.
- /// Returns this array concatenated with the other array.
+ /// The source to concatenate with the other .
+ /// The other to concatenate with the source .
+ /// The underlying type of the .
+ /// Returns the current concatenated with the other .
public static T[] ConcatenateWith(this T[] array, T[] other)
{
- int length = array.Length + other.Length;
- T[] result = new T[length];
-
- Array.Copy(array, 0, result, 0, array.Length);
- Array.Copy(other, 0, result, array.Length, other.Length);
-
- return result;
+ return [..array, ..other];
}
}
diff --git a/OnixLabs.Core/Extensions.Object.cs b/OnixLabs.Core/Extensions.Object.cs
new file mode 100644
index 0000000..8005057
--- /dev/null
+++ b/OnixLabs.Core/Extensions.Object.cs
@@ -0,0 +1,60 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using OnixLabs.Core.Reflection;
+
+namespace OnixLabs.Core;
+
+///
+/// Provides extension methods for objects.
+///
+[EditorBrowsable(EditorBrowsableState.Never)]
+public static class ObjectExtensions
+{
+ ///
+ /// Compares the current instance with the specified instance.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// The underlying type of the current .
+ /// Returns a signed integer that indicates the relative order of the objects being compared.
+ /// If the specified object is not , or of the specified type.
+ public static int CompareToObject(this IComparable comparable, object? obj)
+ {
+ if (obj is null) return 1;
+ if (obj is T other) return comparable.CompareTo(other);
+ throw new ArgumentException($"Object must be of type {typeof(T).Name}", nameof(obj));
+ }
+
+ ///
+ /// Gets a record-like representation of the current instance.
+ ///
+ /// The current instance.
+ /// Returns a record-like representation of the current instance.
+ public static string ToRecordString(this object value)
+ {
+ Type type = value.GetType();
+
+ IEnumerable properties = type
+ .GetProperties(BindingFlags.Public | BindingFlags.Instance)
+ .Select(property => $"{property.Name} = {property.GetValue(value)}");
+
+ return $"{type.GetName()} {{ {string.Join(", ", properties)} }}";
+ }
+}
diff --git a/OnixLabs.Core/Extensions.String.cs b/OnixLabs.Core/Extensions.String.cs
new file mode 100644
index 0000000..4a92b91
--- /dev/null
+++ b/OnixLabs.Core/Extensions.String.cs
@@ -0,0 +1,349 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+
+namespace OnixLabs.Core;
+
+///
+/// Provides extension methods for strings.
+///
+[EditorBrowsable(EditorBrowsableState.Never)]
+public static class StringExtensions
+{
+ ///
+ /// The value of an index not found.
+ ///
+ private const int NotFound = -1;
+
+ ///
+ /// The default string comparison.
+ ///
+ private const StringComparison DefaultComparison = StringComparison.Ordinal;
+
+ ///
+ /// The default date/time styles.
+ ///
+ private const DateTimeStyles DefaultStyles = DateTimeStyles.None;
+
+ ///
+ /// The default encoding.
+ ///
+ private static readonly Encoding DefaultEncoding = Encoding.UTF8;
+
+ ///
+ /// 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)
+ {
+ return count > 0 ? string.Join(string.Empty, Enumerable.Repeat(value, count)) : string.Empty;
+ }
+
+ ///
+ /// Obtains a sub-string before the specified index within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The index in the current from which to obtain a sub-string.
+ ///
+ /// The value to return in the event that the index is less than zero.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ /// Returns a sub-string before the specified index. If the index is less than zero, then the default value will be returned.
+ /// If the default value is , then the current instance will be returned.
+ ///
+ private static string SubstringBeforeIndex(this string value, int index, string? defaultValue = null)
+ {
+ return index <= NotFound ? defaultValue ?? value : value[..index];
+ }
+
+ ///
+ /// Obtains a sub-string after the specified index within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The index in the current from which to obtain a sub-string.
+ /// The offset from the index which marks the beginning of the sub-string.
+ ///
+ /// The value to return in the event that the index is less than zero.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ /// Returns a sub-string after the specified index. If the index is less than zero, then the default value will be returned.
+ /// If the default value is , then the current instance will be returned.
+ ///
+ private static string SubstringAfterIndex(this string value, int index, int offset, string? defaultValue = null)
+ {
+ return 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.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The delimiter to find within the current instance.
+ ///
+ /// The value to return in the event that the delimiter is not found in the current instance.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ /// Returns a sub-string before the first occurrence of the specified delimiter within the current instance.
+ /// If the delimiter is not found, then the default value will be returned.
+ /// If the default value is , then the current instance is returned.
+ ///
+ public static string SubstringBeforeFirst(this string value, char delimiter, string? defaultValue = null)
+ {
+ return value.SubstringBeforeIndex(value.IndexOf(delimiter), defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string before the first occurrence of the specified delimiter within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The delimiter to find within the current instance.
+ ///
+ /// The value to return in the event that the delimiter is not found in the current instance.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ /// The culture, case and sort rules that will be applied when searching for the specified delimiter.
+ /// The default value is .
+ ///
+ ///
+ ///Returns a sub-string before the first occurrence of the specified delimiter within the current instance.
+ /// If the delimiter is not found, then the default value will be returned.
+ /// If the default value is , then the current instance is returned.
+ ///
+ public static string SubstringBeforeFirst(this string value, string delimiter, string? defaultValue = null, StringComparison comparison = DefaultComparison)
+ {
+ return value.SubstringBeforeIndex(value.IndexOf(delimiter, comparison), defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string before the last occurrence of the specified delimiter within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The delimiter to find within the current instance.
+ ///
+ /// The value to return in the event that the delimiter is not found in the current instance.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ ///Returns a sub-string before the last occurrence of the specified delimiter within the current instance.
+ /// If the delimiter is not found, then the default value will be returned.
+ /// If the default value is , then the current instance is returned.
+ ///
+ public static string SubstringBeforeLast(this string value, char delimiter, string? defaultValue = null)
+ {
+ return value.SubstringBeforeIndex(value.LastIndexOf(delimiter), defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string before the last occurrence of the specified delimiter within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The delimiter to find within the current instance.
+ ///
+ /// The value to return in the event that the delimiter is not found in the current instance.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ /// The culture, case and sort rules that will be applied when searching for the specified delimiter.
+ /// The default value is .
+ ///
+ ///
+ ///Returns a sub-string before the last occurrence of the specified delimiter within the current instance.
+ /// If the delimiter is not found, then the default value will be returned.
+ /// If the default value is , then the current instance is returned.
+ ///
+ public static string SubstringBeforeLast(this string value, string delimiter, string? defaultValue = null, StringComparison comparison = DefaultComparison)
+ {
+ return value.SubstringBeforeIndex(value.LastIndexOf(delimiter, comparison), defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string after the first occurrence of the specified delimiter within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The delimiter to find within the current instance.
+ ///
+ /// The value to return in the event that the delimiter is not found in the current instance.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ /// Returns a sub-string after the first occurrence of the specified delimiter within the current instance.
+ /// If the delimiter is not found, then the default value will be returned.
+ /// If the default value is , then the current instance is returned.
+ ///
+ public static string SubstringAfterFirst(this string value, char delimiter, string? defaultValue = null)
+ {
+ return value.SubstringAfterIndex(value.IndexOf(delimiter), 1, defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string after the first occurrence of the specified delimiter within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The delimiter to find within the current instance.
+ ///
+ /// The value to return in the event that the delimiter is not found in the current instance.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ /// The culture, case and sort rules that will be applied when searching for the specified delimiter.
+ /// The default value is .
+ ///
+ ///
+ ///Returns a sub-string after the first occurrence of the specified delimiter within the current instance.
+ /// If the delimiter is not found, then the default value will be returned.
+ /// If the default value is , then the current instance is returned.
+ ///
+ public static string SubstringAfterFirst(this string value, string delimiter, string? defaultValue = null, StringComparison comparison = DefaultComparison)
+ {
+ return value.SubstringAfterIndex(value.IndexOf(delimiter, comparison), delimiter.Length, defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string after the last occurrence of the specified delimiter within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The delimiter to find within the current instance.
+ ///
+ /// The value to return in the event that the delimiter is not found in the current instance.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ ///Returns a sub-string after the last occurrence of the specified delimiter within the current instance.
+ /// If the delimiter is not found, then the default value will be returned.
+ /// If the default value is , then the current instance is returned.
+ ///
+ public static string SubstringAfterLast(this string value, char delimiter, string? defaultValue = null)
+ {
+ return value.SubstringAfterIndex(value.LastIndexOf(delimiter), 1, defaultValue);
+ }
+
+ ///
+ /// Obtains a sub-string after the last occurrence of the specified delimiter within the current instance.
+ ///
+ /// The current instance from which to obtain a sub-string.
+ /// The delimiter to find within the current instance.
+ ///
+ /// The value to return in the event that the delimiter is not found in the current instance.
+ /// If the default value is then the current instance is returned.
+ ///
+ ///
+ /// The culture, case and sort rules that will be applied when searching for the specified delimiter.
+ /// The default value is .
+ ///
+ ///
+ ///Returns a sub-string after the last occurrence of the specified delimiter within the current instance.
+ /// If the delimiter is not found, then the default value will be returned.
+ /// If the default value is , then the current instance is returned.
+ ///
+ public static string SubstringAfterLast(this string value, string delimiter, string? defaultValue = null, StringComparison comparison = DefaultComparison)
+ {
+ return value.SubstringAfterIndex(value.LastIndexOf(delimiter, comparison), 1, defaultValue);
+ }
+
+ ///
+ /// Converts the current instance into a new instance.
+ ///
+ /// The current from which to obtain a .
+ /// The encoding that will be used to convert the current into a .
+ /// Returns a new representation of the current instance.
+ public static byte[] ToByteArray(this string value, Encoding? encoding = null)
+ {
+ return (encoding ?? DefaultEncoding).GetBytes(value);
+ }
+
+ ///
+ /// Converts the current instance into a new instance.
+ ///
+ /// The current instance to convert.
+ /// An object that provides culture-specific formatting information.
+ /// A bit-wise combination of enumeration values that indicate the style elements that can be present.
+ /// Returns a new instance parsed from the current instance.
+ public static DateTime ToDateTime(this string value, IFormatProvider? provider = null, DateTimeStyles styles = DefaultStyles)
+ {
+ return DateTime.Parse(value, provider, styles);
+ }
+
+ ///
+ /// Converts the current instance into a new instance.
+ ///
+ /// The current instance to convert.
+ /// An object that provides culture-specific formatting information.
+ /// A bit-wise combination of enumeration values that indicate the style elements that can be present.
+ /// Returns a new instance parsed from the current instance.
+ public static DateOnly ToDateOnly(this string value, IFormatProvider? provider = null, DateTimeStyles styles = DefaultStyles)
+ {
+ return DateOnly.Parse(value, provider, styles);
+ }
+
+ ///
+ /// Converts the current instance into a new instance.
+ ///
+ /// The current instance to convert.
+ /// An object that provides culture-specific formatting information.
+ /// A bit-wise combination of enumeration values that indicate the style elements that can be present.
+ /// Returns a new instance parsed from the current instance.
+ public static TimeOnly ToTimeOnly(this string value, IFormatProvider? provider = null, DateTimeStyles styles = DefaultStyles)
+ {
+ return TimeOnly.Parse(value, provider, styles);
+ }
+
+ ///
+ /// Tries to copy the current instance into the destination .
+ ///
+ /// The current instance to copy.
+ /// The into which the current contents will be copied.
+ /// The number of characters written to the destination .
+ /// Returns if the current instance was copied into the destination ; otherwise, if the destination was too short.
+ public static bool TryCopyTo(this string value, Span destination, out int charsWritten)
+ {
+ bool result = value.TryCopyTo(destination);
+ charsWritten = result ? value.Length : 0;
+ return result;
+ }
+
+ ///
+ /// Wraps the current instance between the specified before and after instances.
+ ///
+ /// The current instance to wrap.
+ /// 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)
+ {
+ return $"{before}{value}{after}";
+ }
+
+ ///
+ /// Wraps the current instance between the specified before and after instances.
+ ///
+ /// The current instance to wrap.
+ /// 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)
+ {
+ return $"{before}{value}{after}";
+ }
+}
diff --git a/OnixLabs.Core/HashCodeExtensions.cs b/OnixLabs.Core/HashCodeExtensions.cs
deleted file mode 100644
index b22c40f..0000000
--- a/OnixLabs.Core/HashCodeExtensions.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using OnixLabs.Core.Linq;
-
-namespace OnixLabs.Core;
-
-///
-/// Provides extension methods for hash codes.
-///
-[EditorBrowsable(EditorBrowsableState.Never)]
-public static class HashCodeExtensions
-{
- ///
- /// Adds an item to be hashed into a instance.
- ///
- /// The which will receive the item to hash.
- /// The item to hash into the .
- /// The underlying type of the item to hash.
- /// Returns the containing the added item.
- public static HashCode AddItem(this HashCode hashCode, T item)
- {
- hashCode.Add(item);
- return hashCode;
- }
-
- ///
- /// Adds the items to be hashed into a instance.
- ///
- /// The which will receive the items to hash.
- /// The items to hash into the .
- /// The underlying type of the items to hash.
- /// Returns the containing the added items.
- public static HashCode AddItems(this HashCode hashCode, IEnumerable items)
- {
- items.ForEach(hashCode.Add);
- return hashCode;
- }
-}
diff --git a/OnixLabs.Core/IBinaryConvertible.cs b/OnixLabs.Core/IBinaryConvertible.cs
new file mode 100644
index 0000000..a6bace1
--- /dev/null
+++ b/OnixLabs.Core/IBinaryConvertible.cs
@@ -0,0 +1,27 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+namespace OnixLabs.Core;
+
+///
+/// Defines a type that is convertible to a binary representation.
+///
+public interface IBinaryConvertible
+{
+ ///
+ /// Gets the underlying representation of the current instance.
+ ///
+ /// Return the underlying representation of the current instance.
+ byte[] ToByteArray();
+}
diff --git a/OnixLabs.Core/IValueComparable.cs b/OnixLabs.Core/IValueComparable.cs
new file mode 100644
index 0000000..921fdeb
--- /dev/null
+++ b/OnixLabs.Core/IValueComparable.cs
@@ -0,0 +1,73 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+
+namespace OnixLabs.Core;
+
+///
+/// Defines an extension to the default and interfaces,
+/// including equality, inequality, greater than, greater than or equal, less than, and less than or equal operators.
+///
+/// The underlying type of the objects to compare.
+public interface IValueComparable : IComparable, IComparable where T : IValueComparable
+{
+ ///
+ /// Performs an equality comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is equal to the right-hand instance; otherwise, .
+ public static abstract bool operator ==(T left, T right);
+
+ ///
+ /// Performs an inequality comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is not equal to the right-hand instance; otherwise, .
+ public static abstract bool operator !=(T left, T right);
+
+ ///
+ /// Performs a greater than comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is greater than the right-hand instance; otherwise, .
+ public static abstract bool operator >(T left, T right);
+
+ ///
+ /// Performs a greater than or equal comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is greater than or equal to the right-hand instance; otherwise, .
+ public static abstract bool operator >=(T left, T right);
+
+ ///
+ /// Performs a less than comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is less than the right-hand instance; otherwise, .
+ public static abstract bool operator <(T left, T right);
+
+ ///
+ /// Performs a less than or equal comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is less than or equal to the right-hand instance; otherwise, .
+ public static abstract bool operator <=(T left, T right);
+}
diff --git a/OnixLabs.Core/IValueEquatable.cs b/OnixLabs.Core/IValueEquatable.cs
new file mode 100644
index 0000000..eafb819
--- /dev/null
+++ b/OnixLabs.Core/IValueEquatable.cs
@@ -0,0 +1,40 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+
+namespace OnixLabs.Core;
+
+///
+/// Defines an extension to the default interface, including equality and inequality operators.
+///
+/// The underlying type of the objects to compare.
+public interface IValueEquatable : IEquatable where T : IValueEquatable
+{
+ ///
+ /// Performs an equality comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is equal to the right-hand instance; otherwise, .
+ public static abstract bool operator ==(T left, T right);
+
+ ///
+ /// Performs an inequality comparison between two object instances.
+ ///
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is not equal to the right-hand instance; otherwise, .
+ public static abstract bool operator !=(T left, T right);
+}
diff --git a/OnixLabs.Core/Linq/Extensions.IEnumerable.cs b/OnixLabs.Core/Linq/Extensions.IEnumerable.cs
new file mode 100644
index 0000000..41b7ace
--- /dev/null
+++ b/OnixLabs.Core/Linq/Extensions.IEnumerable.cs
@@ -0,0 +1,244 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Numerics;
+
+namespace OnixLabs.Core.Linq;
+
+///
+/// Provides LINQ-like extension methods for .
+///
+// ReSharper disable InconsistentNaming
+[EditorBrowsable(EditorBrowsableState.Never)]
+public static class IEnumerableExtensions
+{
+ ///
+ /// Determines whether all elements of the current are equal by a specified property.
+ ///
+ /// The current on which to perform the operation.
+ /// The selector function which will be used to select the desired property from each element.
+ /// The underlying type of the .
+ /// The underlying type of each selected element.
+ /// Returns if all selected element properties are equal; otherwise .
+ public static bool AllEqualBy(this IEnumerable enumerable, Func selector)
+ {
+ return enumerable.Select(selector).Distinct().IsSingle();
+ }
+
+ ///
+ /// Determines whether any elements of the current are equal by a specified property.
+ ///
+ /// The current on which to perform the operation.
+ /// The selector function which will be used to select the desired property from each element.
+ /// The underlying type of the .
+ /// The underlying type of each selected element.
+ /// Returns if any selected element properties are equal; otherwise .
+ public static bool AnyEqualBy(this IEnumerable enumerable, Func selector)
+ {
+ return enumerable.GroupBy(selector).Any(group => group.Count() > 1);
+ }
+
+ ///
+ /// Obtains a number that represents how many elements in the current do not satisfy the specified predicate condition.
+ ///
+ /// The current on which to perform the operation.
+ /// The function to test each element for a condition.
+ /// The underlying type of the .
+ /// Returns a number that represents how many elements in the current do not satisfy the specified predicate condition.
+ public static int CountNot(this IEnumerable enumerable, Func predicate)
+ {
+ return enumerable.Count(element => !predicate(element));
+ }
+
+ ///
+ /// Performs the specified for each element of the current .
+ ///
+ /// The current over which to iterate.
+ /// The to perform for each element.
+ /// The underlying type of the .
+ public static void ForEach(this IEnumerable enumerable, Action action)
+ {
+ foreach (T element in enumerable) action(element);
+ }
+
+ ///
+ /// Gets the content hash code of the elements of the current .
+ ///
+ /// The current from which to compute a content hash code.
+ /// The underlying type of the .
+ /// Returns the computed content hash code of the current .
+ public static int GetContentHashCode(this IEnumerable enumerable)
+ {
+ HashCode result = new();
+ enumerable.ForEach(element => result.Add(element));
+ return result.ToHashCode();
+ }
+
+ ///
+ /// Determines whether the current is empty.
+ ///
+ /// The current on which to perform the operation.
+ /// The underlying type of the .
+ /// Returns if the is empty; otherwise, .
+ public static bool IsEmpty(this IEnumerable enumerable)
+ {
+ return !enumerable.Any();
+ }
+
+ ///
+ /// Determines whether the current is not empty.
+ ///
+ /// The current on which to perform the operation.
+ /// The underlying type of the .
+ /// Returns if the is not empty; otherwise, .
+ public static bool IsNotEmpty(this IEnumerable enumerable)
+ {
+ return enumerable.Any();
+ }
+
+ ///
+ /// Determines whether the current contains a single element.
+ ///
+ /// The current on which to perform the operation.
+ /// The underlying type of the .
+ /// Returns if the contains a single element; otherwise, .
+ public static bool IsSingle(this IEnumerable enumerable)
+ {
+ return enumerable.LongCount() == 1;
+ }
+
+ ///
+ /// Determines whether the current contains an even number of elements.
+ ///
+ /// The current on which to perform the operation.
+ /// The function to test each element for a condition.
+ /// The underlying type of the .
+ /// Returns if the contains an even number of elements; otherwise, .
+ public static bool IsCountEven(this IEnumerable enumerable, Func? predicate = null)
+ {
+ return enumerable.LongCount(element => predicate?.Invoke(element) ?? true) % 2 == 0;
+ }
+
+ ///
+ /// Determines whether the current contains an odd number of elements.
+ ///
+ /// The current on which to perform the operation.
+ /// The function to test each element for a condition.
+ /// The underlying type of the .
+ /// Returns if the contains an odd number of elements; otherwise, .
+ public static bool IsCountOdd(this IEnumerable enumerable, Func? predicate = null)
+ {
+ return enumerable.LongCount(element => predicate?.Invoke(element) ?? true) % 2 != 0;
+ }
+
+ ///
+ /// Joins the elements of the current into a instance.
+ ///
+ /// The current to join.
+ /// The separator which will appear between joined elements.
+ /// The underlying type of the .
+ /// Returns the elements of the current , joined into a instance.
+ public static string JoinToString(this IEnumerable enumerable, string separator = ", ")
+ {
+ return string.Join(separator, enumerable);
+ }
+
+ ///
+ /// Determines whether none of the elements of the current satisfy the specified predicate condition.
+ ///
+ /// The current on which to perform the operation.
+ /// The function to test each element for a condition.
+ /// The underlying type of the .
+ /// Returns if none of the elements of the current satisfy the specified predicate condition; otherwise, .
+ public static bool None(this IEnumerable enumerable, Func predicate)
+ {
+ return !enumerable.Any(predicate);
+ }
+
+ ///
+ /// Calculates the sum of the elements of the current .
+ ///
+ /// The current to sum.
+ /// The underlying type of the .
+ /// Returns the sum of the elements of the current .
+ public static T Sum(this IEnumerable enumerable) where T : INumberBase
+ {
+ IEnumerable numbers = enumerable as T[] ?? enumerable.ToArray();
+ return numbers.IsEmpty() ? T.Zero : numbers.Aggregate((left, right) => left + right);
+ }
+
+ ///
+ /// Calculates the sum of the elements of the current .
+ ///
+ /// The current to sum.
+ /// The selector function which will be used to select each property from each element.
+ /// The underlying type of the .
+ /// The underlying type of each element to sum.
+ /// Returns the sum of the elements of the current .
+ public static TResult SumBy(this IEnumerable enumerable, Func selector) where TResult : INumberBase
+ {
+ return enumerable.Select(selector).Sum();
+ }
+
+ ///
+ /// Filters the current elements that do not satisfy the specified predicate condition.
+ ///
+ /// The current on which to perform the operation.
+ /// The function to test each element for a condition.
+ /// The underlying type of the .
+ /// Returns a new that contains elements that do not satisfy the condition.
+ public static IEnumerable WhereNot(this IEnumerable enumerable, Func predicate)
+ {
+ return enumerable.Where(element => !predicate(element));
+ }
+
+ ///
+ /// Filters the current elements that are not .
+ ///
+ /// The current on which to perform the operation.
+ /// The underlying type of the .
+ /// Returns a new that contains elements that are not .
+ public static IEnumerable WhereNotNull(this IEnumerable enumerable) where T : notnull
+ {
+ return enumerable.Where(element => element is not null)!;
+ }
+
+ ///
+ /// Formats the current as a collection string.
+ ///
+ /// The current to format.
+ /// The underlying type of the .
+ /// Returns a new instance representing the current .
+ public static string ToCollectionString(this IEnumerable enumerable)
+ {
+ return enumerable.JoinToString().Wrap('[', ']');
+ }
+
+ ///
+ /// Formats the current as a collection string.
+ ///
+ /// The current to format.
+ /// The format which will be applied to each element.
+ /// An object that provides culture-specific formatting information.
+ /// The underlying type of the .
+ /// Returns a new instance representing the current .
+ public static string ToCollectionString(this IEnumerable enumerable, string format, IFormatProvider? provider = null) where T : IFormattable
+ {
+ return enumerable.Select(element => element.ToString(format, provider)).ToCollectionString();
+ }
+}
diff --git a/OnixLabs.Core/Linq/IEnumerableExtensions.cs b/OnixLabs.Core/Linq/IEnumerableExtensions.cs
deleted file mode 100644
index d082232..0000000
--- a/OnixLabs.Core/Linq/IEnumerableExtensions.cs
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-// ReSharper disable InconsistentNaming
-
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-
-namespace OnixLabs.Core.Linq;
-
-///
-/// Provides LINQ-like extension methods for .
-///
-[EditorBrowsable(EditorBrowsableState.Never)]
-public static class IEnumerableExtensions
-{
- ///
- /// Determines whether all elements of this are equal by a specified property.
- ///
- /// The on which to perform the operation.
- /// The selector function which will be used to select each property from each element.
- /// The underlying type of the .
- /// The underlying type of each selected element.
- /// Returns true if all selected element properties are equal; otherwise false.
- public static bool AllEqualBy(this IEnumerable enumerable, Func selector)
- {
- IEnumerable elements = enumerable.ToArray();
-
- if (elements.IsEmpty())
- {
- return false;
- }
-
- if (elements.IsSingle())
- {
- return true;
- }
-
- TProperty first = selector(elements.First());
- return elements.All(element => Equals(first, selector(element)));
- }
-
- ///
- /// Determines whether any elements of this are equal by a specified property.
- ///
- /// The on which to perform the operation.
- /// The selector function which will be used to select each property from each element.
- /// The underlying type of the .
- /// The underlying type of each selected element.
- /// Returns true if any selected element properties are equal; otherwise false.
- public static bool AnyEqualBy(this IEnumerable enumerable, Func selector)
- {
- IEnumerable elements = enumerable.ToArray();
-
- if (elements.IsEmpty())
- {
- return false;
- }
-
- if (elements.IsSingle())
- {
- return true;
- }
-
- TProperty first = selector(elements.First());
- return elements.Any(element => Equals(first, selector(element)));
- }
-
- ///
- /// Performs the specified for each element of this .
- ///
- /// The over which to iterate.
- /// The to perform for each element.
- /// The underlying type of the .
- public static void ForEach(this IEnumerable enumerable, Action action)
- {
- foreach (T element in enumerable)
- {
- action(element);
- }
- }
-
- ///
- /// Gets the content hash code of the elements of this .
- ///
- /// The from which to compute a content hash code.
- /// The underlying type of the .
- /// Returns the computed content hash code of this .
- public static int GetContentHashCode(this IEnumerable enumerable)
- {
- return new HashCode().AddItems(enumerable).ToHashCode();
- }
-
- ///
- /// Determines whether this is empty.
- ///
- /// The on which to perform the operation.
- /// he underlying type of the .
- /// Returns true if the is empty; otherwise, false.
- public static bool IsEmpty(this IEnumerable enumerable)
- {
- return !enumerable.Any();
- }
-
- ///
- /// Determines whether this is not empty.
- ///
- /// The on which to perform the operation.
- /// The underlying type of the .
- /// Returns true if the is not empty; otherwise, false.
- public static bool IsNotEmpty(this IEnumerable enumerable)
- {
- return !enumerable.IsEmpty();
- }
-
- ///
- /// Determines whether this contains a single element.
- ///
- /// The on which to perform the operation.
- /// The underlying type of the .
- /// Returns true if the contains a single element; otherwise, false.
- public static bool IsSingle(this IEnumerable enumerable)
- {
- return enumerable.LongCount() == 1;
- }
-
- ///
- /// Determines whether this contains an even number of elements.
- ///
- /// The on which to perform the operation.
- /// The underlying type of the .
- /// Returns true if the contains an even number of elements; otherwise, false.
- public static bool IsCountEven(this IEnumerable enumerable)
- {
- return enumerable.LongCount() % 2 == 0;
- }
-
- ///
- /// Determines whether this contains an odd number of elements.
- ///
- /// The on which to perform the operation.
- /// The underlying type of the .
- /// Returns true if the contains an odd number of elements; otherwise, false.
- public static bool IsCountOdd(this IEnumerable enumerable)
- {
- return !enumerable.IsCountEven();
- }
-
- ///
- /// Filters this to only elements of the specified type.
- ///
- /// The on which to perform the operation.
- /// The underlying type of the .
- /// Returns a new containing only elements of the specified type.
- public static IEnumerable WhereIs(this IEnumerable enumerable)
- {
- foreach (object? element in enumerable)
- {
- if (element is T elementOfType)
- {
- yield return elementOfType;
- }
- }
- }
-}
diff --git a/OnixLabs.Core/OnixLabs.Core.csproj b/OnixLabs.Core/OnixLabs.Core.csproj
index 69d849f..d9e77e1 100644
--- a/OnixLabs.Core/OnixLabs.Core.csproj
+++ b/OnixLabs.Core/OnixLabs.Core.csproj
@@ -1,28 +1,45 @@
-
- net6.0
- 10
+ net8.0
+ 12
enable
true
OnixLabs.Core
ONIXLabs
ONIXLabs Core API for .NET
- 5.0.0
+ 7.0.0
en
- Copyright © ONIXLabs 2020-2022
+ Copyright © ONIXLabs 2020
https://github.com/onix-labs/onixlabs-dotnet
- 5.0.0
+ 7.0.0
-
-
- true
- bin\Debug\net5.0\OnixLabs.Core.xml
+
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+ embedded
+ true
+ true
+ true
+ Apache-2.0
+ https://github.com/onix-labs/onixlabs-dotnet
+ README.md
+ true
+ true
+ git
+ https://github.com/onix-labs/onixlabs-dotnet
-
-
- bin\Release\net5.0\OnixLabs.Core.xml
- true
+
+ true
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/OnixLabs.Core/Preconditions.cs b/OnixLabs.Core/Preconditions.cs
index e38c4ac..e149ef1 100644
--- a/OnixLabs.Core/Preconditions.cs
+++ b/OnixLabs.Core/Preconditions.cs
@@ -1,11 +1,11 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -13,47 +13,88 @@
// limitations under the License.
using System;
-using System.Runtime.CompilerServices;
+using OnixLabs.Core.Linq;
namespace OnixLabs.Core;
///
-/// Provides methods for performing pre-conditions and guard clauses.
+/// Provides general methods for performing pre-conditions and guard clauses.
///
public static class Preconditions
{
///
- /// Performs a general pre-condition check, which fails if the condition returns false.
+ /// Performs a general pre-condition check that fails when the specified condition is .
///
- /// The condition to check.
- /// The exception message to throw in the event that the condition fails.
- /// The name of the parameter which is invalid.
- /// If the condition fails.
- [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
- public static void Check(bool value, string message = "Argument check failed.", string? paramName = null)
+ /// The condition to check.
+ /// The exception message to throw in the event that the specified condition is .
+ /// If the specified condition is .
+ public static void Check(bool condition, string message = "Check failed.")
{
- if (!value)
- {
- throw new ArgumentException(message, paramName);
- }
+ if (!condition) throw new InvalidOperationException(message);
}
///
- /// Performs a general pre-condition check that the specified value is not null, which fails if the value is null.
+ /// Performs a general pre-condition check that fails if the specified value is .
///
/// The nullable value to check.
- /// The exception message to throw in the event that the condition fails.
- /// The underlying type of the value to check.
- /// Returns the specified value as non-nullable in the event that the value is not null.
- /// If the condition fails and the value is null.
- [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
- public static T CheckNotNull(T? value, string message = "Argument null checked failed.") where T : notnull
+ /// The exception message to throw in the event that the specified value is .
+ /// The underlying type of the value.
+ /// Returns a non-null value of the specified type.
+ /// If the specified value is .
+ public static T CheckNotNull(T? value, string message = "Argument must not be null.") where T : notnull
{
- if (value is null)
- {
- throw new ArgumentNullException(message);
- }
+ return value ?? throw new InvalidOperationException(message);
+ }
+
+ ///
+ /// Performs a general pre-condition requirement that fails when the specified condition is .
+ ///
+ /// The condition to check.
+ /// The exception message to throw in the event that the specified condition is .
+ /// The name of the invalid paramter.
+ /// If the specified condition is .
+ public static void Require(bool condition, string message = "Argument requirement failed.", string? parameterName = null)
+ {
+ if (!condition) throw new ArgumentException(message, parameterName);
+ }
+
+ ///
+ /// Performs a general pre-condition requirement that fails when the specified condition is .
+ ///
+ /// The condition to check.
+ /// The exception message to throw in the event that the specified condition is .
+ /// The name of the invalid paramter.
+ /// If the specified condition is .
+ public static void RequireWithinRange(bool condition, string message = "Argument is out of range.", string? parameterName = null)
+ {
+ if (!condition) throw new ArgumentOutOfRangeException(parameterName, message);
+ }
+
+ ///
+ /// Performs a general pre-condition requirement that fails if the specified value is .
+ ///
+ /// The nullable value to check.
+ /// The exception message to throw in the event that the specified value is .
+ /// The name of the invalid parameter.
+ /// The underlying type of the value.
+ /// Returns a non-null value of the specified type.
+ /// If the specified value is .
+ public static T RequireNotNull(T? value, string message = "Argument must not be null.", string? parameterName = null) where T : notnull
+ {
+ return value ?? throw new ArgumentNullException(parameterName, message);
+ }
+
+ ///
+ /// Performs a general pre-condition requirement that the specified value is defined by the specified type.
+ ///
+ /// The enum value to check.
+ /// The name of the invalid parameter.
+ /// The underlying type of the .
+ public static void RequireIsDefined(T value, string? parameterName = null) where T : struct, Enum
+ {
+ if (Enum.IsDefined(value)) return;
- return value;
+ string message = $"Invalid {typeof(T).Name} enum value: {value}. Valid values include: {Enum.GetNames().JoinToString()}.";
+ throw new ArgumentOutOfRangeException(parameterName, message);
}
}
diff --git a/OnixLabs.Core/Reflection/Extensions.Type.cs b/OnixLabs.Core/Reflection/Extensions.Type.cs
new file mode 100644
index 0000000..7ca3965
--- /dev/null
+++ b/OnixLabs.Core/Reflection/Extensions.Type.cs
@@ -0,0 +1,40 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.ComponentModel;
+
+namespace OnixLabs.Core.Reflection;
+
+///
+/// Provides extension methods for types.
+///
+[EditorBrowsable(EditorBrowsableState.Never)]
+public static class TypeExtensions
+{
+ ///
+ /// The identifier marker than indicates a generic type.
+ ///
+ private const char GenericTypeIdentifierMarker = '`';
+
+ ///
+ /// Gets the simple type name from the current instance.
+ ///
+ /// The current instance from which to obtain the simple name.
+ /// Returns the simple type name from the current instance.
+ public static string GetName(this Type type)
+ {
+ return type.Name.SubstringBeforeFirst(GenericTypeIdentifierMarker);
+ }
+}
diff --git a/OnixLabs.Core/StringExtensions.cs b/OnixLabs.Core/StringExtensions.cs
deleted file mode 100644
index 6be0262..0000000
--- a/OnixLabs.Core/StringExtensions.cs
+++ /dev/null
@@ -1,228 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.ComponentModel;
-using System.Text;
-
-namespace OnixLabs.Core;
-
-///
-/// Provides extension methods for strings.
-///
-[EditorBrowsable(EditorBrowsableState.Never)]
-public static class StringExtensions
-{
- ///
- /// The value of an index not found.
- ///
- private const int IndexNotFound = -1;
-
- ///
- /// Returns a substring before the first occurrence of the specified delimiter.
- ///
- /// The original from which to obtain a sub-string.
- /// The delimiter to find within the original string.
- /// The value to return if the delimiter is not found, which defaults to the original string.
- /// Returns a substring before the first occurrence of the specified delimiter.
- public static string SubstringBefore(this string value, char delimiter, string? defaultValue = null)
- {
- int index = value.IndexOf(delimiter);
-
- return index switch
- {
- IndexNotFound => defaultValue ?? value,
- _ => value[..index]
- };
- }
-
- ///
- /// Returns a substring before the first occurrence of the specified delimiter.
- ///
- /// The original from which to obtain a sub-string.
- /// The delimiter to find within the original string.
- /// The value to return if the delimiter is not found, which defaults to the original string.
- /// Specifies the string comparison rule for the search.
- /// Returns a substring before the first occurrence of the specified delimiter.
- public static string SubstringBefore(
- this string value,
- string delimiter,
- string? defaultValue = null,
- StringComparison comparison = StringComparison.Ordinal)
- {
- int index = value.IndexOf(delimiter, comparison);
-
- return index switch
- {
- IndexNotFound => defaultValue ?? value,
- _ => value[..index]
- };
- }
-
- ///
- /// Returns a substring before the last occurrence of the specified delimiter.
- ///
- /// The original from which to obtain a sub-string.
- /// The delimiter to find within the original string.
- /// The value to return if the delimiter is not found, which defaults to the original string.
- /// Returns a substring before the last occurrence of the specified delimiter.
- public static string SubstringBeforeLast(this string value, char delimiter, string? defaultValue = null)
- {
- int index = value.LastIndexOf(delimiter);
-
- return index switch
- {
- IndexNotFound => defaultValue ?? value,
- _ => value[..index]
- };
- }
-
- ///
- /// Returns a substring before the last occurrence of the specified delimiter.
- ///
- /// The original from which to obtain a sub-string.
- /// The delimiter to find within the original string.
- /// The value to return if the delimiter is not found, which defaults to the original string.
- /// Specifies the string comparison rule for the search.
- /// Returns a substring before the last occurrence of the specified delimiter.
- public static string SubstringBeforeLast(
- this string value,
- string delimiter,
- string? defaultValue = null,
- StringComparison comparison = StringComparison.Ordinal)
- {
- int index = value.LastIndexOf(delimiter, comparison);
-
- return index switch
- {
- IndexNotFound => defaultValue ?? value,
- _ => value[..index]
- };
- }
-
- ///
- /// Returns a substring after the first occurrence of the specified delimiter.
- ///
- /// The original from which to obtain a sub-string.
- /// The delimiter to find within the original string.
- /// The value to return if the delimiter is not found, which defaults to the original string.
- /// Returns a substring after the first occurrence of the specified delimiter.
- public static string SubstringAfter(this string value, char delimiter, string? defaultValue = null)
- {
- int index = value.IndexOf(delimiter);
-
- return index switch
- {
- IndexNotFound => defaultValue ?? value,
- _ => value[(index + 1)..value.Length]
- };
- }
-
- ///
- /// Returns a substring after the first occurrence of the specified delimiter.
- ///
- /// The original from which to obtain a sub-string.
- /// The delimiter to find within the original string.
- /// The value to return if the delimiter is not found, which defaults to the original string.
- /// Specifies the string comparison rule for the search.
- /// Returns a substring after the first occurrence of the specified delimiter.
- public static string SubstringAfter(
- this string value,
- string delimiter,
- string? defaultValue = null,
- StringComparison comparison = StringComparison.Ordinal)
- {
- int index = value.IndexOf(delimiter, comparison);
-
- return index switch
- {
- IndexNotFound => defaultValue ?? value,
- _ => value[(index + delimiter.Length)..value.Length]
- };
- }
-
- ///
- /// Returns a substring after the last occurrence of the specified delimiter.
- ///
- /// The original from which to obtain a sub-string.
- /// The delimiter to find within the original string.
- /// The value to return if the delimiter is not found, which defaults to the original string.
- /// Returns a substring after the last occurrence of the specified delimiter.
- public static string SubstringAfterLast(this string value, char delimiter, string? defaultValue = null)
- {
- int index = value.LastIndexOf(delimiter);
-
- return index switch
- {
- IndexNotFound => defaultValue ?? value,
- _ => value[(index + 1)..value.Length]
- };
- }
-
- ///
- /// Returns a substring after the last occurrence of the specified delimiter.
- ///
- /// The original from which to obtain a sub-string.
- /// The delimiter to find within the original string.
- /// The value to return if the delimiter is not found, which defaults to the original string.
- /// Specifies the string comparison rule for the search.
- /// Returns a substring after the last occurrence of the specified delimiter.
- public static string SubstringAfterLast(
- this string value,
- string delimiter,
- string? defaultValue = null,
- StringComparison comparison = StringComparison.Ordinal)
- {
- int index = value.LastIndexOf(delimiter, comparison);
-
- return index switch
- {
- IndexNotFound => defaultValue ?? value,
- _ => value[(index + delimiter.Length)..value.Length]
- };
- }
-
- ///
- /// Converts the current to a array using the default .
- ///
- /// The original from which to obtain a byte array.
- /// Returns a array using the default .
- public static byte[] ToByteArray(this string value)
- {
- return ToByteArray(value, Encoding.Default);
- }
-
- ///
- /// Converts the current to a array using the specified .
- ///
- /// The original from which to obtain a byte array.
- /// The which will be used to convert the current to a array.
- /// Returns a array using the specified .
- public static byte[] ToByteArray(this string value, Encoding encoding)
- {
- return encoding.GetBytes(value);
- }
-
- ///
- /// Converts the current between the specified before and after values.
- ///
- /// The current value to wrap.
- /// The that should precede the current value.
- /// The that should succeed the current value.
- /// Returns the current wrapped between the specified before and after values.
- public static string Wrap(this string value, string before, string after)
- {
- return $"{before}{value}{after}";
- }
-}
diff --git a/OnixLabs.Core/Text/Base16.Equatable.cs b/OnixLabs.Core/Text/Base16.Equatable.cs
index e4d923f..dee52b2 100644
--- a/OnixLabs.Core/Text/Base16.Equatable.cs
+++ b/OnixLabs.Core/Text/Base16.Equatable.cs
@@ -1,73 +1,72 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-using System;
using System.Linq;
using OnixLabs.Core.Linq;
namespace OnixLabs.Core.Text;
-public readonly partial struct Base16 : IEquatable
+public readonly partial struct Base16
{
///
- /// Performs an equality check between two object instances.
+ /// Checks whether the current object is equal to another object of the same type.
///
- /// Instance a.
- /// Instance b.
- /// True if the instances are equal; otherwise, false.
- public static bool operator ==(Base16 a, Base16 b)
+ /// An object to compare with the current object.
+ /// Returns if the current object is equal to the other parameter; otherwise, .
+ public bool Equals(Base16 other)
{
- return Equals(a, b);
+ return other.value.SequenceEqual(value);
}
///
- /// Performs an inequality check between two object instances.
+ /// Checks for equality between the current instance and another object.
///
- /// Instance a.
- /// Instance b.
- /// True if the instances are not equal; otherwise, false.
- public static bool operator !=(Base16 a, Base16 b)
+ /// The object to check for equality.
+ /// Returns if the object is equal to the current instance; otherwise, .
+ public override bool Equals(object? obj)
{
- return !Equals(a, b);
+ return obj is Base16 other && Equals(other);
}
///
- /// Checks for equality between this instance and another object.
+ /// Serves as a hash code function for the current instance.
///
- /// The object to check for equality.
- /// true if the object is equal to this instance; otherwise, false.
- public bool Equals(Base16 other)
+ /// Returns a hash code for the current instance.
+ public override int GetHashCode()
{
- return other.Value.SequenceEqual(Value);
+ return value.GetContentHashCode();
}
///
- /// Checks for equality between this instance and another object.
+ /// Performs an equality comparison between two object instances.
///
- /// The object to check for equality.
- /// true if the object is equal to this instance; otherwise, false.
- public override bool Equals(object? obj)
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is equal to the right-hand instance; otherwise, .
+ public static bool operator ==(Base16 left, Base16 right)
{
- return obj is Base16 other && Equals(other);
+ return Equals(left, right);
}
///
- /// Serves as a hash code function for this instance.
+ /// Performs an inequality comparison between two object instances.
///
- /// A hash code for this instance.
- public override int GetHashCode()
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is not equal to the right-hand instance; otherwise, .
+ public static bool operator !=(Base16 left, Base16 right)
{
- return HashCode.Combine(Value.GetContentHashCode());
+ return !Equals(left, right);
}
}
diff --git a/OnixLabs.Core/Text/Base16.Format.cs b/OnixLabs.Core/Text/Base16.Format.cs
new file mode 100644
index 0000000..ff7eb9f
--- /dev/null
+++ b/OnixLabs.Core/Text/Base16.Format.cs
@@ -0,0 +1,33 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+
+namespace OnixLabs.Core.Text;
+
+public readonly partial struct Base16
+{
+ ///
+ /// Tries to format the value of the current instance into the provided span of characters.
+ ///
+ /// The span in which to write this instance's value formatted as a span of characters.
+ /// When this method returns, contains the number of characters that were written in .
+ /// A span containing the characters that represent a standard or custom format string that defines the acceptable format for .
+ /// An optional object that supplies culture-specific formatting information for .
+ /// Returns if the formatting was successful; otherwise, .
+ bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider)
+ {
+ return ToString(format, provider).TryCopyTo(destination, out charsWritten);
+ }
+}
diff --git a/OnixLabs.Core/Text/Base16.From.cs b/OnixLabs.Core/Text/Base16.From.cs
deleted file mode 100644
index 361de10..0000000
--- a/OnixLabs.Core/Text/Base16.From.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.Linq;
-using System.Text;
-
-namespace OnixLabs.Core.Text;
-
-public readonly partial struct Base16
-{
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// Returns a new instance.
- public static Base16 FromByteArray(byte[] value)
- {
- return new Base16(value);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// Returns a new instance.
- public static Base16 FromCharArray(char[] value)
- {
- return FromCharArray(value, Encoding.Default);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// Returns a new instance.
- public static Base16 FromCharArray(char[] value, Encoding encoding)
- {
- byte[] bytes = encoding.GetBytes(value);
- return FromByteArray(bytes);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// Returns a new instance.
- public static Base16 FromSpan(ReadOnlySpan value)
- {
- return FromSpan(value, Encoding.Default);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// Returns a new instance.
- public static Base16 FromSpan(ReadOnlySpan value, Encoding encoding)
- {
- char[] characters = value.ToArray();
- return FromCharArray(characters, encoding);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// Returns a new instance.
- public static Base16 FromString(string value)
- {
- return FromString(value, Encoding.Default);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// Returns a new instance.
- public static Base16 FromString(string value, Encoding encoding)
- {
- char[] characters = value.ToArray();
- return FromCharArray(characters, encoding);
- }
-}
diff --git a/OnixLabs.Core/Text/Base16.Parse.cs b/OnixLabs.Core/Text/Base16.Parse.cs
index 5ce2028..880eae8 100644
--- a/OnixLabs.Core/Text/Base16.Parse.cs
+++ b/OnixLabs.Core/Text/Base16.Parse.cs
@@ -1,11 +1,11 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,35 +19,62 @@ namespace OnixLabs.Core.Text;
public readonly partial struct Base16
{
///
- /// Parses a Base-16 (hexadecimal) value into a instance.
+ /// Parses the specified Base-16 encoded value into a value.
///
- /// The Base-16 (hexadecimal) value to parse.
- /// Returns a new instance.
- public static Base16 Parse(string value)
+ /// The Base-16 encoded value to parse.
+ /// The format provider that will be used to decode the specified value.
+ /// Returns a new instance, parsed from the specified Base-16 encoded value.
+ public static Base16 Parse(string value, IFormatProvider? provider = null)
{
- ReadOnlySpan characters = value.AsSpan();
- return Parse(characters);
+ return Parse(value.AsSpan(), provider);
}
///
- /// Parses a Base-16 (hexadecimal) value into a instance.
+ /// Parses the specified Base-16 encoded value into a value.
///
- /// The Base-16 (hexadecimal) value to parse.
- /// Returns a new instance.
- public static Base16 Parse(char[] value)
+ /// The Base-16 encoded value to parse.
+ /// The format provider that will be used to decode the specified value.
+ /// Returns a new instance, parsed from the specified Base-16 encoded value.
+ public static Base16 Parse(ReadOnlySpan value, IFormatProvider? provider = null)
{
- ReadOnlySpan characters = value.AsSpan();
- return Parse(characters);
+ byte[] bytes = IBaseCodec.Base16.Decode(value, provider);
+ return new Base16(bytes);
}
///
- /// Parses a Base-16 (hexadecimal) value into a instance.
+ /// Tries to parse the specified Base-16 encoded value into a value.
///
- /// The Base-16 (hexadecimal) value to parse.
- /// Returns a new instance.
- public static Base16 Parse(ReadOnlySpan value)
+ /// The Base-16 encoded value to parse.
+ /// The format provider that will be used to decode the specified value.
+ ///
+ /// A new instance, parsed from the specified Base-16 encoded value,
+ /// or the default value if the specified Base-16 encoded could not be parsed.
+ ///
+ /// Returns if the specified Base-16 value was decoded successfully; otherwise, .
+ public static bool TryParse(string? value, IFormatProvider? provider, out Base16 result)
{
- byte[] bytes = Convert.FromHexString(value);
- return FromByteArray(bytes);
+ return TryParse(value.AsSpan(), provider, out result);
+ }
+
+ ///
+ /// Tries to parse the specified Base-16 encoded value into a value.
+ ///
+ /// The Base-16 encoded value to parse.
+ /// The format provider that will be used to decode the specified value.
+ ///
+ /// A new instance, parsed from the specified Base-16 encoded value,
+ /// or the default value if the specified Base-16 encoded could not be parsed.
+ ///
+ /// Returns if the specified Base-16 value was decoded successfully; otherwise, .
+ public static bool TryParse(ReadOnlySpan value, IFormatProvider? provider, out Base16 result)
+ {
+ if (IBaseCodec.Base16.TryDecode(value, provider, out byte[] bytes))
+ {
+ result = new Base16(bytes);
+ return true;
+ }
+
+ result = default;
+ return false;
}
}
diff --git a/OnixLabs.Core/Text/Base16.To.cs b/OnixLabs.Core/Text/Base16.To.cs
index f26ab6b..1cc48cd 100644
--- a/OnixLabs.Core/Text/Base16.To.cs
+++ b/OnixLabs.Core/Text/Base16.To.cs
@@ -1,11 +1,11 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -13,46 +13,58 @@
// limitations under the License.
using System;
-using System.Text;
namespace OnixLabs.Core.Text;
public readonly partial struct Base16
{
///
- /// Returns a array that represents the current object.
+ /// Gets the underlying representation of the current instance.
///
- /// Returns a array that represents the current object.
+ /// Return the underlying representation of the current instance.
public byte[] ToByteArray()
{
- return Value.Copy();
+ return value.Copy();
}
///
- /// Returns a that represents the current object in plain text.
+ /// Returns a that represents the current object.
///
- /// Returns a that represents the current object in plain text.
- public string ToPlainTextString()
+ /// Returns a that represents the current object.
+ public override string ToString()
{
- return ToPlainTextString(Encoding.Default);
+ return ToString(Base16FormatProvider.Invariant);
}
///
- /// Returns a that represents the current object in plain text.
+ /// Formats the value of the current instance using the specified format.
///
- /// The encoding to use to obtain the underlying value.
- /// Returns a that represents the current object in plain text.
- public string ToPlainTextString(Encoding encoding)
+ /// The provider to use to format the value.
+ /// The value of the current instance in the specified format.
+ public string ToString(IFormatProvider? formatProvider)
{
- return encoding.GetString(Value);
+ return ToString(null, formatProvider);
}
///
- /// Returns a that represents the current object.
+ /// Formats the value of the current instance using the specified format.
///
- /// A that represents the current object.
- public override string ToString()
+ /// The format to use.
+ /// The provider to use to format the value.
+ /// The value of the current instance in the specified format.
+ public string ToString(string? format, IFormatProvider? formatProvider)
+ {
+ return ToString(format.AsSpan(), formatProvider);
+ }
+
+ ///
+ /// Formats the value of the current instance using the specified format.
+ ///
+ /// The format to use.
+ /// The provider to use to format the value.
+ /// The value of the current instance in the specified format.
+ public string ToString(ReadOnlySpan format, IFormatProvider? formatProvider)
{
- return Convert.ToHexString(Value).ToLower();
+ return IBaseCodec.Base16.Encode(value, formatProvider);
}
}
diff --git a/OnixLabs.Core/Text/Base16.cs b/OnixLabs.Core/Text/Base16.cs
index bf6bbcc..eeba0e6 100644
--- a/OnixLabs.Core/Text/Base16.cs
+++ b/OnixLabs.Core/Text/Base16.cs
@@ -1,35 +1,33 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
+using System;
+
namespace OnixLabs.Core.Text;
///
-/// Represents a Base-16 (hexadecimal) value.
+/// Represents a Base-16 value.
///
-public readonly partial struct Base16
+/// The underlying value.
+public readonly partial struct Base16(ReadOnlySpan value) : IBaseValue
{
+ private readonly byte[] value = value.ToArray();
+
///
- /// Initializes a new instance of the struct.
+ /// Initializes a new default value.
///
- /// The underlying value.
- private Base16(byte[] value)
+ public Base16() : this([])
{
- Value = value;
}
-
- ///
- /// Gets the underlying value.
- ///
- private byte[] Value { get; }
}
diff --git a/OnixLabs.Core/Text/Base16Codec.cs b/OnixLabs.Core/Text/Base16Codec.cs
new file mode 100644
index 0000000..fcc49b4
--- /dev/null
+++ b/OnixLabs.Core/Text/Base16Codec.cs
@@ -0,0 +1,143 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+using System.Buffers;
+
+namespace OnixLabs.Core.Text;
+
+///
+/// Represents a codec for encoding and decoding Base-16 values.
+///
+public sealed class Base16Codec : IBaseCodec
+{
+ private static readonly SearchValues Base16UppercaseValues = SearchValues.Create("ABCDEF");
+
+ private static readonly SearchValues Base16LowercaseValues = SearchValues.Create("abcdef");
+
+ ///
+ /// Encodes the specified value into a Base-16 representation.
+ ///
+ /// The value to encode into a Base-16 representation.
+ /// The format provider that will be used to encode the specified value.
+ /// Returns a new Base-16 representation encoded from the specified value.
+ public string Encode(ReadOnlySpan value, IFormatProvider? provider = null)
+ {
+ if (TryEncode(value, provider, out string result)) return result;
+ throw new FormatException(IBaseCodec.EncodingFormatException);
+ }
+
+ ///
+ /// Decodes the specified Base-16 representation into a .
+ ///
+ /// The Base-16 value to decode into a .
+ /// The format provider that will be used to decode the specified value.
+ /// Returns a new decoded from the specified value.
+ public byte[] Decode(ReadOnlySpan value, IFormatProvider? provider = null)
+ {
+ if (TryDecode(value, provider, out byte[] result)) return result;
+ throw new FormatException(IBaseCodec.DecodingFormatException);
+ }
+
+ ///
+ /// Tries to encode the specified value into a Base-16 representation.
+ ///
+ /// The value to encode into a Base-16 representation.
+ /// The format provider that will be used to encode the specified value.
+ ///
+ /// A new Base-16 representation encoded from the specified value,
+ /// or an empty string if the specified value could not be encoded.
+ ///
+ /// Returns if the specified value was encoded successfully; otherwise, .
+ public bool TryEncode(ReadOnlySpan value, IFormatProvider? provider, out string result)
+ {
+ try
+ {
+ if (value.IsEmpty)
+ {
+ result = string.Empty;
+ return true;
+ }
+
+ if (provider is not null && provider is not Base16FormatProvider)
+ {
+ result = string.Empty;
+ return false;
+ }
+
+ Base16FormatProvider formatProvider = provider as Base16FormatProvider ?? Base16FormatProvider.Invariant;
+
+ result = formatProvider == Base16FormatProvider.Uppercase
+ ? Convert.ToHexString(value)
+ : Convert.ToHexString(value).ToLower();
+
+ return true;
+ }
+ catch
+ {
+ result = string.Empty;
+ return false;
+ }
+ }
+
+ ///
+ /// Tries to decode the specified Base-16 representation into a .
+ ///
+ /// The Base-16 value to decode into a .
+ /// The format provider that will be used to decode the specified value.
+ ///
+ /// A new decoded from the specified value,
+ /// or an empty if the specified value could not be decoded.
+ ///
+ /// Returns if the specified value was decoded successfully; otherwise, .
+ public bool TryDecode(ReadOnlySpan value, IFormatProvider? provider, out byte[] result)
+ {
+ try
+ {
+ if (value.IsEmpty)
+ {
+ result = [];
+ return true;
+ }
+
+ if (provider is not null && provider is not Base16FormatProvider)
+ {
+ result = [];
+ return false;
+ }
+
+ Base16FormatProvider formatProvider = provider as Base16FormatProvider ?? Base16FormatProvider.Invariant;
+
+ if (formatProvider == Base16FormatProvider.Uppercase && value.ContainsAny(Base16LowercaseValues))
+ {
+ result = [];
+ return false;
+ }
+
+ if (formatProvider == Base16FormatProvider.Lowercase && value.ContainsAny(Base16UppercaseValues))
+ {
+ result = [];
+ return false;
+ }
+
+ result = Convert.FromHexString(value);
+ return true;
+ }
+ catch
+ {
+ result = [];
+ return false;
+ }
+ }
+}
diff --git a/OnixLabs.Core/Text/Base16FormatProvider.cs b/OnixLabs.Core/Text/Base16FormatProvider.cs
new file mode 100644
index 0000000..82541cf
--- /dev/null
+++ b/OnixLabs.Core/Text/Base16FormatProvider.cs
@@ -0,0 +1,67 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+
+namespace OnixLabs.Core.Text;
+
+///
+/// Represents a Base-16 format provider.
+///
+public sealed class Base16FormatProvider : Enumeration, IFormatProvider
+{
+ ///
+ /// Gets the invariant Base-16 format provider.
+ /// The invariant format provider favours lowercase for Base-16 encoding.
+ /// The alphabet provided by this format provider is not a strict Base-16 alphabet as it contains all uppercase and lowercase values.
+ ///
+ public static readonly Base16FormatProvider Invariant = new(0, nameof(Invariant), "0123456789ABCDEFabcdef");
+
+ ///
+ /// Gets the uppercase Base-16 format provider.
+ ///
+ public static readonly Base16FormatProvider Uppercase = new(1, nameof(Uppercase), "0123456789ABCDEF");
+
+ ///
+ /// Gets the lowercase Base-16 format provider.
+ ///
+ public static readonly Base16FormatProvider Lowercase = new(2, nameof(Lowercase), "0123456789abcdef");
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The value of the enumeration entry.
+ /// The name of the enumeration entry.
+ /// The alphabet of the format provider.
+ private Base16FormatProvider(int value, string name, string alphabet) : base(value, name)
+ {
+ Alphabet = alphabet;
+ }
+
+ ///
+ /// Gets the alphabet of the current instance.
+ ///
+ public string Alphabet { get; }
+
+ /// Gets an object that provides formatting services for the specified type.
+ /// An object that specifies the type of format object to return.
+ ///
+ /// Returns an instance of the object specified by ,
+ /// if the implementation can supply that type of object; otherwise, .
+ ///
+ public object? GetFormat(Type? formatType)
+ {
+ return formatType == typeof(Base16FormatProvider) ? this : null;
+ }
+}
diff --git a/OnixLabs.Core/Text/Base32.Codec.cs b/OnixLabs.Core/Text/Base32.Codec.cs
deleted file mode 100644
index 254c197..0000000
--- a/OnixLabs.Core/Text/Base32.Codec.cs
+++ /dev/null
@@ -1,156 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.Text;
-
-namespace OnixLabs.Core.Text;
-
-public readonly partial struct Base32
-{
- ///
- /// The Base-32 input data size.
- ///
- private const int InputSize = 8;
-
- ///
- /// The Base-32 output data size.
- ///
- private const int OutputSize = 5;
-
- ///
- /// Encode a byte array into a Base-32 string.
- ///
- /// The value to encode.
- /// The Base-32 alphabet to use for encoding.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a Base-32 encoded string.
- private static string Encode(byte[] value, string alphabet, bool padding)
- {
- if (value.Length == 0)
- {
- return string.Empty;
- }
-
- StringBuilder builder = new(value.Length * InputSize / OutputSize);
-
- int inputPosition = 0;
- int inputSubPosition = 0;
- byte outputPosition = 0;
- int outputSubPosition = 0;
-
- while (inputPosition < value.Length)
- {
- int availableBits = Math.Min(InputSize - inputSubPosition, OutputSize - outputSubPosition);
-
- outputPosition <<= availableBits;
- outputPosition |= (byte) (value[inputPosition] >> (InputSize - (inputSubPosition + availableBits)));
- inputSubPosition += availableBits;
-
- if (inputSubPosition >= InputSize)
- {
- inputPosition++;
- inputSubPosition = 0;
- }
-
- outputSubPosition += availableBits;
-
- if (outputSubPosition < OutputSize) continue;
-
- outputPosition &= 0x1F;
- builder.Append(alphabet[outputPosition]);
- outputSubPosition = 0;
- }
-
- if (outputSubPosition <= 0) return builder.ToString();
-
- outputPosition <<= (OutputSize - outputSubPosition);
- outputPosition &= 0x1F;
- builder.Append(alphabet[outputPosition]);
-
- while (padding && builder.Length % InputSize != 0)
- {
- builder.Append('=');
- }
-
- return builder.ToString();
- }
-
- ///
- /// Decodes a Base-32 into a byte array.
- ///
- /// The value to decode.
- /// The Base-32 alphabet to use for decoding.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a byte array.
- /// If the Base-32 string format is invalid.
- private static byte[] Decode(ReadOnlySpan value, string alphabet, bool padding)
- {
- if (value == string.Empty)
- {
- return Array.Empty();
- }
-
- if (padding && value.Length % InputSize != 0)
- {
- throw new FormatException("Base32 string is invalid. Insufficient padding has been applied.");
- }
-
- ReadOnlySpan valueWithoutPadding = padding ? value.TrimEnd('=') : value;
-
- byte[] outputBytes = new byte[valueWithoutPadding.Length * OutputSize / InputSize];
-
- if (outputBytes.Length == 0)
- {
- throw new FormatException("Base32 string is invalid. Not enough data to construct byte array.");
- }
-
- int inputPosition = 0;
- int inputSubPosition = 0;
- int outputPosition = 0;
- int outputSubPosition = 0;
-
- while (outputPosition < outputBytes.Length)
- {
- char character = valueWithoutPadding[inputPosition];
- int index = alphabet.IndexOf(character);
-
- if (index < 0)
- {
- throw new FormatException($"Invalid Base32 character '{character}' at position {inputPosition}");
- }
-
- int availableBits = Math.Min(OutputSize - inputSubPosition, InputSize - outputSubPosition);
-
- outputBytes[outputPosition] <<= availableBits;
- outputBytes[outputPosition] |= (byte) (index >> (OutputSize - (inputSubPosition + availableBits)));
- outputSubPosition += availableBits;
-
- if (outputSubPosition >= InputSize)
- {
- outputPosition++;
- outputSubPosition = 0;
- }
-
- inputSubPosition += availableBits;
-
- if (inputSubPosition < OutputSize) continue;
-
- inputPosition++;
- inputSubPosition = 0;
- }
-
- return outputBytes;
- }
-}
diff --git a/OnixLabs.Core/Text/Base32.Equatable.cs b/OnixLabs.Core/Text/Base32.Equatable.cs
index ebdd552..e9f993e 100644
--- a/OnixLabs.Core/Text/Base32.Equatable.cs
+++ b/OnixLabs.Core/Text/Base32.Equatable.cs
@@ -1,73 +1,72 @@
-// Copyright 2020-2022 ONIXLabs
-//
+// Copyright 2020 ONIXLabs
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-using System;
using System.Linq;
using OnixLabs.Core.Linq;
namespace OnixLabs.Core.Text;
-public readonly partial struct Base32 : IEquatable
+public readonly partial struct Base32
{
///
- /// Performs an equality check between two object instances.
+ /// Checks whether the current object is equal to another object of the same type.
///
- /// Instance a.
- /// Instance b.
- /// True if the instances are equal; otherwise, false.
- public static bool operator ==(Base32 a, Base32 b)
+ /// An object to compare with the current object.
+ /// Returns if the current object is equal to the other parameter; otherwise, .
+ public bool Equals(Base32 other)
{
- return Equals(a, b);
+ return other.value.SequenceEqual(value);
}
///
- /// Performs an inequality check between two object instances.
+ /// Checks for equality between the current instance and another object.
///
- /// Instance a.
- /// Instance b.
- /// True if the instances are not equal; otherwise, false.
- public static bool operator !=(Base32 a, Base32 b)
+ /// The object to check for equality.
+ /// Returns if the object is equal to the current instance; otherwise, .
+ public override bool Equals(object? obj)
{
- return !Equals(a, b);
+ return obj is Base32 other && Equals(other);
}
///
- /// Checks for equality between this instance and another object.
+ /// Serves as a hash code function for the current instance.
///
- /// The object to check for equality.
- /// true if the object is equal to this instance; otherwise, false.
- public bool Equals(Base32 other)
+ /// Returns a hash code for the current instance.
+ public override int GetHashCode()
{
- return other.Value.SequenceEqual(Value) && other.Alphabet == Alphabet && other.Padding == Padding;
+ return value.GetContentHashCode();
}
///
- /// Checks for equality between this instance and another object.
+ /// Performs an equality comparison between two object instances.
///
- /// The object to check for equality.
- /// true if the object is equal to this instance; otherwise, false.
- public override bool Equals(object? obj)
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is equal to the right-hand instance; otherwise, .
+ public static bool operator ==(Base32 left, Base32 right)
{
- return obj is Base32 other && Equals(other);
+ return Equals(left, right);
}
///
- /// Serves as a hash code function for this instance.
+ /// Performs an inequality comparison between two object instances.
///
- /// A hash code for this instance.
- public override int GetHashCode()
+ /// The left-hand instance to compare.
+ /// The right-hand instance to compare.
+ /// Returns if the left-hand instance is not equal to the right-hand instance; otherwise, .
+ public static bool operator !=(Base32 left, Base32 right)
{
- return HashCode.Combine(Value.GetContentHashCode());
+ return !Equals(left, right);
}
}
diff --git a/OnixLabs.Core/Text/Base32.Format.cs b/OnixLabs.Core/Text/Base32.Format.cs
new file mode 100644
index 0000000..447bd83
--- /dev/null
+++ b/OnixLabs.Core/Text/Base32.Format.cs
@@ -0,0 +1,33 @@
+// Copyright 2020 ONIXLabs
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System;
+
+namespace OnixLabs.Core.Text;
+
+public readonly partial struct Base32
+{
+ ///
+ /// Tries to format the value of the current instance into the provided span of characters.
+ ///
+ /// The span in which to write this instance's value formatted as a span of characters.
+ /// When this method returns, contains the number of characters that were written in .
+ /// A span containing the characters that represent a standard or custom format string that defines the acceptable format for .
+ /// An optional object that supplies culture-specific formatting information for .
+ /// Returns if the formatting was successful; otherwise, .
+ bool ISpanFormattable.TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider)
+ {
+ return ToString(format, provider).TryCopyTo(destination, out charsWritten);
+ }
+}
diff --git a/OnixLabs.Core/Text/Base32.From.cs b/OnixLabs.Core/Text/Base32.From.cs
deleted file mode 100644
index 0105180..0000000
--- a/OnixLabs.Core/Text/Base32.From.cs
+++ /dev/null
@@ -1,349 +0,0 @@
-// Copyright 2020-2022 ONIXLabs
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.Linq;
-using System.Text;
-
-namespace OnixLabs.Core.Text;
-
-public readonly partial struct Base32
-{
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// Returns a new instance.
- public static Base32 FromByteArray(byte[] value)
- {
- return FromByteArray(value, Base32Alphabet.Default);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The alphabet that will be used for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromByteArray(byte[] value, Base32Alphabet alphabet)
- {
- return FromByteArray(value, alphabet, true);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromByteArray(byte[] value, bool padding)
- {
- return FromByteArray(value, Base32Alphabet.Default, padding);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The alphabet that will be used for Base-32 encoding and decoding operations.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromByteArray(byte[] value, Base32Alphabet alphabet, bool padding)
- {
- return new Base32(value, alphabet, padding);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// Returns a new instance.
- public static Base32 FromCharArray(char[] value)
- {
- return FromCharArray(value, Encoding.Default, Base32Alphabet.Default, true);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// Returns a new instance.
- public static Base32 FromCharArray(char[] value, Encoding encoding)
- {
- return FromCharArray(value, encoding, Base32Alphabet.Default, true);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromCharArray(char[] value, bool padding)
- {
- return FromCharArray(value, Encoding.Default, Base32Alphabet.Default, padding);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromCharArray(char[] value, Encoding encoding, bool padding)
- {
- return FromCharArray(value, encoding, Base32Alphabet.Default, padding);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The alphabet that will be used for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromCharArray(char[] value, Base32Alphabet alphabet)
- {
- return FromCharArray(value, Encoding.Default, alphabet);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// The alphabet that will be used for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromCharArray(char[] value, Encoding encoding, Base32Alphabet alphabet)
- {
- byte[] bytes = encoding.GetBytes(value);
- return FromByteArray(bytes, alphabet);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The alphabet that will be used for Base-32 encoding and decoding operations.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromCharArray(char[] value, Base32Alphabet alphabet, bool padding)
- {
- return FromCharArray(value, Encoding.Default, alphabet, padding);
- }
-
- ///
- /// Creates a instance from the specified array.
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// The alphabet that will be used for Base-32 encoding and decoding operations.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromCharArray(char[] value, Encoding encoding, Base32Alphabet alphabet, bool padding)
- {
- byte[] bytes = encoding.GetBytes(value);
- return FromByteArray(bytes, alphabet, padding);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// Returns a new instance.
- public static Base32 FromSpan(ReadOnlySpan value)
- {
- return FromSpan(value, Encoding.Default, Base32Alphabet.Default, true);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// Returns a new instance.
- public static Base32 FromSpan(ReadOnlySpan value, Encoding encoding)
- {
- return FromSpan(value, encoding, Base32Alphabet.Default, true);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromSpan(ReadOnlySpan value, bool padding)
- {
- return FromSpan(value, Encoding.Default, Base32Alphabet.Default, padding);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// The encoding to use to obtain the underlying value.
- /// Determines whether padding should be applied for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromSpan(ReadOnlySpan value, Encoding encoding, bool padding)
- {
- return FromSpan(value, encoding, Base32Alphabet.Default, padding);
- }
-
- ///
- /// Creates a instance from the specified .
- ///
- /// The underlying value.
- /// The alphabet that will be used for Base-32 encoding and decoding operations.
- /// Returns a new instance.
- public static Base32 FromSpan(ReadOnlySpan value, Base32Alphabet alphabet)
- {
- return FromSpan(value, Encoding.Default, alphabet);
- }
-
- ///
- /// Creates a