Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
288 changes: 288 additions & 0 deletions TUnit.Assertions/Conditions/Wrappers/CountWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
using System.Collections;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using TUnit.Assertions.Conditions;
using TUnit.Assertions.Core;
using TUnit.Assertions.Extensions;

namespace TUnit.Assertions.Conditions.Wrappers;

/// <summary>
/// Wrapper for collection count assertions that provides .EqualTo() method.
/// Example: await Assert.That(list).Count().EqualTo(5);
/// </summary>
public class CountWrapper<TCollection, TItem> : IAssertionSource<TCollection>
where TCollection : IEnumerable<TItem>
{
private readonly AssertionContext<TCollection> _context;

public CountWrapper(AssertionContext<TCollection> context)
{
_context = context;
}

AssertionContext<TCollection> IAssertionSource<TCollection>.Context => _context;

/// <summary>
/// Not supported on CountWrapper - use IsTypeOf on the assertion source before calling HasCount().
/// </summary>
TypeOfAssertion<TCollection, TExpected> IAssertionSource<TCollection>.IsTypeOf<TExpected>()
{
throw new NotSupportedException(
"IsTypeOf is not supported after HasCount(). " +
"Use: Assert.That(value).IsTypeOf<List<int>>().HasCount().EqualTo(5)");
}

/// <summary>
/// Not supported on CountWrapper - use IsAssignableTo on the assertion source before calling HasCount().
/// </summary>
IsAssignableToAssertion<TTarget, TCollection> IAssertionSource<TCollection>.IsAssignableTo<TTarget>()
{
throw new NotSupportedException(
"IsAssignableTo is not supported after HasCount(). " +
"Use: Assert.That(value).IsAssignableTo<IList<int>>().HasCount().EqualTo(5)");
}

/// <summary>
/// Not supported on CountWrapper - use IsNotAssignableTo on the assertion source before calling HasCount().
/// </summary>
IsNotAssignableToAssertion<TTarget, TCollection> IAssertionSource<TCollection>.IsNotAssignableTo<TTarget>()
{
throw new NotSupportedException(
"IsNotAssignableTo is not supported after HasCount(). " +
"Use: Assert.That(value).IsNotAssignableTo<IList<int>>().HasCount().EqualTo(5)");
}

/// <summary>
/// Not supported on CountWrapper - use IsAssignableFrom on the assertion source before calling HasCount().
/// </summary>
IsAssignableFromAssertion<TTarget, TCollection> IAssertionSource<TCollection>.IsAssignableFrom<TTarget>()
{
throw new NotSupportedException(
"IsAssignableFrom is not supported after HasCount(). " +
"Use: Assert.That(value).IsAssignableFrom<IList<int>>().HasCount().EqualTo(5)");
}

/// <summary>
/// Not supported on CountWrapper - use IsNotAssignableFrom on the assertion source before calling HasCount().
/// </summary>
IsNotAssignableFromAssertion<TTarget, TCollection> IAssertionSource<TCollection>.IsNotAssignableFrom<TTarget>()
{
throw new NotSupportedException(
"IsNotAssignableFrom is not supported after HasCount(). " +
"Use: Assert.That(value).IsNotAssignableFrom<IList<int>>().HasCount().EqualTo(5)");
}

/// <summary>
/// Not supported on CountWrapper - use IsNotTypeOf on the assertion source before calling HasCount().
/// </summary>
IsNotTypeOfAssertion<TCollection, TExpected> IAssertionSource<TCollection>.IsNotTypeOf<TExpected>()
{
throw new NotSupportedException(
"IsNotTypeOf is not supported after HasCount(). " +
"Use: Assert.That(value).IsNotTypeOf<List<int>>().HasCount().EqualTo(5)");
}

/// <summary>
/// Asserts that the collection count is equal to the expected count.
/// </summary>
public CollectionCountAssertion<TCollection, TItem> EqualTo(
int expectedCount,
[CallerArgumentExpression(nameof(expectedCount))] string? expression = null)
{
_context.ExpressionBuilder.Append($".EqualTo({expression})");
return new CollectionCountAssertion<TCollection, TItem>(_context, expectedCount);
}

/// <summary>
/// Asserts that the collection count is greater than or equal to the expected count.
/// </summary>
public TValue_IsGreaterThanOrEqualTo_TValue_Assertion<int> GreaterThanOrEqualTo(
int expected,
[CallerArgumentExpression(nameof(expected))] string? expression = null)
{
_context.ExpressionBuilder.Append($".GreaterThanOrEqualTo({expression})");
// Map context to get the count
var countContext = _context.Map<int>(value =>
{
if (value == null)
{
return 0;
}

if (value is ICollection collection)
{
return collection.Count;
}

return value.Cast<object>().Count();
});
return new TValue_IsGreaterThanOrEqualTo_TValue_Assertion<int>(countContext, expected);
}

/// <summary>
/// Asserts that the collection count is positive (greater than 0).
/// </summary>
public TValue_IsGreaterThan_TValue_Assertion<int> Positive()
{
_context.ExpressionBuilder.Append(".Positive()");
// Map context to get the count
var countContext = _context.Map<int>(value =>
{
if (value == null)
{
return 0;
}

if (value is ICollection collection)
{
return collection.Count;
}

return value.Cast<object>().Count();
});
return new TValue_IsGreaterThan_TValue_Assertion<int>(countContext, 0);
}

/// <summary>
/// Asserts that the collection count is greater than the expected count.
/// </summary>
public TValue_IsGreaterThan_TValue_Assertion<int> GreaterThan(
int expected,
[CallerArgumentExpression(nameof(expected))] string? expression = null)
{
_context.ExpressionBuilder.Append($".GreaterThan({expression})");
// Map context to get the count
var countContext = _context.Map<int>(value =>
{
if (value == null)
{
return 0;
}

if (value is ICollection collection)
{
return collection.Count;
}

return value.Cast<object>().Count();
});
return new TValue_IsGreaterThan_TValue_Assertion<int>(countContext, expected);
}

/// <summary>
/// Asserts that the collection count is less than the expected count.
/// </summary>
public TValue_IsLessThan_TValue_Assertion<int> LessThan(
int expected,
[CallerArgumentExpression(nameof(expected))] string? expression = null)
{
_context.ExpressionBuilder.Append($".LessThan({expression})");
// Map context to get the count
var countContext = _context.Map<int>(value =>
{
if (value == null)
{
return 0;
}

if (value is ICollection collection)
{
return collection.Count;
}

return value.Cast<object>().Count();
});
return new TValue_IsLessThan_TValue_Assertion<int>(countContext, expected);
}

/// <summary>
/// Asserts that the collection count is less than or equal to the expected count.
/// </summary>
public TValue_IsLessThanOrEqualTo_TValue_Assertion<int> LessThanOrEqualTo(
int expected,
[CallerArgumentExpression(nameof(expected))] string? expression = null)
{
_context.ExpressionBuilder.Append($".LessThanOrEqualTo({expression})");
// Map context to get the count
var countContext = _context.Map<int>(value =>
{
if (value == null)
{
return 0;
}

if (value is ICollection collection)
{
return collection.Count;
}

return value.Cast<object>().Count();
});
return new TValue_IsLessThanOrEqualTo_TValue_Assertion<int>(countContext, expected);
}

/// <summary>
/// Asserts that the collection count is between the minimum and maximum values.
/// </summary>
public BetweenAssertion<int> Between(
int minimum,
int maximum,
[CallerArgumentExpression(nameof(minimum))] string? minExpression = null,
[CallerArgumentExpression(nameof(maximum))] string? maxExpression = null)
{
_context.ExpressionBuilder.Append($".Between({minExpression}, {maxExpression})");
// Map context to get the count
var countContext = _context.Map<int>(value =>
{
if (value == null)
{
return 0;
}

if (value is ICollection collection)
{
return collection.Count;
}

return value.Cast<object>().Count();
});
return new BetweenAssertion<int>(countContext, minimum, maximum);
}

/// <summary>
/// Asserts that the collection count is zero (empty collection).
/// </summary>
public CollectionCountAssertion<TCollection, TItem> Zero()
{
_context.ExpressionBuilder.Append(".Zero()");
return new CollectionCountAssertion<TCollection, TItem>(_context, 0);
}

/// <summary>
/// Asserts that the collection count is not equal to the expected count.
/// </summary>
public NotEqualsAssertion<int> NotEqualTo(
int expected,
[CallerArgumentExpression(nameof(expected))] string? expression = null)
{
_context.ExpressionBuilder.Append($".NotEqualTo({expression})");
// Map context to get the count
var countContext = _context.Map<int>(value =>
{
if (value == null)
{
return 0;
}

if (value is ICollection collection)
{
return collection.Count;
}

return value.Cast<object>().Count();
});
return new NotEqualsAssertion<int>(countContext, expected);
}
}
93 changes: 93 additions & 0 deletions TUnit.Assertions/Conditions/Wrappers/LengthWrapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
using System.Runtime.CompilerServices;
using System.Text;
using TUnit.Assertions.Conditions;
using TUnit.Assertions.Core;

namespace TUnit.Assertions.Conditions.Wrappers;

/// <summary>
/// Wrapper for string length assertions that provides .EqualTo() method.
/// Example: await Assert.That(str).HasLength().EqualTo(5);
/// </summary>
public class LengthWrapper : IAssertionSource<string>
{
private readonly AssertionContext<string> _context;

public LengthWrapper(AssertionContext<string> context)
{
_context = context;
}

AssertionContext<string> IAssertionSource<string>.Context => _context;

/// <summary>
/// Not supported on LengthWrapper - use IsTypeOf on the assertion source before calling HasLength().
/// </summary>
TypeOfAssertion<string, TExpected> IAssertionSource<string>.IsTypeOf<TExpected>()
{
throw new NotSupportedException(
"IsTypeOf is not supported after HasLength(). " +
"Use: Assert.That(value).IsTypeOf<string>().HasLength().EqualTo(5)");
}

/// <summary>
/// Not supported on LengthWrapper - use IsAssignableTo on the assertion source before calling HasLength().
/// </summary>
IsAssignableToAssertion<TTarget, string> IAssertionSource<string>.IsAssignableTo<TTarget>()
{
throw new NotSupportedException(
"IsAssignableTo is not supported after HasLength(). " +
"Use: Assert.That(value).IsAssignableTo<string>().HasLength().EqualTo(5)");
}

/// <summary>
/// Not supported on LengthWrapper - use IsNotAssignableTo on the assertion source before calling HasLength().
/// </summary>
IsNotAssignableToAssertion<TTarget, string> IAssertionSource<string>.IsNotAssignableTo<TTarget>()
{
throw new NotSupportedException(
"IsNotAssignableTo is not supported after HasLength(). " +
"Use: Assert.That(value).IsNotAssignableTo<string>().HasLength().EqualTo(5)");
}

/// <summary>
/// Not supported on LengthWrapper - use IsAssignableFrom on the assertion source before calling HasLength().
/// </summary>
IsAssignableFromAssertion<TTarget, string> IAssertionSource<string>.IsAssignableFrom<TTarget>()
{
throw new NotSupportedException(
"IsAssignableFrom is not supported after HasLength(). " +
"Use: Assert.That(value).IsAssignableFrom<string>().HasLength().EqualTo(5)");
}

/// <summary>
/// Not supported on LengthWrapper - use IsNotAssignableFrom on the assertion source before calling HasLength().
/// </summary>
IsNotAssignableFromAssertion<TTarget, string> IAssertionSource<string>.IsNotAssignableFrom<TTarget>()
{
throw new NotSupportedException(
"IsNotAssignableFrom is not supported after HasLength(). " +
"Use: Assert.That(value).IsNotAssignableFrom<string>().HasLength().EqualTo(5)");
}

/// <summary>
/// Not supported on LengthWrapper - use IsNotTypeOf on the assertion source before calling HasLength().
/// </summary>
IsNotTypeOfAssertion<string, TExpected> IAssertionSource<string>.IsNotTypeOf<TExpected>()
{
throw new NotSupportedException(
"IsNotTypeOf is not supported after HasLength(). " +
"Use: Assert.That(value).IsNotTypeOf<string>().HasLength().EqualTo(5)");
}

/// <summary>
/// Asserts that the string length is equal to the expected length.
/// </summary>
public StringLengthAssertion EqualTo(
int expectedLength,
[CallerArgumentExpression(nameof(expectedLength))] string? expression = null)
{
_context.ExpressionBuilder.Append($".EqualTo({expression})");
return new StringLengthAssertion(_context, expectedLength);
}
}
Loading
Loading