using Azimuth.DenseLinearAlgebra; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using UnitTestSharp; namespace Azimuth.UnitTests { public class BlasBoundsFixtureTests : UnitTestSharp.TestFixture { public class FauxDenseVector : IVector { public int Length { get; set; } private bool changed; public Scalar this[int index] => throw new NotImplementedException(); bool IEquatable.Equals(IVector other) => Equals(other as FauxDenseVector); public override bool Equals(object obj) => Equals(obj as FauxDenseVector); public bool Equals(FauxDenseVector other) => Length == other?.Length && changed == other?.changed; public override int GetHashCode() => base.GetHashCode(); public static void CheckLength(int offset, int length, int maxLength, int stride = 1) { if (length < 0 || offset < 0) { throw new ArgumentException(); } if (offset + (stride * length - stride) >= maxLength) { throw new ArgumentException(); } } public static void StaticChecks1(FauxDenseVector A, int offsetA = 0, int? length = null) { CheckLength(offsetA, length ?? A.Length, A.Length); } public static void StaticChecksNothing1(FauxDenseVector A, int offsetA = 0, int? length = null) { } public void Checks0(int offset = 0, int? length = null) { CheckLength(offset, length ?? Length, Length); } public void Checks1(FauxDenseVector A, int offset = 0, int offsetA = 0, int? length = null) { CheckLength(offset, length ?? Length, Length); CheckLength(offsetA, length ?? Length, Length); } public void Checks2(FauxDenseVector A, FauxDenseVector B, int offset = 0, int offsetA = 0, int offsetB = 0, int? length = null) { CheckLength(offset, length ?? Length, Length); CheckLength(offsetA, length ?? Length, Length); CheckLength(offsetB, length ?? Length, Length); } public void Checks3(FauxDenseVector A, FauxDenseVector B, FauxDenseVector C, int offset = 0, int offsetA = 0, int offsetB = 0, int offsetC = 0, int? length = null) { CheckLength(offset, length ?? Length, Length); CheckLength(offsetA, length ?? Length, Length); CheckLength(offsetB, length ?? Length, Length); CheckLength(offsetC, length ?? Length, Length); } public void Checks4(FauxDenseVector A, FauxDenseVector B, FauxDenseVector C, FauxDenseVector D, int offset = 0, int offsetA = 0, int offsetB = 0, int offsetC = 0, int offsetD = 0, int? length = null) { CheckLength(offset, length ?? Length, Length); CheckLength(offsetA, length ?? Length, Length); CheckLength(offsetB, length ?? Length, Length); CheckLength(offsetC, length ?? Length, Length); CheckLength(offsetD, length ?? Length, Length); } public void ChecksNothing0(int offset = 0, int? length = null) { } public void ChecksNothing1(FauxDenseVector A, int offset = 0, int offsetA = 0, int? length = null) { } public void ChecksNothing2(FauxDenseVector A, FauxDenseVector B, int offset = 0, int offsetA = 0, int offsetB = 0, int? length = null) { } public void ChecksNothing3(FauxDenseVector A, FauxDenseVector B, FauxDenseVector C, int offset = 0, int offsetA = 0, int offsetB = 0, int offsetC = 0, int? length = null) { } public void ChecksNothing4(FauxDenseVector A, FauxDenseVector B, FauxDenseVector C, FauxDenseVector D, int offset = 0, int offsetA = 0, int offsetB = 0, int offsetC = 0, int offsetD = 0, int? length = null) { } public void DoesNotAllowZeroLength(int offset = 0, int? length = null) { if ((length ?? Length) == 0) { throw new ArgumentException(); } } public void ChangesArguments(FauxDenseVector A, FauxDenseVector B, FauxDenseVector C, FauxDenseVector D, int offset = 0, int offsetA = 0, int offsetB = 0, int offsetC = 0, int offsetD = 0, int? length = null) { A.changed = true; B.changed = true; C.changed = true; D.changed = true; } public void Stride2(FauxDenseVector A, FauxDenseVector B, FauxDenseVector C, FauxDenseVector D, int offset = 0, int offsetA = 0, int offsetB = 0, int offsetC = 0, int offsetD = 0, int? length = null) { int runLength = (length ?? Length) / 2; CheckLength(offset, 2 * runLength, Length, stride: 2); CheckLength(offsetA, 2 * runLength, Length, stride: 2); CheckLength(offsetB, 2 * runLength, Length, stride: 2); CheckLength(offsetC, 2 * runLength, Length, stride: 2); CheckLength(offsetD, 2 * runLength, Length, stride: 2); } public void InterfaceArgument(IVector vector, int offset = 0, int? length = null) { } } [IgnoreFixture] public abstract class FauxBlasBoundsFixture : BlasBoundsFixtureGeneric { public FauxBlasBoundsFixture() : base(array => new FauxDenseVector { Length = array.Length }) { } } [IgnoreTest] public static System.ValueTuple RunTest( Expression> methodToTest) where T : FauxBlasBoundsFixture, new() { var fixture = new T(); var methodInfo = LambdaHelper.GetMethodInfoForWrappedCall(methodToTest); int failedChecks = 0; bool testPassed = TestRunner.RunTest(fixture, methodInfo, null, 0, _ => {}, ref failedChecks); return (testPassed, failedChecks); } [IgnoreTest] public static System.ValueTuple RunTest(Type type, Expression> methodToTest) { var fixture = (FauxBlasBoundsFixture)System.Activator.CreateInstance(type); var methodInfo = LambdaHelper.GetMethodInfoForWrappedCall(methodToTest); int failedChecks = 0; bool testPassed = TestRunner.RunTest(fixture, methodInfo, null, 0, _ => {}, ref failedChecks); return (testPassed, failedChecks); } public class StaticChecks1 : TestFixture { public Expression>[] StaticChecks1Methods = new Expression>[] { fixture => fixture.OffsetA_Negative(), fixture => fixture.OffsetA_TooLarge(), fixture => fixture.Length_Negative(), fixture => fixture.Length_TooLarge(), }; [IgnoreFixture] public class StaticChecks1_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.StaticChecks1); } [Parameterized(nameof(StaticChecks1Methods))] public void CheckPass0(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(0, failedChecks); Check(testPassed); } [IgnoreFixture] public class StaticChecksNothing0_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.StaticChecksNothing1); } [Parameterized(nameof(StaticChecks1Methods))] public void CheckFail0(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(1, failedChecks); CheckFalse(testPassed); } } public class Checks0 : TestFixture { public Expression>[] Checks0Methods = new Expression>[] { fixture => fixture.Offset_Negative(), fixture => fixture.Offset_TooLarge(), fixture => fixture.Length_Negative(), fixture => fixture.Length_TooLarge(), }; [IgnoreFixture] public class Checks0_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.Checks0); } [Parameterized(nameof(Checks0Methods))] public void CheckPass0(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(0, failedChecks); Check(testPassed); } [IgnoreFixture] public class ChecksNothing0_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.ChecksNothing0); } [Parameterized(nameof(Checks0Methods))] public void CheckFail0(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(1, failedChecks); CheckFalse(testPassed); } public void CheckBaselinePasses_Checks0() { (bool testPassed, int failedChecks) = RunTest(fixture => fixture.BaselinePasses()); CheckEqual(0, failedChecks); Check(testPassed); } public void CheckBaselinePasses_ChecksNothing0() { (bool testPassed, int failedChecks) = RunTest(fixture => fixture.BaselinePasses()); CheckEqual(0, failedChecks); Check(testPassed); } public void CheckZeroLengthPasses_Checks0() { (bool testPassed, int failedChecks) = RunTest(fixture => fixture.ZeroLength()); CheckEqual(0, failedChecks); Check(testPassed); } public void CheckZeroLengthPasses_ChecksNothing0() { (bool testPassed, int failedChecks) = RunTest(fixture => fixture.ZeroLength()); CheckEqual(0, failedChecks); Check(testPassed); } } public class Checks1 : TestFixture { public Expression>[] Checks1Methods = new Expression>[] { fixture => fixture.Offset_Negative(), fixture => fixture.Offset_TooLarge(), fixture => fixture.Length_Negative(), fixture => fixture.Length_TooLarge(), fixture => fixture.OffsetA_Negative(), fixture => fixture.OffsetA_TooLarge(), }; [IgnoreFixture] public class Checks1_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.Checks1); } [Parameterized(nameof(Checks1Methods))] public void CheckPass1(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(0, failedChecks); Check(testPassed); } [IgnoreFixture] public class ChecksNothing1_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.ChecksNothing1); } [Parameterized(nameof(Checks1Methods))] public void CheckFail1(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(1, failedChecks); CheckFalse(testPassed); } } public class Checks2 : TestFixture { public Expression>[] Checks2Methods = new Expression>[] { fixture => fixture.Offset_Negative(), fixture => fixture.Offset_TooLarge(), fixture => fixture.Length_Negative(), fixture => fixture.Length_TooLarge(), fixture => fixture.OffsetA_Negative(), fixture => fixture.OffsetA_TooLarge(), fixture => fixture.OffsetB_Negative(), fixture => fixture.OffsetB_TooLarge(), }; [IgnoreFixture] public class Checks2_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.Checks2); } [Parameterized(nameof(Checks2Methods))] public void CheckPass2(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(0, failedChecks); Check(testPassed); } [IgnoreFixture] public class ChecksNothing2_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.ChecksNothing2); } [Parameterized(nameof(Checks2Methods))] public void CheckFail2(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(1, failedChecks); CheckFalse(testPassed); } } public class Checks3 : TestFixture { public Expression>[] Checks3Methods = new Expression>[] { fixture => fixture.Offset_Negative(), fixture => fixture.Offset_TooLarge(), fixture => fixture.Length_Negative(), fixture => fixture.Length_TooLarge(), fixture => fixture.OffsetA_Negative(), fixture => fixture.OffsetA_TooLarge(), fixture => fixture.OffsetB_Negative(), fixture => fixture.OffsetB_TooLarge(), fixture => fixture.OffsetC_Negative(), fixture => fixture.OffsetC_TooLarge(), }; [IgnoreFixture] public class Checks3_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.Checks3); } [Parameterized(nameof(Checks3Methods))] public void CheckPass3(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(0, failedChecks); Check(testPassed); } [IgnoreFixture] public class ChecksNothing3_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.ChecksNothing3); } [Parameterized(nameof(Checks3Methods))] public void CheckFail3(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(1, failedChecks); CheckFalse(testPassed); } } public class Checks4 : TestFixture { public Expression>[] Checks4Methods = new Expression>[] { fixture => fixture.Offset_Negative(), fixture => fixture.Offset_TooLarge(), fixture => fixture.Length_Negative(), fixture => fixture.Length_TooLarge(), fixture => fixture.OffsetA_Negative(), fixture => fixture.OffsetA_TooLarge(), fixture => fixture.OffsetB_Negative(), fixture => fixture.OffsetB_TooLarge(), fixture => fixture.OffsetC_Negative(), fixture => fixture.OffsetC_TooLarge(), fixture => fixture.OffsetD_Negative(), fixture => fixture.OffsetD_TooLarge(), }; [IgnoreFixture] public class Checks4_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.Checks4); } [Parameterized(nameof(Checks4Methods))] public void CheckPass4(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(0, failedChecks); Check(testPassed); } [IgnoreFixture] public class ChecksNothing4_Fixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.ChecksNothing4); } [Parameterized(nameof(Checks4Methods))] public void CheckFail4(Expression> methodToTest) { (bool testPassed, int failedChecks) = RunTest(methodToTest); CheckEqual(1, failedChecks); CheckFalse(testPassed); } } public class OtherChecks : TestFixture { public Type[] FixturesChecks = new Type[] { typeof(StaticChecks1.StaticChecks1_Fixture), typeof(Checks0.Checks0_Fixture), typeof(Checks1.Checks1_Fixture), typeof(Checks2.Checks2_Fixture), typeof(Checks3.Checks3_Fixture), typeof(Checks4.Checks4_Fixture), typeof(StaticChecks1.StaticChecksNothing0_Fixture), typeof(Checks0.ChecksNothing0_Fixture), typeof(Checks1.ChecksNothing1_Fixture), typeof(Checks2.ChecksNothing2_Fixture), typeof(Checks3.ChecksNothing3_Fixture), typeof(Checks4.ChecksNothing4_Fixture), }; [Parameterized(nameof(FixturesChecks))] public void CheckBaselinePasses(Type type) { (bool testPassed, int failedChecks) = RunTest(type, fixture => fixture.BaselinePasses()); CheckEqual(0, failedChecks); Check(testPassed); } [Parameterized(nameof(FixturesChecks))] public void CheckZeroLengthPasses(Type type) { (bool testPassed, int failedChecks) = RunTest(type, fixture => fixture.ZeroLength()); CheckEqual(0, failedChecks); Check(testPassed); } } public class ChangesArgumentTests : TestFixture { [IgnoreFixture] public class ChangesArgumentsFixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.ChangesArguments); } public Expression>[] Methods = new Expression>[] { fixture => fixture.A_Unchanged(), fixture => fixture.B_Unchanged(), fixture => fixture.C_Unchanged(), fixture => fixture.D_Unchanged(), }; [Parameterized(nameof(Methods))] public void CheckUnchanged_A(Expression> method) { (bool testPassed, int failedChecks) = RunTest(method); CheckEqual(1, failedChecks); CheckFalse(testPassed); } public class AUnchangedTests : TestFixture { public Type[] FixturesChecks = new Type[] { typeof(Checks1.Checks1_Fixture), typeof(Checks2.Checks2_Fixture), typeof(Checks3.Checks3_Fixture), typeof(Checks4.Checks4_Fixture), }; [Parameterized(nameof(FixturesChecks))] public void CheckUnchanged(Type type) { (bool testPassed, int failedChecks) = RunTest(type, fixture => fixture.A_Unchanged()); CheckEqual(0, failedChecks); Check(testPassed); } } public class BUnchangedTests : TestFixture { public Type[] FixturesChecks = new Type[] { typeof(Checks2.Checks2_Fixture), typeof(Checks3.Checks3_Fixture), typeof(Checks4.Checks4_Fixture), }; [Parameterized(nameof(FixturesChecks))] public void CheckUnchanged(Type type) { (bool testPassed, int failedChecks) = RunTest(type, fixture => fixture.B_Unchanged()); CheckEqual(0, failedChecks); Check(testPassed); } } public class CUnchangedTests : TestFixture { public Type[] FixturesChecks = new Type[] { typeof(Checks3.Checks3_Fixture), typeof(Checks4.Checks4_Fixture), }; [Parameterized(nameof(FixturesChecks))] public void CheckUnchanged(Type type) { (bool testPassed, int failedChecks) = RunTest(type, fixture => fixture.C_Unchanged()); CheckEqual(0, failedChecks); Check(testPassed); } } public class DUnchangedTests : TestFixture { public Type[] FixturesChecks = new Type[] { typeof(Checks4.Checks4_Fixture), }; [Parameterized(nameof(FixturesChecks))] public void CheckUnchanged(Type type) { (bool testPassed, int failedChecks) = RunTest(type, fixture => fixture.D_Unchanged()); CheckEqual(0, failedChecks); Check(testPassed); } } } public class DoesNotAllowZeroLengthTests : TestFixture { [IgnoreFixture] public class DoesNotAllowZeroLengthFixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.DoesNotAllowZeroLength); public override bool AllowsZeroLength => false; } public void MethodThrowsException() { CheckThrow(); var fixture = new DoesNotAllowZeroLengthFixture(); fixture.FixtureSetup(); fixture.TestSetup(); fixture.Arguments.SetZeroLengths(); fixture.Arguments.Instance.DoesNotAllowZeroLength(); } public void TestModifiesItselfCorrectly() { (bool testPassed, int failedChecks) = RunTest( fixture => fixture.ZeroLength()); CheckEqual(0, failedChecks); Check(testPassed); } } public class OperationStride : TestFixture { [IgnoreFixture] public class OperationStrideFixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.Stride2); public override int OperationStride => 2; } [IgnoreFixture] public class IndividualStridesFixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.Stride2); public override int InstanceOperationStride => 2; public override int VectorAOperationStride => 2; public override int VectorBOperationStride => 2; public override int VectorCOperationStride => 2; public override int VectorDOperationStride => 2; } [IgnoreFixture] public class NoStrideFixture : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.Stride2); } public Expression>[] Methods = new Expression>[] { fixture => fixture.Offset_TooLarge(), fixture => fixture.OffsetA_TooLarge(), fixture => fixture.OffsetB_TooLarge(), fixture => fixture.OffsetC_TooLarge(), fixture => fixture.OffsetD_TooLarge(), }; [Parameterized(nameof(Methods))] public void Stride(Expression> method) { (bool testPassed, int failedChecks) = RunTest(method); CheckEqual(0, failedChecks); CheckTrue(testPassed); } [Parameterized(nameof(Methods))] public void NoStride(Expression> method) { (bool testPassed, int failedChecks) = RunTest(method); CheckEqual(1, failedChecks); CheckFalse(testPassed); } [Parameterized(nameof(Methods))] public void IndividualStrides(Expression> method) { (bool testPassed, int failedChecks) = RunTest(method); CheckEqual(0, failedChecks); Check(testPassed); } } public class TypeFactoryTests : TestFixture { [IgnoreFixture] public class WithTypeFactory : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.InterfaceArgument); public override Dictionary> TypeFactory => new Dictionary> { { typeof(IVector), () => new DenseVector() }, }; } [IgnoreFixture] public class NoTypeFactory : FauxBlasBoundsFixture { public override string MethodName => nameof(FauxDenseVector.InterfaceArgument); } public void WithTypeFactoryCompletes() { (bool success, int failures) = RunTest(fixture => fixture.BaselinePasses()); Check(success); CheckEqual(0, failures); } public void NoTypeFactoryFails() { (bool success, int failures) = RunTest(fixture => fixture.BaselinePasses()); CheckFalse(success); CheckEqual(1, failures); } } } }