2017-03-19 12:34:47 +01:00
|
|
|
namespace OpenTK.Tests
|
|
|
|
|
|
|
|
open Xunit
|
|
|
|
open FsCheck
|
|
|
|
open FsCheck.Xunit
|
|
|
|
open System
|
|
|
|
open OpenTK
|
|
|
|
|
2017-03-19 12:39:01 +01:00
|
|
|
module Vector2 =
|
2017-03-19 15:32:37 +01:00
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module Constructors =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
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)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
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)
|
|
|
|
|
2017-05-31 16:14:04 +02:00
|
|
|
//[<Property>]
|
2017-03-19 15:36:36 +01:00
|
|
|
// disabled - behaviour needs discussion
|
2017-03-19 15:32:37 +01:00
|
|
|
let ``Clamping works for each component`` (a : Vector2,b : Vector2,c : Vector2) =
|
|
|
|
let inline clamp (value : float32) minV maxV = MathHelper.Clamp(value,minV,maxV)
|
|
|
|
let r = Vector2.Clamp(a,b,c)
|
|
|
|
Assert.Equal(clamp a.X b.X c.X,r.X)
|
2017-03-19 15:36:36 +01:00
|
|
|
Assert.Equal(clamp a.Y b.Y c.Y,r.Y)
|
2017-03-19 15:32:37 +01:00
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Length is always >= 0`` (a : Vector2) =
|
|
|
|
//
|
|
|
|
Assert.True(a.Length >= 0.0f)
|
2017-05-31 16:14:04 +02:00
|
|
|
|
2017-05-31 22:28:27 +02:00
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module Length =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
let ``Length method works`` (a, b) =
|
|
|
|
let v = Vector2(a, b)
|
|
|
|
let l = System.Math.Sqrt((float)(a * a + b * b))
|
|
|
|
|
|
|
|
Assert.Equal((float32)l, v.Length)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
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)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Length squared method works`` (a, b) =
|
|
|
|
let v = Vector2(a, b)
|
|
|
|
let lsq = a * a + b * b
|
|
|
|
|
|
|
|
Assert.Equal(lsq, v.LengthSquared)
|
|
|
|
|
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module ``Unit vectors and perpendicularity`` =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
let ``Perpendicular vector to the right is correct`` (a, b) =
|
|
|
|
let v = Vector2(a, b)
|
|
|
|
let perp = Vector2(a, -b)
|
|
|
|
|
|
|
|
Assert.Equal(perp, v.PerpendicularRight)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Perpendicular vector to the left is correct`` (a, b) =
|
|
|
|
let v = Vector2(a, b)
|
|
|
|
let perp = Vector2(-a, b)
|
|
|
|
|
|
|
|
Assert.Equal(perp, v.PerpendicularLeft)
|
|
|
|
|
2017-05-31 16:14:04 +02:00
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module Indexing =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
let ``Index operators work for the correct components`` (x,y) =
|
|
|
|
let v = Vector2(x,y)
|
|
|
|
Assert.Equal(v.[0],v.X)
|
|
|
|
Assert.Equal(v.[1],v.Y)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector indexing throws index out of range exception correctly`` (x, y) =
|
|
|
|
let mutable v = Vector2(x, y)
|
|
|
|
let invalidIndexingAccess = fun() -> v.[2] |> ignore
|
|
|
|
Assert.Throws<IndexOutOfRangeException>(invalidIndexingAccess) |> ignore
|
|
|
|
|
|
|
|
let invalidIndexingAssignment = (fun() -> v.[2] <- x)
|
|
|
|
Assert.Throws<IndexOutOfRangeException>(invalidIndexingAssignment) |> ignore
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Component assignment by indexing works`` (x, y) =
|
|
|
|
let mutable v = Vector2()
|
|
|
|
v.[0] <- x
|
|
|
|
v.[1] <- y
|
|
|
|
Assert.Equal(x, v.X)
|
|
|
|
Assert.Equal(y, v.Y)
|
|
|
|
|
|
|
|
|
2017-03-19 14:35:46 +01:00
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
2017-03-19 12:39:01 +01:00
|
|
|
module ``Simple Properties`` =
|
2017-03-19 12:34:47 +01:00
|
|
|
//
|
2017-03-19 12:39:01 +01:00
|
|
|
[<Property>]
|
|
|
|
let ``Vector equality is by component`` (a : Vector2,b : Vector2) =
|
|
|
|
//
|
|
|
|
Assert.Equal((a.X = b.X && a.Y = b.Y),(a = b))
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector length is always >= 0`` (a : Vector2) =
|
|
|
|
//
|
|
|
|
Assert.True(a.Length >= 0.0f)
|
2017-03-19 12:34:47 +01:00
|
|
|
|
2017-03-19 14:35:46 +01:00
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
2017-03-19 12:39:01 +01:00
|
|
|
module Addition =
|
2017-03-19 12:34:47 +01:00
|
|
|
//
|
2017-03-19 12:39:01 +01:00
|
|
|
[<Property>]
|
|
|
|
let ``Vector addition is the same as component addition`` (a : Vector2,b : Vector2) =
|
|
|
|
let c = a + b
|
2017-03-19 14:35:46 +01:00
|
|
|
Assert.ApproximatelyEqual(a.X + b.X,c.X)
|
|
|
|
Assert.ApproximatelyEqual(a.Y + b.Y,c.Y)
|
2017-03-19 12:39:01 +01:00
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector addition is commutative`` (a : Vector2,b : Vector2) =
|
|
|
|
let c = a + b
|
|
|
|
let c2 = b + a
|
2017-03-19 14:35:46 +01:00
|
|
|
Assert.ApproximatelyEqual(c,c2)
|
2017-03-19 12:39:01 +01:00
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector addition is associative`` (a : Vector2,b : Vector2,c : Vector2) =
|
|
|
|
let r1 = (a + b) + c
|
|
|
|
let r2 = a + (b + c)
|
2017-03-19 14:35:46 +01:00
|
|
|
Assert.ApproximatelyEqual(r1,r2)
|
2017-03-19 12:34:47 +01:00
|
|
|
|
2017-03-19 14:35:46 +01:00
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
2017-03-19 12:39:01 +01:00
|
|
|
module Multiplication =
|
|
|
|
//
|
|
|
|
[<Property>]
|
2017-05-31 20:08:41 +02:00
|
|
|
let ``Vector2 multiplication is the same as component multiplication`` (a : Vector2, b : Vector2) =
|
2017-03-19 12:39:01 +01:00
|
|
|
let c = a * b
|
|
|
|
Assert.Equal(a.X * b.X,c.X)
|
|
|
|
Assert.Equal(a.Y * b.Y,c.Y)
|
|
|
|
|
|
|
|
[<Property>]
|
2017-05-31 20:08:41 +02:00
|
|
|
let ``Vector2 multiplication is commutative`` (a : Vector2, b : Vector2) =
|
2017-03-19 12:39:01 +01:00
|
|
|
let r1 = a * b
|
|
|
|
let r2 = b * a
|
|
|
|
Assert.Equal(r1,r2)
|
|
|
|
|
|
|
|
[<Property>]
|
2017-05-31 20:08:41 +02:00
|
|
|
let ``Vector2-float multiplication is the same as component-float multiplication`` (a : Vector2, f : float32) =
|
2017-03-19 12:39:01 +01:00
|
|
|
let r = a * f
|
|
|
|
Assert.Equal(a.X * f,r.X)
|
|
|
|
Assert.Equal(a.Y * f,r.Y)
|
2017-05-31 16:14:04 +02:00
|
|
|
|
|
|
|
// Inverse direction
|
|
|
|
let r = f * a
|
|
|
|
Assert.Equal(a.X * f,r.X)
|
|
|
|
Assert.Equal(a.Y * f,r.Y)
|
2017-03-19 12:34:47 +01:00
|
|
|
|
2017-03-19 14:35:46 +01:00
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
2017-03-19 12:39:01 +01:00
|
|
|
module Subtraction =
|
|
|
|
//
|
|
|
|
[<Property>]
|
2017-05-31 20:08:41 +02:00
|
|
|
let ``Vector2 subtraction is the same as component subtraction`` (a : Vector2, b : Vector2) =
|
2017-03-19 12:39:01 +01:00
|
|
|
let c = a - b
|
|
|
|
Assert.Equal(a.X - b.X,c.X)
|
|
|
|
Assert.Equal(a.Y - b.Y,c.Y)
|
2017-03-19 12:34:47 +01:00
|
|
|
|
2017-03-19 14:35:46 +01:00
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
2017-03-19 12:39:01 +01:00
|
|
|
module Division =
|
|
|
|
//
|
|
|
|
[<Property>]
|
2017-05-31 20:08:41 +02:00
|
|
|
let ``Vector2-float division is the same as component-float division`` (a : Vector2, f : float32) =
|
2017-03-19 15:43:19 +01:00
|
|
|
if not (approxEq f 0.0f) then // we don't support diving by zero.
|
|
|
|
let r = a / f
|
|
|
|
Assert.ApproximatelyEqual(a.X / f,r.X)
|
|
|
|
Assert.ApproximatelyEqual(a.Y / f,r.Y)
|
2017-05-31 16:14:04 +02:00
|
|
|
|
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module Negation =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector negation operator works`` (x, y) =
|
|
|
|
let v = Vector2(x, y)
|
|
|
|
let vNeg = -v
|
|
|
|
Assert.Equal(-x, vNeg.X)
|
|
|
|
Assert.Equal(-y, vNeg.Y)
|
|
|
|
|
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module Equality =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector equality operator works`` (x, y) =
|
|
|
|
let v1 = Vector2(x, y)
|
|
|
|
let v2 = Vector2(x, y)
|
|
|
|
let equality = v1 = v2
|
2017-05-31 16:39:19 +02:00
|
|
|
|
2017-05-31 16:14:04 +02:00
|
|
|
Assert.True(equality)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector inequality operator works`` (x, y) =
|
|
|
|
let v1 = Vector2(x, y)
|
2017-05-31 16:45:18 +02:00
|
|
|
let v2 = Vector2(x + (float32)1 , y + (float32)1)
|
2017-05-31 16:14:04 +02:00
|
|
|
let inequality = v1 <> v2
|
2017-05-31 16:39:19 +02:00
|
|
|
|
2017-05-31 16:14:04 +02:00
|
|
|
Assert.True(inequality)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector equality method works`` (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)
|
|
|
|
|
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module Swizzling =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
let ``Vector swizzling works`` (x, y) =
|
|
|
|
let v1 = Vector2(x, y)
|
|
|
|
let v2 = Vector2(y, x)
|
|
|
|
|
|
|
|
let v1yx = v1.Yx;
|
|
|
|
Assert.Equal(v2, v1yx);
|
|
|
|
|
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module Interpolation =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
let ``Linear interpolation works`` (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))
|
|
|
|
|
2017-05-31 16:39:19 +02:00
|
|
|
let vRes = Vector2.Lerp(ref a, ref b, q)
|
2017-05-31 16:14:04 +02:00
|
|
|
Assert.Equal(vExp, vRes)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Barycentric interpolation works`` (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))
|
|
|
|
|
2017-05-31 16:39:19 +02:00
|
|
|
let vRes = Vector2.BaryCentric(ref a, ref b, ref c, u, v)
|
2017-05-31 16:14:04 +02:00
|
|
|
Assert.Equal(r, vRes)
|
|
|
|
|
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
|
|
|
module ``Vector products`` =
|
|
|
|
//
|
|
|
|
[<Property>]
|
|
|
|
let ``Dot product works`` (a : Vector2, b : Vector2) =
|
|
|
|
let dot = a.X * b.X + a.Y * b.Y
|
|
|
|
|
|
|
|
Assert.Equal(dot, Vector2.Dot(a, b));
|
|
|
|
|
2017-05-31 16:39:19 +02:00
|
|
|
let vRes = Vector2.Dot(ref a, ref b)
|
2017-05-31 16:14:04 +02:00
|
|
|
Assert.Equal(dot, vRes)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Perpendicular dot product works`` (a : Vector2, b : Vector2) =
|
2017-05-31 16:39:19 +02:00
|
|
|
let dot = a.X * b.Y - a.Y * b.X
|
2017-05-31 16:14:04 +02:00
|
|
|
|
|
|
|
Assert.Equal(dot, Vector2.PerpDot(a, b));
|
|
|
|
|
2017-05-31 16:39:19 +02:00
|
|
|
let vRes = Vector2.PerpDot(ref a, ref b)
|
2017-05-31 16:14:04 +02:00
|
|
|
Assert.Equal(dot, vRes)
|
|
|
|
|
|
|
|
[<Properties(Arbitrary = [| typeof<OpenTKGen> |])>]
|
2017-05-31 22:28:27 +02:00
|
|
|
module Normalization =
|
2017-05-31 16:14:04 +02:00
|
|
|
//
|
2017-05-31 22:28:27 +02:00
|
|
|
[<Property>]
|
|
|
|
let ``Normalization of instance, creating a new vector, works`` (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.ApproximatelyEqual(v.X / l, norm.X)
|
|
|
|
Assert.ApproximatelyEqual(v.Y / l, norm.Y)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Normalization of instance works`` (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.ApproximatelyEqual(v.X / l, norm.X)
|
|
|
|
Assert.ApproximatelyEqual(v.Y / l, norm.Y)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Fast approximate normalization of instance works`` (a, b) =
|
|
|
|
let v = Vector2(a, b)
|
|
|
|
let norm = Vector2(a, b)
|
|
|
|
norm.NormalizeFast()
|
|
|
|
|
|
|
|
let scale = MathHelper.InverseSqrtFast(a * a + b * b)
|
|
|
|
|
|
|
|
Assert.ApproximatelyEqual(v.X * scale, norm.X)
|
|
|
|
Assert.ApproximatelyEqual(v.Y * scale, norm.Y)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Normalization by reference works`` (a : Vector2) =
|
|
|
|
if not (approxEq a.Length 0.0f) then
|
|
|
|
let scale = 1.0f / a.Length
|
|
|
|
let norm = Vector2(a.X * scale, a.Y * scale)
|
|
|
|
let vRes = Vector2.Normalize(ref a)
|
|
|
|
|
|
|
|
Assert.ApproximatelyEqual(norm, vRes)
|
|
|
|
|
2017-05-31 16:14:04 +02:00
|
|
|
[<Property>]
|
|
|
|
let ``Normalization works`` (a : Vector2) =
|
2017-05-31 22:28:27 +02:00
|
|
|
if not (approxEq a.Length 0.0f) then
|
|
|
|
let scale = 1.0f / a.Length
|
|
|
|
let norm = Vector2(a.X * scale, a.Y * scale)
|
|
|
|
|
2017-05-31 22:28:51 +02:00
|
|
|
Assert.ApproximatelyEqual(norm, Vector2.Normalize(a));
|
2017-05-31 16:14:04 +02:00
|
|
|
|
|
|
|
[<Property>]
|
2017-05-31 22:28:27 +02:00
|
|
|
let ``Fast approximate normalization by reference works`` (a : Vector2) =
|
2017-05-31 16:14:04 +02:00
|
|
|
let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y)
|
2017-05-31 22:28:27 +02:00
|
|
|
|
2017-05-31 16:14:04 +02:00
|
|
|
let norm = Vector2(a.X * scale, a.Y * scale)
|
2017-05-31 16:39:19 +02:00
|
|
|
let vRes = Vector2.NormalizeFast(ref a)
|
2017-05-31 16:14:04 +02:00
|
|
|
|
2017-05-31 22:28:27 +02:00
|
|
|
Assert.ApproximatelyEqual(norm, vRes)
|
|
|
|
|
|
|
|
[<Property>]
|
|
|
|
let ``Fast approximate normalization works`` (a : Vector2) =
|
|
|
|
let scale = MathHelper.InverseSqrtFast(a.X * a.X + a.Y * a.Y)
|
|
|
|
|
|
|
|
let norm = Vector2(a.X * scale, a.Y * scale)
|
|
|
|
|
|
|
|
Assert.ApproximatelyEqual(norm, Vector2.NormalizeFast(a));
|