Skip to content

Commit

Permalink
Fix broken paths, add tests for paths, remove obsolete Assert() api, …
Browse files Browse the repository at this point in the history
…bump version to 1.1.0
  • Loading branch information
kasthack committed Jan 6, 2022
1 parent 9045812 commit 0000000
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 66 deletions.
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<PublishDocumentationFile>true</PublishDocumentationFile>
<PublishDocumentationFiles>true</PublishDocumentationFiles>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageVersion>1.0.7</PackageVersion>
<PackageVersion>1.1.0</PackageVersion>
<PackageDescription>.NotEmpty&lt;T&gt;() test extension</PackageDescription>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageTags>kasthack nunit xunit mstest test empty null notempty emptinness nullability</PackageTags>
Expand Down
3 changes: 2 additions & 1 deletion src/kasthack.NotEmpty.Core/AssertContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
using System;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// Dispose doesn't do what you migth think.
Expand All @@ -14,7 +15,7 @@ internal class AssertContext

public int CurrentDepth => this.pathSegments.Count;

public string Path => string.Concat(this.pathSegments);
public string Path => "(value)" + string.Concat(this.pathSegments.Reverse());

public bool IsArrayElement { get; set; } = false;

Expand Down
33 changes: 18 additions & 15 deletions src/kasthack.NotEmpty.Core/NotEmptyExtensionsBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,26 @@ public void NotEmpty<T>(T? value, AssertOptions? assertOptions)
this.NotEmptyBoxed(value, new AssertContext(assertOptions));
}

protected abstract void Assert(bool value, string message);

internal void NotEmptyInternal<T>(T? value, AssertContext context)
{
if (context.Options.MaxDepth != null && context.Options.MaxDepth.Value < context.CurrentDepth)
{
return;
}

string message = GetEmptyMessage(context.Path);
this.Assert(value is not null, message); // fast lane
var path = context.Path;
string message = GetEmptyMessage(path);
this.Assert(value is not null, message, path); // fast lane
if (
!(context.Options.AllowZerosInNumberArrays &&
context.IsArrayElement &&
value is byte or sbyte or short or ushort or char or int or uint or long or ulong or float or double or decimal or BigInteger
#if NET5_0_OR_GREATER
or Half
#endif
#if NET5_0_OR_GREATER
or Half or nint or nuint
#endif
))
{
this.Assert(!EqualityComparer<T>.Default.Equals(default!, value!), message);
this.Assert(!EqualityComparer<T>.Default.Equals(default!, value!), message, path);
}

switch (value)
Expand All @@ -61,7 +60,8 @@ or TimeOnly _
context.Options.AllowEmptyStrings
? s != null
: !string.IsNullOrEmpty(s),
message);
message,
path);
break;
case System.Collections.IDictionary d:
var cnt = 0;
Expand All @@ -76,30 +76,30 @@ or TimeOnly _

if (!context.Options.AllowEmptyCollections)
{
this.Assert(cnt != 0, message);
this.Assert(cnt != 0, message, path);
}

break;
case System.Collections.IEnumerable e:
var index = 0;
foreach (var item in e)
{
using (context.EnterPath(index++.ToString(), true))
using (context.EnterPath($"[{index++}]", true))
{
this.NotEmptyBoxed(item, context);
}
}

if (!context.Options.AllowEmptyCollections)
{
this.Assert(index != 0, message);
this.Assert(index != 0, message, path);
}

break;
default:
foreach (var pathValue in CachedPropertyExtractor<T>.GetProperties(value))
{
using (context.EnterPath(pathValue.Path, false))
using (context.EnterPath($".{pathValue.Path}", false))
{
this.NotEmptyBoxed(pathValue.Value, context);
}
Expand All @@ -111,10 +111,13 @@ or TimeOnly _

internal void NotEmptyBoxed(object? value, AssertContext context)
{
this.Assert(value is not null, GetEmptyMessage(context.Path));
var path = context.Path;
this.Assert(value is not null, GetEmptyMessage(path), path);
CachedEmptyDelegate.GetDelegate(value!.GetType())(this, value, context);
}

private static string GetEmptyMessage(string? path) => $"value{path} is empty";
protected abstract void Assert(bool value, string message, string path);

private static string GetEmptyMessage(string? path) => $"{path} is empty";
}
}
10 changes: 1 addition & 9 deletions src/kasthack.NotEmpty.MsTest/NotEmptyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ public static class NotEmptyExtensions
{
private static readonly NotEmptyExtensionsBaseXunit Instance = new();

/// <summary>
/// Tests objects for emptinness(being null, default(T), empty collection or string) recursively.
/// </summary>
/// <param name="value">Value to test for emptinness.</param>
/// <typeparam name="T">Type of value(inferred by the compiler).</typeparam>
[Obsolete]
public static void NotEmpty<T>(this T? value) => NotEmpty<T>(value, default);

/// <summary>
/// Tests objects for emptinness(being null, default(T), empty collection or string) recursively.
/// </summary>
Expand All @@ -28,7 +20,7 @@ public static class NotEmptyExtensions

private class NotEmptyExtensionsBaseXunit : NotEmptyExtensionsBase
{
protected override void Assert(bool value, string message) => global::Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue(value, message);
protected override void Assert(bool value, string message, string path) => global::Microsoft.VisualStudio.TestTools.UnitTesting.Assert.IsTrue(value, message);
}
}
}
10 changes: 1 addition & 9 deletions src/kasthack.NotEmpty.Nunit/NotEmptyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ public static class NotEmptyExtensions
{
private static readonly NotEmptyExtensionsBaseXunit Instance = new();

/// <summary>
/// Tests objects for emptinness(being null, default(T), empty collection or string) recursively.
/// </summary>
/// <param name="value">Value to test for emptinness.</param>
/// <typeparam name="T">Type of value(inferred by the compiler).</typeparam>
[Obsolete]
public static void NotEmpty<T>(this T? value) => NotEmpty<T>(value, default);

/// <summary>
/// Tests objects for emptinness(being null, default(T), empty collection or string) recursively.
/// </summary>
Expand All @@ -28,7 +20,7 @@ public static class NotEmptyExtensions

private class NotEmptyExtensionsBaseXunit : NotEmptyExtensionsBase
{
protected override void Assert(bool value, string message) => global::NUnit.Framework.Assert.IsTrue(value, message);
protected override void Assert(bool value, string message, string path) => global::NUnit.Framework.Assert.IsTrue(value, message);
}
}
}
28 changes: 16 additions & 12 deletions src/kasthack.NotEmpty.Raw/NotEmptyExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,15 @@
namespace kasthack.NotEmpty.Raw
{
using System;

using kasthack.NotEmpty.Core;

/// <summary>
/// .NotEmpty&lt;T&gt;() extensions.
/// </summary>
public static class NotEmptyExtensions
{
private static readonly NotEmptyExtensionsBaseXunit Instance = new();

/// <summary>
/// Tests objects for emptinness(being null, default(T), empty collection or string) recursively.
/// </summary>
/// <param name="value">Value to test for emptinness.</param>
/// <typeparam name="T">Type of value(inferred by the compiler).</typeparam>
[Obsolete]
public static void NotEmpty<T>(this T? value) => NotEmpty<T>(value, default);
private static readonly NotEmptyExtensionsBaseRaw Instance = new();

/// <summary>
/// Tests objects for emptinness(being null, default(T), empty collection or string) recursively.
Expand All @@ -26,15 +19,26 @@ public static class NotEmptyExtensions
/// <typeparam name="T">Type of value(inferred by the compiler).</typeparam>
public static void NotEmpty<T>(this T? value, AssertOptions? assertOptions = null) => Instance.NotEmpty(value, assertOptions);

private class NotEmptyExtensionsBaseXunit : NotEmptyExtensionsBase
private class NotEmptyExtensionsBaseRaw : NotEmptyExtensionsBase
{
protected override void Assert(bool value, string message)
protected override void Assert(bool value, string message, string path)
{
if (!value)
{
throw new System.ComponentModel.DataAnnotations.ValidationException(message);
throw new EmptyException(message, path);
}
}
}
}

public class EmptyException : Exception
{
public EmptyException(string message, string path)
: base(message)
{
this.Path = path;
}

public string Path { get; }
}
}
1 change: 0 additions & 1 deletion src/kasthack.NotEmpty.Raw/kasthack.NotEmpty.Raw.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,5 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\kasthack.NotEmpty.Core\kasthack.NotEmpty.Core.csproj" />
<Reference Include="System.ComponentModel.DataAnnotations" />
</ItemGroup>
</Project>
8 changes: 0 additions & 8 deletions src/kasthack.NotEmpty.Tests/GenericTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,4 @@ public MsTestNotEmptyTest()
{
}
}

public class RawNotEmptyTest : NotEmptyTestBase
{
public RawNotEmptyTest()
: base((x, o) => kasthack.NotEmpty.Raw.NotEmptyExtensions.NotEmpty(x, o))
{
}
}
}
2 changes: 1 addition & 1 deletion src/kasthack.NotEmpty.Tests/NotEmptyTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,6 @@ public struct InfiniteNestedStruct
}
#endregion

private void Action(object? value, AssertOptions? options = null) => this.action(value, options);
protected void Action(object? value, AssertOptions? options = null) => this.action(value, options);
}
}
35 changes: 35 additions & 0 deletions src/kasthack.NotEmpty.Tests/RawNotEmptyTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace kasthack.NotEmpty.Tests
{
using System.Collections.Generic;
using global::Xunit;

public class RawNotEmptyTest : NotEmptyTestBase
{
public RawNotEmptyTest()
: base((x, o) => kasthack.NotEmpty.Raw.NotEmptyExtensions.NotEmpty(x, o))
{
}

[Fact]
public void RawAssertThrowsAnExceptionOfACorrectType() => Assert.Throws<Raw.EmptyException>(() => this.Action(new { Value = 0, }));

[Fact]
public void PathIsConstructedProperlyForTheRootObject() => this.AssertExceptionPath("(value)", 0);

[Fact]
public void PathIsConstructedProperlyForProperties() => this.AssertExceptionPath("(value).Value", new { Value = 0, });

[Fact]
public void PathIsConstructedProperlyForNestedProperties() => this.AssertExceptionPath("(value).Value.A", new { Value = new { A = 0 } });

[Fact]
public void PathIsConstructedProperlyForArrays() => this.AssertExceptionPath("(value).Value[0].A", new { Value = new[] { new { A = 0 } } });

[Fact]
public void PathIsConstructedProperlyForDictionaries() => this.AssertExceptionPath("(value).Value[str]", new { Value = new Dictionary<string, int> { { "str", 0 } } });

private void AssertExceptionPath(string expectedPath, object value) => Assert.Equal(
expectedPath,
Assert.Throws<Raw.EmptyException>(() => this.Action(value)).Path);
}
}
10 changes: 1 addition & 9 deletions src/kasthack.NotEmpty.Xunit/NotEmptyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ public static class NotEmptyExtensions
{
private static readonly NotEmptyExtensionsBaseXunit Instance = new();

/// <summary>
/// Tests objects for emptinness(being null, default(T), empty collection or string) recursively.
/// </summary>
/// <param name="value">Value to test for emptinness.</param>
/// <typeparam name="T">Type of value(inferred by the compiler).</typeparam>
[Obsolete]
public static void NotEmpty<T>(this T? value) => NotEmpty<T>(value, default);

/// <summary>
/// Tests objects for emptinness(being null, default(T), empty collection or string) recursively.
/// </summary>
Expand All @@ -28,7 +20,7 @@ public static class NotEmptyExtensions

private class NotEmptyExtensionsBaseXunit : NotEmptyExtensionsBase
{
protected override void Assert(bool value, string message) => global::Xunit.Assert.True(value, message);
protected override void Assert(bool value, string message, string path) => global::Xunit.Assert.True(value, message);
}
}
}

0 comments on commit 0000000

Please sign in to comment.