using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Runtime.InteropServices.ComTypes; using System.Runtime.Serialization; using System.Text; using UnitTestSharp; namespace Azimuth.UnitTests { public class Vector3Tests : TestFixture { public class IVectorSpaceTests : TestFixture { public void Dimension() { IVectorSpace v1 = new Vector3(4, 14, 2); CheckEqual(3, v1.Dimension); } public void GetDimension() { IVectorSpace v1 = new Vector3(4, 14, 2); CheckEqual(4, v1[0]); CheckEqual(14, v1[1]); CheckEqual(2, v1[2]); } public void GetDimension_OutOfBounds_Hi() { IVectorSpace v1 = new Vector3(4, 14, 2); CheckThrow(typeof(System.Exception)); Scalar dummy = v1[3]; } public void GetDimension_OutOfBounds_Lo() { IVectorSpace v1 = new Vector3(4, 14, 2); CheckThrow(typeof(System.Exception)); Scalar dummy = v1[-1]; } public void AssignmentAdd() { IVectorSpace a = new Vector3(-10, 10, 2); Vector3 b = new Vector3(5, -5, 4); a.AddAssignment(b); CheckEqual(new Vector3(-5, 5, 6), a); } public void AssignmentSubtract() { IVectorSpace a = new Vector3(-10, 10, 2); Vector3 b = new Vector3(5, -5, -4); a.SubtractAssignment(b); CheckEqual(new Vector3(-15, 15, 6), a); } public void AssignmentScale() { IVectorSpace a = new Vector3(-10, 10, 4); Scalar b = -2; a.ScaleAssignment(b); CheckEqual(new Vector3(20, -20, -8), a); } public void AssignmentScaleThenAdd() { IVectorSpace a = new Vector3(10, 20, 4); Scalar scale = 10; Vector3 b = new Vector3(1, -1, 11); a.ScaleThenAddAssignment(scale, b); CheckEqual(new Vector3(20, 10, 114), a); CheckEqual(new Vector3(1, -1, 11), b); } public void InnerProduct() { Vector3 a = new Vector3(-10, 10, 4); Vector3 b = new Vector3(10, -10, 3); CheckEqual(-200 + 12, a.InnerProduct(b)); CheckEqual(new Vector3(-10, 10, 4), a); CheckEqual(new Vector3(10, -10, 3), b); } public void Clone() { Vector3 a = new Vector3(10, 20, 4); Vector3 b = ((IVectorSpace)a).Clone(); a += new Vector3(1, 2, 4); CheckEqual(new Vector3(10, 20, 4), b); CheckEqual(new Vector3(11, 22, 8), a); } } public void Ctor() { Vector3 vec = new Vector3(17, 23, 11); CheckEqual(17, vec.X); CheckEqual(23, vec.Y); CheckEqual(11, vec.Z); } public void StaticDotProduct() { Vector3 v1 = new Vector3(17, 23, 3); Vector3 v2 = new Vector3(-23, 17, -3); CheckEqual(-9, Vector3.DotProduct(v1, v2)); CheckEqual(-9, Vector3.DotProduct(v2, v1)); } public void DotProduct() { Vector3 v1 = new Vector3(17, 23, 3); Vector3 v2 = new Vector3(-23, 17, -3); CheckEqual(-9, v1.DotProduct(v2)); CheckEqual(-9, v2.DotProduct(v1)); } public void StaticCrossProduct() { Vector3 v1 = new Vector3(5, 11, 2); Vector3 v2 = new Vector3(-11, 17, 3); CheckEqual(new Vector3(-1, -37, 206), Vector3.CrossProduct(v1, v2)); CheckEqual(new Vector3(1, 37, -206), Vector3.CrossProduct(v2, v1)); } public void CrossProduct() { Vector3 v1 = new Vector3(5, 11, 2); Vector3 v2 = new Vector3(-11, 17, 3); CheckEqual(new Vector3(-1, -37, 206), v1.CrossProduct(v2)); CheckEqual(new Vector3(1, 37, -206), v2.CrossProduct(v1)); } public void LengthSquared() { Vector3 v1 = new Vector3(17, 23, 2); CheckEqual(822, v1.LengthSquared()); } public void Length() { Vector3 v1 = new Vector3(1, 4, 8); CheckEqual(9, v1.Length()); } public void Length_Zero() { Vector3 v1 = new Vector3(0, 0, 0); CheckEqual(0, v1.Length()); } public void Length_Negative_X() { Vector3 v1 = new Vector3(-1, 4, 8); CheckEqual(9, v1.Length()); } public void Length_Negative_Y() { Vector3 v1 = new Vector3(1, -4, 8); CheckEqual(9, v1.Length()); } public void Length_Negative_Z() { Vector3 v1 = new Vector3(1, 4, -8); CheckEqual(9, v1.Length()); } public void Length_AllNegative() { Vector3 v1 = new Vector3(-1, -4, -8); CheckEqual(9, v1.Length()); } public void Length_XCancellation() { Vector3 v1 = new Vector3(0, -4, -3); CheckEqual(5, v1.Length()); } public void Length_YCancellation() { Vector3 v1 = new Vector3(-3, 0, 4); CheckEqual(5, v1.Length()); } public void Length_ZCancellation() { Vector3 v1 = new Vector3(-3, 4, 0); CheckEqual(5, v1.Length()); } public void DistanceSquared() { Vector3 v1 = new Vector3(11, 13, 4); Vector3 v2 = new Vector3(28, 36, 4); CheckEqual(818, Vector3.DistanceSquared(v1, v2)); CheckEqual(818, Vector3.DistanceSquared(v2, v1)); } public void Distance() { Vector3 v1 = new Vector3(11, 13, 4); Vector3 v2 = new Vector3(15, 16, 4); CheckEqual(5, Vector3.Distance(v2, v1)); } public void Equality() { Vector3 v1 = new Vector3(3, 4, 5); Vector3 v2 = new Vector3(3, 4, 5); CheckEqual(v1, v2); } public void FuzzyEquality() { Vector3 v1 = new Vector3(3, 4, 5); Vector3 v2 = new Vector3(3 + 1e-11, 4 - 1e-11, 5 - 1e-11); CheckEqual(v1, v2); } public void Negation() { Vector3 v1 = new Vector3(-17, 23, 2); CheckEqual(17, (-v1).X); CheckEqual(-23, (-v1).Y); CheckEqual(-2, (-v1).Z); } public void Scaling_InPlace() { Vector3 v1 = new Vector3(1, 2, 3); v1 *= 3; CheckEqual(3, v1.X); CheckEqual(6, v1.Y); CheckEqual(9, v1.Z); } public void Scaling_Left() { Vector3 v1 = new Vector3(1, 2, 3); v1 = 3 * v1; CheckEqual(3, v1.X); CheckEqual(6, v1.Y); CheckEqual(9, v1.Z); } public void Scaling_Right() { Vector3 v1 = new Vector3(1, 2, 3); v1 = v1 * 3; CheckEqual(3, v1.X); CheckEqual(6, v1.Y); CheckEqual(9, v1.Z); } public void Addition() { Vector3 v1 = new Vector3(3, 4, 5); Vector3 v2 = new Vector3(-7, -11, 1); Vector3 expected = new Vector3(-4, -7, 6); CheckEqual(expected, v1 + v2); CheckEqual(expected, v2 + v1); } public void Addition_InPlace() { Vector3 v1 = new Vector3(3, 4, 5); Vector3 v2 = new Vector3(-7, -11, 1); Vector3 v3 = v1; Vector3 expected = new Vector3(-4, -7, 6); v1 += v2; v2 += v3; CheckEqual(expected, v1); CheckEqual(expected, v2); } public void Subtraction() { Vector3 v1 = new Vector3(3, 4, 5); Vector3 v2 = new Vector3(-7, -11, 1); Vector3 expected = new Vector3(10, 15, 4); CheckEqual(expected, v1 - v2); CheckEqual(-expected, v2 - v1); } public void Subtraction_InPlace() { Vector3 v1 = new Vector3(3, 4, 5); Vector3 v2 = new Vector3(-7, -11, 1); Vector3 v3 = v1; Vector3 expected = new Vector3(10, 15, 4); v1 -= v2; v2 -= v3; CheckEqual(expected, v1); CheckEqual(-expected, v2); } public void ScalarDivision_InPlace() { Vector3 v1 = new Vector3(16, 32, 5); Vector3 expected = new Vector3(2, 4, 5.0/8.0); v1 /= 8; CheckEqual(expected, v1); } public void ScalarDivision_Reverse() { Vector3 v1 = new Vector3(16, 32, 64); Vector3 expected = new Vector3(8.0 / 16.0, 8.0 / 32.0, 8.0 / 64.0); v1 = 8 / v1; CheckEqual(expected, v1); } public void ScalarDivision_Right() { Vector3 v1 = new Vector3(16, 32, 64); Vector3 expected = new Vector3(2, 4, 8); v1 = v1 / 8; CheckEqual(expected, v1); } public void Normalization() { Vector3 v1 = new Vector3(1, 4, 8); v1.Normalize(); CheckEqual(new Vector3(1.0 / 9.0, 4.0 / 9.0, 8.0 / 9.0), v1); } public void Normalization_ZeroLength() { Vector3 v1 = new Vector3(0, 0, 0); v1.Normalize(); Check(Vector3.IsNaN(v1)); } public void NormalizedCopy() { Vector3 v1 = new Vector3(1, 4, 8); CheckEqual(new Vector3(1.0 / 9.0, 4.0 / 9.0, 8.0 / 9.0), v1.NormalizedCopy()); CheckEqual(new Vector3(1, 4, 8), v1); } public void NormalizedCopy_ZeroLength() { Vector3 v1 = new Vector3(0, 0, 0); Check(Vector3.IsNaN(v1.NormalizedCopy())); } public void Vector3_IsNotNaN() { Vector3 v1 = new Vector3(1, 2, 3); CheckFalse(Vector3.IsNaN(v1)); } public void Vector3_IsNan_JustX() { Vector3 v1 = new Vector3(Scalar.NaN, 2, 3); Check(Vector3.IsNaN(v1)); } public void Vector3_IsNan_JustY() { Vector3 v1 = new Vector3(1, Scalar.NaN, 3); Check(Vector3.IsNaN(v1)); } public void Vector3_IsNan_JustZ() { Vector3 v1 = new Vector3(1, 3, Scalar.NaN); Check(Vector3.IsNaN(v1)); } public void Vector3_IsNan_XYZ() { Vector3 v1 = new Vector3(Scalar.NaN, Scalar.NaN, Scalar.NaN); Check(Vector3.IsNaN(v1)); } public void Vector3_ToString() { Vector3 v1 = new Vector3(1, 2, 3); CheckEqual("<1 : 2 : 3>", v1.ToString()); } public void Vector3_ToString_Fuzzy() { Vector3 v1 = new Vector3(1.0 / 3.0, 2.0 / 3.0, 3.0); CheckEqual("<0.3333333333 : 0.6666666667 : 3>", v1.ToString()); } public void MinMax() { Vector3 v1 = new Vector3(8, 1, 2); Vector3 v2 = new Vector3(3, 24, 11); Vector3 v3, v4; v1.MinMax(v2, out v3, out v4); CheckEqual(new Vector3(3, 1, 2), v3); CheckEqual(new Vector3(8, 24, 11), v4); } public class CompareToTests : TestFixture { public void CompletelyUnequal() { var a = new Vector3(7, 2, 0); var b = new Vector3(2, 1, 5); Check(a.CompareTo(b) > 0); Check(b.CompareTo(a) < 0); } public void CompletelyEqual() { var a = new Vector3(7, 2, 1); var b = new Vector3(7, 2, 1); Check(a.CompareTo(b) == 0); Check(b.CompareTo(a) == 0); } public void XZsEqual() { var a = new Vector3(7, 2, 0); var b = new Vector3(7, 1, 0); Check(a.CompareTo(b) > 0); Check(b.CompareTo(a) < 0); } public void YZsEqual() { var a = new Vector3(2, 7, 3); var b = new Vector3(1, 7, 3); Check(a.CompareTo(b) > 0); Check(b.CompareTo(a) < 0); } public void XYsEqual() { var a = new Vector3(1, 7, 3); var b = new Vector3(1, 7, -3); Check(a.CompareTo(b) > 0); Check(b.CompareTo(a) < 0); } } public class ToStringTests : TestFixture { public void Fractions() { var Vector3 = new Vector3(1.125, 5.321, 2.111); CheckEqual("<1.125 : 5.321 : 2.111>", Vector3.ToString()); } public void Basic() { var Vector3 = new Vector3(1, 5, 2); CheckEqual("<1 : 5 : 2>", Vector3.ToString()); } public void Infinity() { var Vector3 = new Vector3(Scalar.PositiveInfinity, Scalar.PositiveInfinity, Scalar.PositiveInfinity); CheckEqual("", Vector3.ToString()); } public void NegativeInfinity() { var Vector3 = new Vector3(Scalar.NegativeInfinity, Scalar.NegativeInfinity, Scalar.NegativeInfinity); CheckEqual("<-Infinity : -Infinity : -Infinity>", Vector3.ToString()); } public void NaN() { var Vector3 = new Vector3(Scalar.NaN, Scalar.NaN, Scalar.NaN); CheckEqual("", Vector3.ToString()); } public class FormatProviders : UnitTestSharp.TestFixture { private static System.Globalization.NumberFormatInfo formatter = System.Globalization.CultureInfo.GetCultureInfo("de-DE").NumberFormat; public void Basic() { var Vector3 = new Vector3(1, 5, 2); CheckEqual("<1 : 5 : 2>", Vector3.ToString(formatter)); } public void Fractions() { var Vector3 = new Vector3(1.125, 5.321, 2.111); CheckEqual("<1,125 : 5,321 : 2,111>", Vector3.ToString(formatter)); } public void Infinity() { var Vector3 = new Vector3(Scalar.PositiveInfinity, Scalar.PositiveInfinity, Scalar.PositiveInfinity); string symbol = formatter.PositiveInfinitySymbol; CheckEqual($"<{symbol} : {symbol} : {symbol}>", Vector3.ToString(formatter)); } public void NegativeInfinity() { var Vector3 = new Vector3(Scalar.NegativeInfinity, Scalar.NegativeInfinity, Scalar.NegativeInfinity); string symbol = formatter.NegativeInfinitySymbol; CheckEqual($"<{symbol} : {symbol} : {symbol}>", Vector3.ToString(formatter)); } public void NaN() { var Vector3 = new Vector3(Scalar.NaN, Scalar.NaN, Scalar.NaN); string symbol = formatter.NaNSymbol; CheckEqual($"<{symbol} : {symbol} : {symbol}>", Vector3.ToString(formatter)); } } public class CustomFormatter : UnitTestSharp.TestFixture { public void Fractions() { var Vector3 = new Vector3(1.125, 5.321, 2.2222); CheckEqual("", Vector3.ToString("MOM 0.#")); } public void Basic() { var Vector3 = new Vector3(1, 5, 2); CheckEqual("", Vector3.ToString("MOM 0.#")); } public void Infinity() { var Vector3 = new Vector3(Scalar.PositiveInfinity, Scalar.PositiveInfinity, Scalar.PositiveInfinity); CheckEqual("", Vector3.ToString("MOM 0.#")); } public void NegativeInfinity() { var Vector3 = new Vector3(Scalar.NegativeInfinity, Scalar.NegativeInfinity, Scalar.NegativeInfinity); CheckEqual("<-Infinity : -Infinity : -Infinity>", Vector3.ToString("MOM 0.#")); } public void NaN() { var Vector3 = new Vector3(Scalar.NaN, Scalar.NaN, Scalar.NaN); CheckEqual("", Vector3.ToString("MOM 0.#")); } } } public class Parse : TestFixture { public void Basic() { var text = "<10.45 : 11.234 : 2.123>"; var expected = new Vector3(10.45, 11.234, 2.123); var actual = Vector3.Parse(text); CheckEqual(expected, actual); } public void NaN() { var text = ""; var actual = Vector3.Parse(text); Check(Scalar.IsNaN(actual.X)); Check(Scalar.IsNaN(actual.Y)); Check(Scalar.IsNaN(actual.Z)); } public void Infinity() { var text = ""; var actual = Vector3.Parse(text); Check(Scalar.IsInfinity(actual.X)); Check(Scalar.IsNegativeInfinity(actual.Y)); Check(Scalar.IsInfinity(actual.Z)); } public class FormatProviders : UnitTestSharp.TestFixture { private static NumberFormatInfo formatter = System.Globalization.CultureInfo.GetCultureInfo("de-DE").NumberFormat; public void Basic() { var text = "<3000,23 : 7043,1 : 2,123>"; var expected = new Vector3(3000.23, 7043.1, 2.123); var actual = Vector3.Parse(text, formatter); CheckEqual(expected, actual); } public void NaN() { string symbol = formatter.NaNSymbol; var text = $"<{symbol} : {symbol} : {symbol}>"; var actual = Vector3.Parse(text, formatter); Check(Scalar.IsNaN(actual.X)); Check(Scalar.IsNaN(actual.Y)); Check(Scalar.IsNaN(actual.Z)); } public void Infinity() { string symbol = formatter.PositiveInfinitySymbol; string negSymbol = formatter.NegativeInfinitySymbol; var text = $"<{symbol} : {negSymbol} : {negSymbol}>"; var actual = Vector3.Parse(text, formatter); Check(Scalar.IsInfinity(actual.X)); Check(Scalar.IsNegativeInfinity(actual.Y)); Check(Scalar.IsNegativeInfinity(actual.Z)); } } public class CustomFormatter : UnitTestSharp.TestFixture { public void Basic() { var text = "<3,000.23 : 7,043.1 : 2,123>"; var expected = new Vector3(3000.23, 7043.1, 2123); var actual = Vector3.Parse(text, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float); CheckEqual(expected, actual); } public void NaN() { var text = ""; var actual = Vector3.Parse(text, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float); Check(Scalar.IsNaN(actual.X)); Check(Scalar.IsNaN(actual.Y)); Check(Scalar.IsNaN(actual.Z)); } public void Infinity() { var text = ""; var actual = Vector3.Parse(text, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float); Check(Scalar.IsInfinity(actual.X)); Check(Scalar.IsNegativeInfinity(actual.Y)); Check(Scalar.IsNegativeInfinity(actual.Z)); } } } public class TryParse : TestFixture { public void Basic() { var text = "<10.45 : 11.234 : 2.123>"; var expected = new Vector3(10.45, 11.234, 2.123); Vector3 actual; bool success = Vector3.TryParse(text, out actual); CheckEqual(expected, actual); Check(success); } public void NaN() { var text = ""; Vector3 actual; bool success = Vector3.TryParse(text, out actual); Check(Scalar.IsNaN(actual.X)); Check(Scalar.IsNaN(actual.Y)); Check(Scalar.IsNaN(actual.Z)); Check(success); } public void Infinity() { var text = ""; Vector3 actual; bool success = Vector3.TryParse(text, out actual); Check(Scalar.IsInfinity(actual.X)); Check(Scalar.IsNegativeInfinity(actual.Y)); Check(Scalar.IsNegativeInfinity(actual.Z)); Check(success); } public class FormatProviders : UnitTestSharp.TestFixture { private static NumberFormatInfo formatter = System.Globalization.CultureInfo.GetCultureInfo("de-DE").NumberFormat; public void Basic() { var text = "<3000,23 : 7043,1 : 2,123>"; var expected = new Vector3(3000.23, 7043.1, 2.123); Vector3 actual; bool success = Vector3.TryParse(text, formatter, out actual); CheckEqual(expected, actual); Check(success); } public void NaN() { string symbol = formatter.NaNSymbol; var text = $"<{symbol} : {symbol} : {symbol}>"; Vector3 actual; bool success = Vector3.TryParse(text, formatter, out actual); Check(Scalar.IsNaN(actual.X)); Check(Scalar.IsNaN(actual.Y)); Check(Scalar.IsNaN(actual.Z)); Check(success); } public void Infinity() { string a = formatter.PositiveInfinitySymbol; string b = formatter.NegativeInfinitySymbol; string c = formatter.NegativeInfinitySymbol; var text = $"<{a} : {b} : {c}>"; Vector3 actual; bool success = Vector3.TryParse(text, formatter, out actual); Check(Scalar.IsInfinity(actual.X)); Check(Scalar.IsNegativeInfinity(actual.Y)); Check(Scalar.IsNegativeInfinity(actual.Z)); Check(success); } } public class CustomFormatter : UnitTestSharp.TestFixture { public void Basic() { var text = "<3,000.23 : 7,043.1 : 2,123>"; var expected = new Vector3(3000.23, 7043.1, 2123); Vector3 actual; bool success = Vector3.TryParse(text, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, out actual); CheckEqual(expected, actual); Check(success); } public void NaN() { var text = ""; Vector3 actual; bool success = Vector3.TryParse(text, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, out actual); Check(Scalar.IsNaN(actual.X)); Check(Scalar.IsNaN(actual.Y)); Check(Scalar.IsNaN(actual.Z)); Check(success); } public void Infinity() { var text = ""; Vector3 actual; bool success = Vector3.TryParse(text, System.Globalization.NumberStyles.AllowThousands | System.Globalization.NumberStyles.Float, out actual); Check(Scalar.IsInfinity(actual.X)); Check(Scalar.IsNegativeInfinity(actual.Y)); Check(Scalar.IsNegativeInfinity(actual.Z)); Check(success); } } } public class L1NormTests : UnitTestSharp.TestFixture { public void Basic() { var vec = new Vector3(7, 2, 1); CheckEqual(7, vec.L1Norm()); } public void Negative() { var vec = new Vector3(-7, -2, -1); CheckEqual(7, vec.L1Norm()); } } public class LexographicalSort : UnitTestSharp.TestFixture { public void X() { var a = new Vector3(0, 1, 2); var b = new Vector3(1, 0, 0); CheckFalse(Vector3.LexographicallyGreaterThan(a, b)); CheckTrue(Vector3.LexographicallyGreaterThan(b, a)); } public void Y() { var a = new Vector3(1, 0, 3); var b = new Vector3(1, 1, 2); CheckFalse(Vector3.LexographicallyGreaterThan(a, b)); CheckTrue(Vector3.LexographicallyGreaterThan(b, a)); } public void Z() { var a = new Vector3(1, 1, 2); var b = new Vector3(1, 1, 3); CheckFalse(Vector3.LexographicallyGreaterThan(a, b)); CheckTrue(Vector3.LexographicallyGreaterThan(b, a)); } public void Equal() { var a = new Vector3(1, 1, 1); var b = new Vector3(1, 1, 1); CheckFalse(Vector3.LexographicallyGreaterThan(a, b)); CheckFalse(Vector3.LexographicallyGreaterThan(b, a)); } } } }