public void FallingAcceleratesOverTime()
    {
        SingleJump jump          = GetSingleJump();
        Vector3    positionDelta = jump.CalculateNextPosition(false, DELTA_TIME);
        Vector3    lastDelta;

        for (int i = 0; i < 20; i++)
        {
            lastDelta     = positionDelta;
            positionDelta = jump.CalculateNextPosition(false, DELTA_TIME);
            if (positionDelta.magnitude == lastDelta.magnitude)
            {
                Assert.IsTrue(positionDelta.magnitude <= jump.TerminalVelocity,
                              "Delta cannot exceed terminal velocity.");
            }
            else
            {
                Assert.IsTrue(positionDelta.magnitude > lastDelta.magnitude,
                              "Next iteration of falling is expected to be faster than the last.\nCurrent: " + positionDelta.magnitude +
                              "\nLast: " + lastDelta.magnitude);
            }
            Assert.IsTrue(positionDelta.normalized == -jump.UpDirection,
                          "Falling is expected to be the opposite of up.");
        }
    }
    public void JumpHeldOverMaxTime()
    {
        SingleJump jump = GetSingleJump();

        jump.CalculateNextPosition(true, MAX_TIME_HOLD);

        Vector3 positionDelta = jump.CalculateNextPosition(true, DELTA_TIME);

        Assert.IsFalse(Mathf.Approximately(positionDelta.magnitude, 0.0f), "Position Delta should never be zero.");
        Assert.IsTrue(Mathf.Approximately((positionDelta.normalized + jump.UpDirection).magnitude, 0.0f),
                      "Falling must be in the opposite direction of up.");
    }
    public void JumpTest(float deltaTime)
    {
        SingleJump jump          = GetSingleJump();
        Vector3    positionDelta = jump.CalculateNextPosition(true, deltaTime);

        Assert.IsFalse(Mathf.Approximately(positionDelta.magnitude, 0.0f), "Position Delta should never be zero.");
        Assert.IsFalse(positionDelta.normalized != jump.UpDirection, "Jumping is in incorrect direction.");
    }
    public void JumpAllowedAfterLandingOnly()
    {
        SingleJump jump             = GetSingleJump();
        Collision  groundCollision  = GetBottomCollision();
        Collision  ceilingCollision = GetTopCollision();

        Vector3 initialJumpDelta = jump.CalculateNextPosition(true, MAX_TIME_HOLD);

        jump.OnHostEnterCollision(ceilingCollision);
        Vector3 actualFallVector = jump.CalculateNextPosition(true, MAX_TIME_HOLD);

        jump.OnHostEnterCollision(groundCollision);
        Vector3 actualSecondJumpDelta = jump.CalculateNextPosition(true, MAX_TIME_HOLD);

        Assert.AreEqual(initialJumpDelta, actualSecondJumpDelta);
        Assert.AreNotEqual(initialJumpDelta, actualFallVector);
        Assert.AreNotEqual(actualFallVector.normalized, actualSecondJumpDelta.normalized);
        Assert.AreEqual(initialJumpDelta.normalized, jump.UpDirection);
        Assert.AreEqual(actualFallVector.normalized, -jump.UpDirection);
        Assert.AreEqual(actualSecondJumpDelta, jump.UpDirection);
    }
    public void FallTest()
    {
        SingleJump jump = GetSingleJump();

        Vector3 positionDelta = jump.CalculateNextPosition(false, DELTA_TIME);

        Assert.IsTrue(Mathf.Approximately(positionDelta.magnitude, jump.StartFallSpeed),
                      "Falling must start at the starting fall speed.\nActual: " +
                      positionDelta.magnitude + "\nExpected: " + jump.StartFallSpeed);
        Assert.IsFalse(Mathf.Approximately(positionDelta.magnitude, 0.0f), "Position Delta should never be zero.");
        Assert.IsTrue(Mathf.Approximately((positionDelta.normalized + jump.UpDirection).magnitude, 0.0f),
                      "Falling must be in the opposite direction of up.");
    }
    public void JumpHeldTest()
    {
        SingleJump jump          = GetSingleJump();
        float      timeHeld      = 0;
        Vector3    positionDelta = jump.CalculateNextPosition(true, DELTA_TIME);

        timeHeld += DELTA_TIME;
        Vector3   lastPositionDelta;
        const int ITERATIONS_TO_MATCH_MAX = 9;

        for (int i = 0; i < ITERATIONS_TO_MATCH_MAX; i++)
        {
            lastPositionDelta = positionDelta;
            positionDelta     = jump.CalculateNextPosition(true, DELTA_TIME);
            timeHeld         += DELTA_TIME;
            Assert.IsTrue(positionDelta.magnitude < lastPositionDelta.magnitude,
                          "Position Delta must decrease as the button is held.\nTime held is:" + timeHeld +
                          "\nLast: " + lastPositionDelta.magnitude + "\tCurrent: " + positionDelta.magnitude);
            Assert.IsFalse(Mathf.Approximately(positionDelta.magnitude, 0.0f), "Position Delta should never be zero.");
            Assert.IsFalse(positionDelta.normalized != jump.UpDirection, "Jumping is in incorrect direction.");
        }
    }
    public void JumpIsFrameIndependent()
    {
        SingleJump jump0 = GetSingleJump();
        SingleJump jump1 = GetSingleJump();

        Vector3   positionDelta0          = Vector3.zero;
        const int ITERATIONS_TO_MATCH_MAX = 10;

        for (int i = 0; i < ITERATIONS_TO_MATCH_MAX; ++i)
        {
            positionDelta0 += jump0.CalculateNextPosition(true, DELTA_TIME);
        }

        Vector3 positionDelta1 = jump1.CalculateNextPosition(true, MAX_TIME_HOLD);

        Assert.IsTrue(Mathf.Approximately(positionDelta0.magnitude, positionDelta1.magnitude),
                      "Iteration: " + positionDelta0.magnitude + "\nImmediate: " + positionDelta1.magnitude +
                      "\nExpected identical deltas");
    }