namespace OpenTK.Tests open Xunit open FsCheck open FsCheck.Xunit open System open System.Runtime.InteropServices open OpenTK module Vector2 = [ |])>] module Constructors = // [] let ``Single value constructor sets all components to the same value`` (f : float32) = let v = Vector2(f) Assert.Equal(f,v.X) Assert.Equal(f,v.Y) [] let ``Two value constructor sets all components correctly`` (x,y) = let v = Vector2(x,y) Assert.Equal(x,v.X) Assert.Equal(y,v.Y) [ |])>] module Clamping = // [] let ``Clamping one vector between two other vectors clamps all components between corresponding components`` (a : Vector2, b : Vector2, w : Vector2) = let res = Vector2.Clamp(w, a, b) let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y Assert.Equal(expX, res.X) Assert.Equal(expY, res.Y) [] let ``Clamping one vector between two other vectors by reference clamps all components`` (a : Vector2, b : Vector2, w : Vector2) = let res = Vector2.Clamp(ref w, ref a, ref b) let expX = if w.X < a.X then a.X else if w.X > b.X then b.X else w.X let expY = if w.Y < a.Y then a.Y else if w.Y > b.Y then b.Y else w.Y Assert.Equal(expX, res.X) Assert.Equal(expY, res.Y) [ |])>] module Length = // [] let ``Length is always >= 0`` (a : Vector2) = // Assert.True(a.Length >= 0.0f) [] let ``Length follows the pythagorean theorem`` (a, b) = let v = Vector2(a, b) let l = System.Math.Sqrt((float)(a * a + b * b)) Assert.Equal((float32)l, v.Length) [] let ``Fast length method works`` (a, b) = let v = Vector2(a, b) let l = 1.0f / MathHelper.InverseSqrtFast(a * a + b * b) Assert.Equal(l, v.LengthFast) [] let ``Length squared method works`` (a, b) = let v = Vector2(a, b) let lsq = a * a + b * b Assert.Equal(lsq, v.LengthSquared) [ |])>] module Distance = [] let ``Distance(a, b) = (b - a).Length`` (a : Vector2, b : Vector2) = Assert.ApproximatelyEqual(Vector2.Distance(a, b), (b - a).Length) [] let ``DistanceSquared(a, b) = (b - a).LengthSquared`` (a : Vector2, b : Vector2) = Assert.ApproximatelyEqual(Vector2.DistanceSquared(a, b), (b - a).LengthSquared) [ |])>] module ``Unit vectors and perpendicularity`` = // [] let ``Perpendicular vector to the right is correct`` (a, b) = let v = Vector2(a, b) let perp = Vector2(b, -a) Assert.Equal(perp, v.PerpendicularRight) [] let ``Perpendicular vector to the left is correct`` (a, b) = let v = Vector2(a, b) let perp = Vector2(-b, a) Assert.Equal(perp, v.PerpendicularLeft) [ |])>] module Indexing = // [] let ``Index operator accesses the correct components`` (x, y) = let v = Vector2(x, y) Assert.Equal(x, v.[0]) Assert.Equal(y, v.[1]) [] let ``Indexed set operator throws exception for negative indices`` (x, y) = let mutable v = Vector2(x, y) (fun() -> v.[-1] <- x) |> Assert.ThrowsIndexExn [] let ``Indexed get operator throws exception for negative indices`` (x, y) = let mutable v = Vector2(x, y) (fun() -> v.[-1] |> ignore) |> Assert.ThrowsIndexExn [] let ``Indexed set operator throws exception for large indices`` (x, y) = let mutable v = Vector2(x, y) (fun() -> v.[2] <- x) |> Assert.ThrowsIndexExn [] let ``Indexed get operator throws exception for large indices`` (x, y) = let mutable v = Vector2(x, y) (fun() -> v.[2] |> ignore) |> Assert.ThrowsIndexExn [ |])>] module ``Simple Properties`` = // [] let ``Vector equality is by component`` (a : Vector2,b : Vector2) = // Assert.Equal((a.X = b.X && a.Y = b.Y),(a = b)) [] let ``Vector length is always >= 0`` (a : Vector2) = // Assert.True(a.Length >= 0.0f) [ |])>] module Addition = // [] let ``Vector addition is the same as component addition`` (a : Vector2,b : Vector2) = let c = a + b Assert.ApproximatelyEquivalent(a.X + b.X,c.X) Assert.ApproximatelyEquivalent(a.Y + b.Y,c.Y) [] let ``Vector addition is commutative`` (a : Vector2,b : Vector2) = let c = a + b let c2 = b + a Assert.ApproximatelyEquivalent(c,c2) [] let ``Vector addition is associative`` (a : Vector2,b : Vector2,c : Vector2) = let r1 = (a + b) + c let r2 = a + (b + c) Assert.ApproximatelyEquivalent(r1,r2) [] let ``Static Vector2 addition method is the same as component addition`` (a : Vector2, b : Vector2) = let v1 = Vector2(a.X + b.X, a.Y + b.Y) let sum = Vector2.Add(a, b) Assert.ApproximatelyEquivalent(v1, sum) [] let ``Static Vector2 addition method by reference is the same as component addition`` (a : Vector2, b : Vector2) = let v1 = Vector2(a.X + b.X, a.Y + b.Y) let sum = Vector2.Add(ref a, ref b) Assert.ApproximatelyEquivalent(v1, sum) [ |])>] module Multiplication = // [] let ``Vector2 multiplication is the same as component multiplication`` (a : Vector2, b : Vector2) = let c = a * b Assert.Equal(a.X * b.X,c.X) Assert.Equal(a.Y * b.Y,c.Y) [] let ``Vector2 multiplication is commutative`` (a : Vector2, b : Vector2) = let r1 = a * b let r2 = b * a Assert.Equal(r1,r2) [] let ``Left-handed Vector2-scalar multiplication is the same as component-scalar multiplication`` (a : Vector2, f : float32) = let r = a * f Assert.Equal(a.X * f,r.X) Assert.Equal(a.Y * f,r.Y) [] let ``Right-handed Vector2-scalar multiplication is the same as component-scalar multiplication`` (a : Vector2, f : float32) = let r = f * a Assert.Equal(a.X * f,r.X) Assert.Equal(a.Y * f,r.Y) [] let ``Static Vector2 multiplication method is the same as component multiplication`` (a : Vector2, b : Vector2) = let v1 = Vector2(a.X * b.X, a.Y * b.Y) let sum = Vector2.Multiply(a, b) Assert.ApproximatelyEquivalent(v1, sum) [] let ``Static Vector2 multiplication method by reference is the same as component multiplication`` (a : Vector2, b : Vector2) = let v1 = Vector2(a.X * b.X, a.Y * b.Y) let sum = Vector2.Multiply(ref a, ref b) Assert.ApproximatelyEquivalent(v1, sum) [] let ``Static method Vector2-scalar multiplication is the same as component-scalar multiplication`` (a : Vector2, f : float32) = let r = Vector2.Multiply(a, f) Assert.Equal(a.X * f,r.X) Assert.Equal(a.Y * f,r.Y) [ |])>] module Subtraction = // [] let ``Vector2 subtraction is the same as component subtraction`` (a : Vector2, b : Vector2) = let c = a - b Assert.Equal(a.X - b.X,c.X) Assert.Equal(a.Y - b.Y,c.Y) [] let ``Static Vector2 subtraction method is the same as component addition`` (a : Vector2, b : Vector2) = let v1 = Vector2(a.X - b.X, a.Y - b.Y) let sum = Vector2.Subtract(a, b) Assert.ApproximatelyEquivalent(v1, sum) [] let ``Static Vector2 subtraction method by reference is the same as component addition`` (a : Vector2, b : Vector2) = let v1 = Vector2(a.X - b.X, a.Y - b.Y) let sum = Vector2.Subtract(ref a, ref b) Assert.ApproximatelyEquivalent(v1, sum) [ |])>] module Division = // [] let ``Vector2-float division is the same as component-float division`` (a : Vector2, f : float32) = if not (approxEq f 0.0f) then let r = a / f Assert.ApproximatelyEquivalent(a.X / f,r.X) Assert.ApproximatelyEquivalent(a.Y / f,r.Y) [] let ``Static Vector2-Vector2 division method is the same as component division`` (a : Vector2, b : Vector2) = if not (anyZero2 a || anyZero2 b) then let v1 = Vector2(a.X / b.X, a.Y / b.Y) let sum = Vector2.Divide(a, b) Assert.ApproximatelyEquivalent(v1, sum) [] let ``Static Vector2-Vector2 divison method by reference `` (a : Vector2, b : Vector2) = if not (anyZero2 a || anyZero2 b) then let v1 = Vector2(a.X / b.X, a.Y / b.Y) let sum = Vector2.Divide(ref a, ref b) Assert.ApproximatelyEquivalent(v1, sum) [] let ``Static Vector2-scalar division method is the same as component division`` (a : Vector2, b : float32) = if not (approxEq b 0.0f) then let v1 = Vector2(a.X / b, a.Y / b) let sum = Vector2.Divide(a, b) Assert.ApproximatelyEquivalent(v1, sum) [] let ``Static Vector2-scalar divison method by reference is the same as component division`` (a : Vector2, b : float32) = if not (approxEq b 0.0f) then let v1 = Vector2(a.X / b, a.Y / b) let sum = Vector2.Divide(ref a, b) Assert.ApproximatelyEquivalent(v1, sum) [ |])>] module Negation = // [] let ``Vector negation operator negates all components`` (x, y) = let v = Vector2(x, y) let vNeg = -v Assert.Equal(-x, vNeg.X) Assert.Equal(-y, vNeg.Y) [ |])>] module Equality = // [] let ``Vector equality operator is by component`` (x, y) = let v1 = Vector2(x, y) let v2 = Vector2(x, y) let equality = v1 = v2 Assert.True(equality) [] let ``Vector inequality operator is by component`` (x, y) = let v1 = Vector2(x, y) let v2 = Vector2(x + 1.0f , y + 1.0f) let inequality = v1 <> v2 Assert.True(inequality) [] let ``Vector equality method is by component`` (x, y) = let v1 = Vector2(x, y) let v2 = Vector2(x, y) let notVector = Matrix2() let equality = v1.Equals(v2) let inequalityByOtherType = v1.Equals(notVector) Assert.True(equality) Assert.False(inequalityByOtherType) [ |])>] module Swizzling = // [] let ``Vector swizzling returns the correct composites`` (x, y) = let v1 = Vector2(x, y) let v2 = Vector2(y, x) let v1yx = v1.Yx; Assert.Equal(v2, v1yx); [ |])>] module Interpolation = // [] let ``Linear interpolation is by component`` (a : Vector2, b : Vector2, q) = let blend = q let rX = blend * (b.X - a.X) + a.X let rY = blend * (b.Y - a.Y) + a.Y let vExp = Vector2(rX, rY) Assert.Equal(vExp, Vector2.Lerp(a, b, q)) let vRes = Vector2.Lerp(ref a, ref b, q) Assert.Equal(vExp, vRes) [] let ``Barycentric interpolation follows the barycentric formula`` (a : Vector2, b : Vector2, c : Vector2, u, v) = let r = a + u * (b - a) + v * (c - a) Assert.Equal(r, Vector2.BaryCentric(a, b, c, u, v)) let vRes = Vector2.BaryCentric(ref a, ref b, ref c, u, v) Assert.Equal(r, vRes) [ |])>] module ``Vector products`` = // [] let ``Dot product follows the dot product formula`` (a : Vector2, b : Vector2) = let dot = a.X * b.X + a.Y * b.Y Assert.Equal(dot, Vector2.Dot(a, b)); let vRes = Vector2.Dot(ref a, ref b) Assert.Equal(dot, vRes) [] let ``Perpendicular dot product follows the perpendicular dot product formula`` (a : Vector2, b : Vector2) = let perpDot = a.X * b.Y - a.Y * b.X Assert.Equal(perpDot, Vector2.PerpDot(a, b)); let vRes = Vector2.PerpDot(ref a, ref b) Assert.Equal(perpDot, vRes) [ |])>] module Normalization = // [] let ``Normalization creates a new unit length vector with the correct components`` (a, b) = let v = Vector2(a, b) let l = v.Length // Dividing by zero is not supported if not (approxEq l 0.0f) then let norm = v.Normalized() Assert.ApproximatelyEquivalent(v.X / l, norm.X) Assert.ApproximatelyEquivalent(v.Y / l, norm.Y) [] let ``Normalization of instance transforms the instance into a unit length vector with the correct components`` (a, b) = let v = Vector2(a, b) let l = v.Length if not (approxEq l 0.0f) then let norm = Vector2(a, b) norm.Normalize() Assert.ApproximatelyEquivalent(v.X / l, norm.X) Assert.ApproximatelyEquivalent(v.Y / l, norm.Y) [] let ``Fast approximate normalization of instance transforms the instance into a unit length vector with the correct components`` (a, b) = let v = Vector2(a, b) let norm = Vector2(a, b) norm.NormalizeFast() let scale = MathHelper.InverseSqrtFast(a * a + b * b) Assert.ApproximatelyEquivalent(v.X * scale, norm.X) Assert.ApproximatelyEquivalent(v.Y * scale, norm.Y) [] let ``Normalization by reference is the same as division by magnitude`` (a : Vector2) = // Zero-length vectors can't be normalized if not (approxEq a.Length 0.0f) then let norm = a / a.Length let vRes = Vector2.Normalize(ref a) Assert.ApproximatelyEquivalent(norm, vRes) [] let ``Normalization is the same as division by magnitude`` (a : Vector2) = // Zero-length vectors can't be normalized if not (approxEq a.Length 0.0f) then let norm = a / a.Length Assert.ApproximatelyEquivalent(norm, Vector2.Normalize(a)); [] let ``Fast approximate normalization by reference is the same as multiplication by the fast inverse square`` (a : Vector2) = let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y) let norm = a * scale let vRes = Vector2.NormalizeFast(ref a) Assert.ApproximatelyEquivalent(norm, vRes) [] let ``Fast approximate normalization is the same as multiplication by the fast inverse square`` (a : Vector2) = let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y) let norm = a * scale Assert.ApproximatelyEquivalent(norm, Vector2.NormalizeFast(a)); [ |])>] module ``Magnitude min and max`` = // [] let ``MagnitudeMin selects the vector with equal or lesser magnitude given two vectors`` (v1 : Vector2, v2: Vector2) = // Results do not matter for equal vectors if not (v1 = v2) then let l1 = v1.LengthSquared let l2 = v2.LengthSquared let vMin = Vector2.MagnitudeMin(v1, v2) if vMin = v1 then let v1ShorterThanv2 = l1 < l2 Assert.True(v1ShorterThanv2) else let v2ShorterThanOrEqualTov1 = l2 <= l1 Assert.True(v2ShorterThanOrEqualTov1) [] let ``MagnitudeMax selects the vector with equal or greater magnitude given two vectors`` (v1 : Vector2, v2: Vector2) = // Results do not matter for equal vectors if not (v1 = v2) then let l1 = v1.LengthSquared let l2 = v2.LengthSquared let vMin = Vector2.MagnitudeMax(v1, v2) if vMin = v1 then let v1LongerThanOrEqualTov2 = l1 >= l2 Assert.True(v1LongerThanOrEqualTov2) else let v2LongerThanv1 = l2 > l1 Assert.True(v2LongerThanv1) [] let ``MagnitudeMin by reference selects the vector with equal or lesser magnitude given two vectors`` (v1 : Vector2, v2: Vector2) = // Results do not matter for equal vectors if not (v1 = v2) then let l1 = v1.LengthSquared let l2 = v2.LengthSquared let vMin = Vector2.MagnitudeMin(ref v1, ref v2) if vMin = v1 then let v1ShorterThanv2 = l1 < l2 Assert.True(v1ShorterThanv2) else let v2ShorterThanOrEqualTov1 = l2 <= l1 Assert.True(v2ShorterThanOrEqualTov1) [] let ``MagnitudeMax by reference selects the vector with equal greater magnitude given two vectors`` (v1 : Vector2, v2: Vector2) = // Results do not matter for equal vectors if not (v1 = v2) then let l1 = v1.LengthSquared let l2 = v2.LengthSquared let vMin = Vector2.MagnitudeMax(ref v1, ref v2) if vMin = v1 then let v1LongerThanOrEqualTov2 = l1 >= l2 Assert.True(v1LongerThanOrEqualTov2) else let v2LongerThanv1 = l2 > l1 Assert.True(v2LongerThanv1) [ |])>] module ``Component min and max`` = // [] let ``ComponentMin creates a new vector from the smallest components of given vectors`` (v1 : Vector2, v2: Vector2) = let vMin = Vector2.ComponentMin(v1, v2) let isComponentSmallest smallComp comp1 comp2 = smallComp <= comp1 && smallComp <= comp2 Assert.True(isComponentSmallest vMin.X v1.X v2.X) Assert.True(isComponentSmallest vMin.Y v1.Y v2.Y) [] let ``ComponentMax creates a new vector from the greatest components of given vectors`` (v1 : Vector2, v2: Vector2) = let vMax = Vector2.ComponentMax(v1, v2) let isComponentLargest largeComp comp1 comp2 = largeComp >= comp1 && largeComp >= comp2 Assert.True(isComponentLargest vMax.X v1.X v2.X) Assert.True(isComponentLargest vMax.Y v1.Y v2.Y) [] let ``ComponentMin by reference creates a new vector from the smallest components of given vectors`` (v1 : Vector2, v2: Vector2) = let vMin = Vector2.ComponentMin(ref v1, ref v2) let isComponentSmallest smallComp comp1 comp2 = smallComp <= comp1 && smallComp <= comp2 Assert.True(isComponentSmallest vMin.X v1.X v2.X) Assert.True(isComponentSmallest vMin.Y v1.Y v2.Y) [] let ``ComponentMax by reference creates a new vector from the greatest components of given vectors`` (v1 : Vector2, v2: Vector2) = let vMax = Vector2.ComponentMax(ref v1, ref v2) let isComponentLargest largeComp comp1 comp2 = largeComp >= comp1 && largeComp >= comp2 Assert.True(isComponentLargest vMax.X v1.X v2.X) Assert.True(isComponentLargest vMax.Y v1.Y v2.Y) [ |])>] module Transformation = // [] let ``Transformation by quaternion is the same as multiplication by quaternion and its conjugate`` (v : Vector2, q : Quaternion) = let vectorQuat = Quaternion(v.X, v.Y, 0.0f, 0.0f) let inverse = Quaternion.Invert(q) let transformedQuat = q * vectorQuat * inverse let transformedVector = Vector2(transformedQuat.X, transformedQuat.Y) Assert.ApproximatelyEquivalent(transformedVector, Vector2.Transform(v, q)) [] let ``Transformation by quaternion by reference is the same as multiplication by quaternion and its conjugate`` (v : Vector2, q : Quaternion) = let vectorQuat = Quaternion(v.X, v.Y, 0.0f, 0.0f) let inverse = Quaternion.Invert(q) let transformedQuat = q * vectorQuat * inverse let transformedVector = Vector2(transformedQuat.X, transformedQuat.Y) Assert.ApproximatelyEquivalent(transformedVector, Vector2.Transform(ref v, ref q)) [ |])>] module Serialization = // [] let ``The absolute size of a Vector2 is always the size of its components`` (v : Vector2) = let expectedSize = sizeof * 2 Assert.Equal(expectedSize, Vector2.SizeInBytes) Assert.Equal(expectedSize, Marshal.SizeOf(Vector2()))