Skip to content

feature/monad-equality-comparer #68

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions OnixLabs.Core.UnitTests/OptionalEqualityComparerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// 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 Xunit;

namespace OnixLabs.Core.UnitTests;

public class OptionalEqualityComparerTests
{
[Fact(DisplayName = "OptionalEqualityComparer.Equals should return true when comparing null values")]
public void OptionalEqualityComparerEqualsShouldReturnTrueWhenComparingNullValues()
{
// Given
Optional<string>? x = null;
Optional<string>? y = null;
OptionalEqualityComparer<string> comparer = new();

// When
bool result = comparer.Equals(x, y);

// Then
Assert.True(result);
}

[Fact(DisplayName = "OptionalEqualityComparer.Equals should return false when comparing null and non-null values")]
public void OptionalEqualityComparerEqualsShouldReturnFalseWhenComparingNullAndNonNullValues()
{
// Given
Optional<string>? x = null;
Optional<string> y = "abc";
OptionalEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.False(result1);
Assert.False(result2);
}

[Fact(DisplayName = "OptionalEqualityComparer.Equals should return true when comparing None values")]
public void OptionalEqualityComparerEqualsShouldReturnTrueWhenComparingNoneValues()
{
// Given
Optional<string> x = Optional<string>.None;
Optional<string> y = Optional<string>.None;
OptionalEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.True(result1);
Assert.True(result2);
}

[Fact(DisplayName = "OptionalEqualityComparer.Equals should return false when comparing None and Some values")]
public void OptionalEqualityComparerEqualsShouldReturnFalseWhenComparingNoneAndSomeValues()
{
// Given
Optional<string> x = Optional<string>.None;
Optional<string> y = "abc";
OptionalEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.False(result1);
Assert.False(result2);
}

[Fact(DisplayName = "OptionalEqualityComparer.Equals should return true when comparing identical Some values")]
public void OptionalEqualityComparerEqualsShouldReturnTrueWhenComparingIdenticalSomeValues()
{
// Given
Optional<string> x = "abc";
Optional<string> y = "abc";
OptionalEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.True(result1);
Assert.True(result2);
}

[Fact(DisplayName = "OptionalEqualityComparer.Equals should return false when comparing non-identical Some values")]
public void OptionalEqualityComparerEqualsShouldReturnFalseWhenComparingNonIdenticalSomeValues()
{
// Given
Optional<string> x = "abc";
Optional<string> y = "xyz";
OptionalEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.False(result1);
Assert.False(result2);
}

[Fact(DisplayName = "OptionalEqualityComparer.Equals should return true when comparing identical Some values with value comparer")]
public void OptionalEqualityComparerEqualsShouldReturnTrueWhenComparingIdenticalSomeValuesWithValueComparer()
{
// Given
Optional<string> x = "abc";
Optional<string> y = "ABC";
OptionalEqualityComparer<string> comparer = new(new CaseInsensitiveStringComparer());

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.True(result1);
Assert.True(result2);
}

[Fact(DisplayName = "OptionalEqualityComparer.Equals should return false when comparing non-identical Some values with value comparer")]
public void OptionalEqualityComparerEqualsShouldReturnFalseWhenComparingNonIdenticalSomeValuesWithValueComparer()
{
// Given
Optional<string> x = "abc";
Optional<string> y = "XYZ";
OptionalEqualityComparer<string> comparer = new(new CaseInsensitiveStringComparer());

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.False(result1);
Assert.False(result2);
}

[Fact(DisplayName = "OptionalEqualityComparer.GetHashCode should return zero when the optional value is none.")]
public void OptionalEqualityComparerGetHashCodeShouldReturnZeroWhenOptionalValueIsNone()
{
// Given
const int expected = default;
Optional<string> optional = Optional<string>.None;
OptionalEqualityComparer<string> comparer = new();

// When
int actual = comparer.GetHashCode(optional);

// Then
Assert.Equal(expected, actual);
}

private sealed class CaseInsensitiveStringComparer : EqualityComparer<string>
{
public override bool Equals(string? x, string? y) => string.Equals(x, y, StringComparison.InvariantCultureIgnoreCase);
public override int GetHashCode(string obj) => obj.GetHashCode();
}
}
164 changes: 164 additions & 0 deletions OnixLabs.Core.UnitTests/ResultEqualityComparerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// 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 Xunit;

namespace OnixLabs.Core.UnitTests;

public class ResultEqualityComparerTests
{
[Fact(DisplayName = "ResultEqualityComparer.Equals should return true when comparing null values")]
public void ResultEqualityComparerEqualsShouldReturnTrueWhenComparingNullValues()
{
// Given
Result<string>? x = null;
Result<string>? y = null;
ResultEqualityComparer<string> comparer = new();

// When
bool result = comparer.Equals(x, y);

// Then
Assert.True(result);
}

[Fact(DisplayName = "ResultEqualityComparer.Equals should return false when comparing null and non-null values")]
public void ResultEqualityComparerEqualsShouldReturnFalseWhenComparingNullAndNonNullValues()
{
// Given
Result<string>? x = null;
Result<string> y = "abc";
ResultEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.False(result1);
Assert.False(result2);
}

[Fact(DisplayName = "ResultEqualityComparer.Equals should return true when comparing Failure values")]
public void ResultEqualityComparerEqualsShouldReturnTrueWhenComparingNoneValues()
{
// Given
Exception exception = new("Failure");
Result<string> x = exception;
Result<string> y = exception;
ResultEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.True(result1);
Assert.True(result2);
}

[Fact(DisplayName = "ResultEqualityComparer.Equals should return false when comparing Success and Failure values")]
public void ResultEqualityComparerEqualsShouldReturnFalseWhenComparingNoneAndSomeValues()
{
// Given
Exception exception = new("Failure");
Result<string> x = exception;
Result<string> y = "abc";
ResultEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.False(result1);
Assert.False(result2);
}

[Fact(DisplayName = "ResultEqualityComparer.Equals should return true when comparing identical Success values")]
public void ResultEqualityComparerEqualsShouldReturnTrueWhenComparingIdenticalSomeValues()
{
// Given
Result<string> x = "abc";
Result<string> y = "abc";
ResultEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.True(result1);
Assert.True(result2);
}

[Fact(DisplayName = "ResultEqualityComparer.Equals should return false when comparing non-identical Success values")]
public void ResultEqualityComparerEqualsShouldReturnFalseWhenComparingNonIdenticalSomeValues()
{
// Given
Result<string> x = "abc";
Result<string> y = "xyz";
ResultEqualityComparer<string> comparer = new();

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.False(result1);
Assert.False(result2);
}

[Fact(DisplayName = "ResultEqualityComparer.Equals should return true when comparing identical Success values with value comparer")]
public void ResultEqualityComparerEqualsShouldReturnTrueWhenComparingIdenticalSomeValuesWithValueComparer()
{
// Given
Result<string> x = "abc";
Result<string> y = "ABC";
ResultEqualityComparer<string> comparer = new(new CaseInsensitiveStringComparer());

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.True(result1);
Assert.True(result2);
}

[Fact(DisplayName = "ResultEqualityComparer.Equals should return false when comparing non-identical Success values with value comparer")]
public void ResultEqualityComparerEqualsShouldReturnFalseWhenComparingNonIdenticalSomeValuesWithValueComparer()
{
// Given
Result<string> x = "abc";
Result<string> y = "XYZ";
ResultEqualityComparer<string> comparer = new(new CaseInsensitiveStringComparer());

// When
bool result1 = comparer.Equals(x, y);
bool result2 = comparer.Equals(y, x);

// Then
Assert.False(result1);
Assert.False(result2);
}

private sealed class CaseInsensitiveStringComparer : EqualityComparer<string>
{
public override bool Equals(string? x, string? y) => string.Equals(x, y, StringComparison.InvariantCultureIgnoreCase);
public override int GetHashCode(string obj) => obj.GetHashCode();
}
}
4 changes: 2 additions & 2 deletions OnixLabs.Core/OnixLabs.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
<Title>OnixLabs.Core</Title>
<Authors>ONIXLabs</Authors>
<Description>ONIXLabs Core API for .NET</Description>
<AssemblyVersion>8.10.1</AssemblyVersion>
<AssemblyVersion>8.11.0</AssemblyVersion>
<NeutralLanguage>en</NeutralLanguage>
<Copyright>Copyright © ONIXLabs 2020</Copyright>
<RepositoryUrl>https://github.com/onix-labs/onixlabs-dotnet</RepositoryUrl>
<PackageVersion>8.10.1</PackageVersion>
<PackageVersion>8.11.0</PackageVersion>
</PropertyGroup>
<PropertyGroup>
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
Expand Down
14 changes: 14 additions & 0 deletions OnixLabs.Core/Optional.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,20 @@ internal Optional()
/// </summary>
public bool HasValue => this is Some<T>;

/// <summary>
/// Gets a value indicating whether the specified <see cref="Optional{T}"/> instance is <see cref="None{T}"/>.
/// </summary>
/// <param name="value">The <see cref="Optional{T}"/> value to check.</param>
/// <returns>Returns <see langword="true"/> if the specified <see cref="Optional{T}"/> instance is <see cref="None{T}"/>; otherwise, <see langword="false"/>.</returns>
public static bool IsNone(Optional<T> value) => value is None<T>;

/// <summary>
/// Gets a value indicating whether the specified <see cref="Optional{T}"/> instance is <see cref="Some{T}"/>.
/// </summary>
/// <param name="value">The <see cref="Optional{T}"/> value to check.</param>
/// <returns>Returns <see langword="true"/> if the specified <see cref="Optional{T}"/> instance is <see cref="Some{T}"/>; otherwise, <see langword="false"/>.</returns>
public static bool IsSome(Optional<T> value) => value is Some<T>;

/// <summary>
/// Creates a new instance of the <see cref="Optional{T}"/> class, where the underlying value is present if
/// the specified value is not <see langword="default"/>; otherwise, the underlying value is <see cref="None"/>.
Expand Down
Loading
Loading