Skip to content
Open
4 changes: 2 additions & 2 deletions Bearded.Utilities.Testing/Geometry/Bivector2Assertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ public AndConstraint<Bivector2Assertions> NotBe(Bivector2 other, string because
public AndConstraint<Bivector2Assertions> BeApproximately(
Bivector2 other, float precision, string because = "", params object[] becauseArgs)
{
subject.Magnitude.Should().BeApproximately(other.Magnitude, precision, because, becauseArgs);
subject.Xy.Should().BeApproximately(other.Xy, precision, because, becauseArgs);
return new AndConstraint<Bivector2Assertions>(this);
}

[CustomAssertion]
public AndConstraint<Bivector2Assertions> NotBeApproximately(
Bivector2 other, float precision, string because = "", params object[] becauseArgs)
{
subject.Magnitude.Should().NotBeApproximately(other.Magnitude, precision, because, becauseArgs);
subject.Xy.Should().NotBeApproximately(other.Xy, precision, because, becauseArgs);
return new AndConstraint<Bivector2Assertions>(this);
}
}
39 changes: 39 additions & 0 deletions Bearded.Utilities.Tests/Assertions/Vector3Assertions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using FluentAssertions;
using FluentAssertions.Execution;
using OpenTK.Mathematics;

namespace Bearded.Utilities.Tests.Assertions
{
sealed class Vector3Assertions
{
private readonly Vector3 subject;

public Vector3Assertions(Vector3 subject)
{
this.subject = subject;
}

[CustomAssertion]
public AndConstraint<Vector3Assertions> BeApproximately(
Vector3 expectedValue,
float precision,
string because = "",
params object[] becauseArgs)
{
var xDifference = Math.Abs(subject.X - expectedValue.X);
var yDifference = Math.Abs(subject.Y - expectedValue.Y);
var zDifference = Math.Abs(subject.Z - expectedValue.Z);

Execute.Assertion
.BecauseOf(because, becauseArgs)
.ForCondition(xDifference <= precision && yDifference <= precision && zDifference <= precision)
.FailWith(
"Expected {context:value} to be approximately {1} +/- {2}{reason}, " +
"but {0}'s coordinates differed by {3} (x), {4} (y), and {5} (z).",
subject, expectedValue, precision, xDifference, yDifference, zDifference);

return new AndConstraint<Vector3Assertions>(this);
}
}
}
9 changes: 9 additions & 0 deletions Bearded.Utilities.Tests/Assertions/Vector3Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using OpenTK.Mathematics;

namespace Bearded.Utilities.Tests.Assertions
{
static class Vector3Extensions
{
public static Vector3Assertions Should(this Vector3 subject) => new Vector3Assertions(subject);
}
}
73 changes: 68 additions & 5 deletions Bearded.Utilities.Tests/Geometry/Bivector2Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Bearded.Utilities.Tests.Geometry;

public sealed class Bivector2Tests
{
private const float epsilon = 1E-6f;
private const float epsilon = 1E-3f;

public Bivector2Tests()
{
Expand Down Expand Up @@ -63,8 +63,52 @@ public void WedgeIsAntiSymmetric(Vector2 left, Vector2 right)
wedge1.Should().Be(-wedge2);
}

[Fact]
public void UnitBivectorHasMagnitudeOne()
{
Bivector2.Unit.Magnitude.Should().BeApproximately(1, epsilon);
Bivector2.Unit.MagnitudeSquared.Should().BeApproximately(1, epsilon);
}

[Fact]
public void ZeroBivectorHasMagnitudeZero()
{
Bivector2.Zero.Magnitude.Should().BeApproximately(0, epsilon);
Bivector2.Zero.MagnitudeSquared.Should().BeApproximately(0, epsilon);
}

[Property]
public void AddingBivectorsAddsMagnitudes(float f1, float f2)
public void NormalizedNonZeroBivectorHasMagnitudeOne(float xy)
{
var bivector = new Bivector2(xy);
if (bivector == Bivector2.Zero) return;

var normalized = bivector.Normalized();

normalized.Magnitude.Should().BeApproximately(1, epsilon);
normalized.MagnitudeSquared.Should().BeApproximately(1, epsilon);
}

[Fact]
public void NormalizedZeroBivectorIsZeroBivector()
{
var bivector = Bivector2.Zero;

bivector.Normalized().Should().Be(bivector);
}

[Property]
public void NormalizedBivectorRetainsSign(float xy)
{
var bivector = new Bivector2(xy);

var normalized = bivector.Normalized();

MathF.Sign(bivector.Xy).Should().Be(MathF.Sign(normalized.Xy));
}

[Property]
public void AddingBivectorsAddsComponents(float f1, float f2)
{
var bivector1 = new Bivector2(f1);
var bivector2 = new Bivector2(f2);
Expand All @@ -74,7 +118,7 @@ public void AddingBivectorsAddsMagnitudes(float f1, float f2)
}

[Property]
public void SubtractingBivectorsSubtractsMagnitudes(float f1, float f2)
public void SubtractingBivectorsSubtractsComponents(float f1, float f2)
{
var bivector1 = new Bivector2(f1);
var bivector2 = new Bivector2(f2);
Expand All @@ -84,7 +128,26 @@ public void SubtractingBivectorsSubtractsMagnitudes(float f1, float f2)
}

[Property]
public void BivectorsWithSameMagnitudeAreEqual(float magnitude)
public void ScalingBivectorScalesItsComponents(float xy, float scalar)
{
var bivector = new Bivector2(xy);
var scaled = scalar * bivector;

scaled.Xy.Should().BeApproximately(xy * scalar, epsilon);
}

[Property]
public void DividingBivectorByScalarDividesItsComponents(float xy, float divider)
{
if (divider == 0) return;
var bivector = new Bivector2(xy);
var scaled = bivector / divider;

scaled.Xy.Should().BeApproximately(xy / divider, epsilon);
}

[Property]
public void BivectorsWithSameComponentsAreEqual(float magnitude)
{
var bivector1 = new Bivector2(magnitude);
var bivector2 = new Bivector2(magnitude);
Expand All @@ -96,7 +159,7 @@ public void BivectorsWithSameMagnitudeAreEqual(float magnitude)
}

[Property]
public void BivectorsWithDifferentMagnitudeAreNotEqual(float f1, float f2)
public void BivectorsWithDifferentComponentsAreNotEqual(float f1, float f2)
{
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (f1 == f2) f2++;
Expand Down
97 changes: 96 additions & 1 deletion Bearded.Utilities.Tests/Geometry/Bivector3Tests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using Bearded.Utilities.Geometry;
using Bearded.Utilities.Testing.Geometry;
using Bearded.Utilities.Tests.Generators;
Expand All @@ -11,7 +12,7 @@ namespace Bearded.Utilities.Tests.Geometry;

public sealed class Bivector3Tests
{
private const float epsilon = 1E-6f;
private const float epsilon = 1E-3f;

public Bivector3Tests()
{
Expand Down Expand Up @@ -62,6 +63,77 @@ public void WedgeIsAntiSymmetric(Vector3 left, Vector3 right)
wedge1.Should().Be(-wedge2);
}

[Property]
public void FromAxisCreatesBivectorWithSameMagnitudeAsVector(Vector3 axis)
{
var bivector = Bivector3.FromAxis(axis);

bivector.Magnitude.Should().BeApproximately(axis.Length, epsilon);
}

[Property]
public void FromAxisRetainsSign(Vector3 axis)
{
var bivector = Bivector3.FromAxis(axis);
var reverseBivector = Bivector3.FromAxis(-axis);

bivector.Should().BeApproximately(-reverseBivector, epsilon);
}

[Theory]
[MemberData(nameof(UnitVectorsWithOrthogonalPlanes))]
public void FromAxisReturnsOrthogonalPlaneToUnitVectors(Vector3 axis, Bivector3 expectedBivector)
{
var bivector = Bivector3.FromAxis(axis);

bivector.Should().BeApproximately(expectedBivector, epsilon);
}

public static IEnumerable<object[]> UnitVectorsWithOrthogonalPlanes()
{
yield return new object[] { Vector3.UnitX, Bivector3.UnitYz };
yield return new object[] { Vector3.UnitY, -Bivector3.UnitXz };
yield return new object[] { Vector3.UnitZ, Bivector3.UnitXy };
}

[Fact]
public void UnitBivectorsHaveMagnitudeOne()
{
Bivector3.UnitXy.Magnitude.Should().BeApproximately(1, epsilon);
Bivector3.UnitXy.MagnitudeSquared.Should().BeApproximately(1, epsilon);
Bivector3.UnitYz.Magnitude.Should().BeApproximately(1, epsilon);
Bivector3.UnitYz.MagnitudeSquared.Should().BeApproximately(1, epsilon);
Bivector3.UnitXz.Magnitude.Should().BeApproximately(1, epsilon);
Bivector3.UnitXz.MagnitudeSquared.Should().BeApproximately(1, epsilon);
}

[Fact]
public void ZeroBivectorHasMagnitudeZero()
{
Bivector3.Zero.Magnitude.Should().BeApproximately(0, epsilon);
Bivector3.Zero.MagnitudeSquared.Should().BeApproximately(0, epsilon);
}

[Property]
public void NormalizedNonZeroBivectorHasMagnitudeOne(float xy, float yz, float xz)
{
var bivector = new Bivector3(xy, yz, xz);
if (bivector == Bivector3.Zero) return;

var normalized = bivector.Normalized();

normalized.Magnitude.Should().BeApproximately(1, epsilon);
normalized.MagnitudeSquared.Should().BeApproximately(1, epsilon);
}

[Fact]
public void NormalizedZeroBivectorIsZeroBivector()
{
var bivector = Bivector3.Zero;

bivector.Normalized().Should().Be(bivector);
}

[Property]
public void AddingBivectorsAddsComponents(float xy1, float xy2, float yz1, float yz2, float xz1, float xz2)
{
Expand All @@ -83,6 +155,29 @@ public void SubtractingBivectorsSubtractsComponents(
sum.Should().BeApproximately(new Bivector3(xy1 - xy2, yz1 - yz2, xz1 - xz2), epsilon);
}

[Property]
public void ScalingBivectorScalesItsComponents(float xy, float yz, float xz, float scalar)
{
var bivector = new Bivector3(xy, yz, xz);
var scaled = scalar * bivector;

scaled.Xy.Should().BeApproximately(xy * scalar, epsilon);
scaled.Yz.Should().BeApproximately(yz * scalar, epsilon);
scaled.Xz.Should().BeApproximately(xz * scalar, epsilon);
}

[Property]
public void DividingBivectorByScalarDividesItsComponents(float xy, float yz, float xz, float divider)
{
if (divider == 0) return;
var bivector = new Bivector3(xy, yz, xz);
var scaled = bivector / divider;

scaled.Xy.Should().BeApproximately(xy / divider, epsilon);
scaled.Yz.Should().BeApproximately(yz / divider, epsilon);
scaled.Xz.Should().BeApproximately(xz / divider, epsilon);
}

[Property]
public void BivectorsWithSameComponentsAreEqual(float xy, float yz, float xz)
{
Expand Down
2 changes: 1 addition & 1 deletion Bearded.Utilities.Tests/Geometry/CircularArc2Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Bearded.Utilities.Tests.Geometry;

public sealed class CircularArc2Tests
{
private const float epsilon = 0.001f;
private const float epsilon = 1E-3f;

public CircularArc2Tests()
{
Expand Down
Loading