/** \file
 *
 *  Contains the test cases for the AuvMath class
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef _AUVMATH_TEST_H_
#define _AUVMATH_TEST_H_

#include "data/Slate.h"
#include "utils/AuvMath.h"

#include <cxxtest/TestSuite.h>

/**
 * %Units tests for class AuvMath
 *
 * \ingroup utils
 */
class AuvMath_Test : public CxxTest::TestSuite
{
public:

    void testAreaContains( void )
    {
        float x0[] = {0, 3, 3, 0, 1, 2, 2, 1};
        float y0[] = {0, 0, 3, 3, 1, 1, 2, 2};
        float x1[] = {3, 3, 0, 0, 2, 2, 1, 1};
        float y1[] = {0, 3, 3, 0, 1, 2, 2, 1};

        TS_ASSERT( !AuvMath::AreaContains( -0.5, -0.5, 8, x0, y0, x1, y1 ) );
        TS_ASSERT( AuvMath::AreaContains( 0.5, 0.5, 8, x0, y0, x1, y1 ) );
        TS_ASSERT( !AuvMath::AreaContains( 1.5, 1.5, 8, x0, y0, x1, y1 ) );
        TS_ASSERT( AuvMath::AreaContains( 2.5, 2.5, 8, x0, y0, x1, y1 ) );
        TS_ASSERT( !AuvMath::AreaContains( 3.5, 3.5, 8, x0, y0, x1, y1 ) );
        TS_ASSERT( AuvMath::AreaContains( 1, 0.5, 8, x0, y0, x1, y1 ) );
        TS_ASSERT( AuvMath::AreaContains( 0.5, 1, 8, x0, y0, x1, y1 ) );
        TS_ASSERT( AuvMath::AreaContains( 2, 0.5, 8, x0, y0, x1, y1 ) );
        TS_ASSERT( AuvMath::AreaContains( 0.5, 2, 8, x0, y0, x1, y1 ) );
    }

    /// AuvMath::Limit %Unit Tests
    void testLimit( void )
    {
        // char
        signed char cMin = -128, cMid = 0, cMax = 127;
        TS_ASSERT_EQUALS( AuvMath::Limit( cMin, cMin, cMax ), cMin );
        TS_ASSERT_EQUALS( AuvMath::Limit( cMid, cMin, cMax ), cMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( cMax, cMin, cMax ), cMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( cMax, cMin, cMax ), cMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( cMin, cMid, cMax ), cMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( cMax, cMin, cMid ), cMid );
        // unsigned char
        unsigned char ucMin = 0, ucMid = 128, ucMax = 255;
        TS_ASSERT_EQUALS( AuvMath::Limit( ucMin, ucMin, ucMax ), ucMin );
        TS_ASSERT_EQUALS( AuvMath::Limit( ucMid, ucMin, ucMax ), ucMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( ucMax, ucMin, ucMax ), ucMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( ucMax, ucMin, ucMax ), ucMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( ucMin, ucMid, ucMax ), ucMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( ucMax, ucMin, ucMid ), ucMid );
        // int
        int iMin = -2147483647, iMid = 0, iMax = 2147483647;
        TS_ASSERT_EQUALS( AuvMath::Limit( iMin, iMin, iMax ), iMin );
        TS_ASSERT_EQUALS( AuvMath::Limit( iMid, iMin, iMax ), iMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( iMax, iMin, iMax ), iMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( iMax, iMin, iMax ), iMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( iMin, iMid, iMax ), iMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( iMax, iMin, iMid ), iMid );
        // unsigned int
        unsigned int uiMin = 0, uiMid = 2147483648U, uiMax = 4294967295U;
        TS_ASSERT_EQUALS( AuvMath::Limit( uiMin, uiMin, uiMax ), uiMin );
        TS_ASSERT_EQUALS( AuvMath::Limit( uiMid, uiMin, uiMax ), uiMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( uiMax, uiMin, uiMax ), uiMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( uiMax, uiMin, uiMax ), uiMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( uiMin, uiMid, uiMax ), uiMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( uiMax, uiMin, uiMid ), uiMid );
        // float
        float fMin = -INFINITY, fMid = 0, fMax = INFINITY, fNan = nanf( "" ), fRes;
        TS_ASSERT_EQUALS( AuvMath::Limit( fMin, fMin, fMax ), fMin );
        TS_ASSERT_EQUALS( AuvMath::Limit( fMid, fMin, fMax ), fMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( fMax, fMin, fMax ), fMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( fMax, fMin, fMax ), fMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( fMin, fMid, fMax ), fMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( fMax, fMin, fMid ), fMid );
        fRes = AuvMath::Limit( fNan, fMin, fMax );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Limit( fMid, fNan, fMax );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Limit( fMid, fMin, fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );
        // double
        double dMin = -INFINITY, dMid = 0, dMax = INFINITY, dNan = nan( "" ), dRes;
        TS_ASSERT_EQUALS( AuvMath::Limit( dMin, dMin, dMax ), dMin );
        TS_ASSERT_EQUALS( AuvMath::Limit( dMid, dMin, dMax ), dMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( dMax, dMin, dMax ), dMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( dMax, dMin, dMax ), dMax );
        TS_ASSERT_EQUALS( AuvMath::Limit( dMin, dMid, dMax ), dMid );
        TS_ASSERT_EQUALS( AuvMath::Limit( dMax, dMin, dMid ), dMid );
        dRes = AuvMath::Limit( dNan, dMin, dMax );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Limit( dMid, dNan, dMax );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Limit( dMid, dMin, dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// AuvMath::Min %Unit Tests
    void testMin( void )
    {
        // char
        signed char cMin = -128, cMid = 0, cMax = 127;
        TS_ASSERT_EQUALS( AuvMath::Min( cMin, cMax ), cMin );
        TS_ASSERT_EQUALS( AuvMath::Min( cMax, cMin ), cMin );
        TS_ASSERT_EQUALS( AuvMath::Min( cMin, cMid ), cMin );
        TS_ASSERT_EQUALS( AuvMath::Min( cMid, cMin ), cMin );
        TS_ASSERT_EQUALS( AuvMath::Min( cMid, cMax ), cMid );
        TS_ASSERT_EQUALS( AuvMath::Min( cMax, cMid ), cMid );
        // unsigned char
        unsigned char ucMin = 0, ucMid = 128, ucMax = 255;
        TS_ASSERT_EQUALS( AuvMath::Min( ucMin, ucMax ), ucMin );
        TS_ASSERT_EQUALS( AuvMath::Min( ucMax, ucMin ), ucMin );
        TS_ASSERT_EQUALS( AuvMath::Min( ucMin, ucMid ), ucMin );
        TS_ASSERT_EQUALS( AuvMath::Min( ucMid, ucMin ), ucMin );
        TS_ASSERT_EQUALS( AuvMath::Min( ucMid, ucMax ), ucMid );
        TS_ASSERT_EQUALS( AuvMath::Min( ucMax, ucMid ), ucMid );
        // int
        int iMin = -2147483647, iMid = 0, iMax = 2147483647;
        TS_ASSERT_EQUALS( AuvMath::Min( iMin, iMax ), iMin );
        TS_ASSERT_EQUALS( AuvMath::Min( iMax, iMin ), iMin );
        TS_ASSERT_EQUALS( AuvMath::Min( iMin, iMid ), iMin );
        TS_ASSERT_EQUALS( AuvMath::Min( iMid, iMin ), iMin );
        TS_ASSERT_EQUALS( AuvMath::Min( iMid, iMax ), iMid );
        TS_ASSERT_EQUALS( AuvMath::Min( iMax, iMid ), iMid );
        // unsigned int
        unsigned int uiMin = 0, uiMid = 2147483648U, uiMax = 4294967295U;
        TS_ASSERT_EQUALS( AuvMath::Min( uiMin, uiMax ), uiMin );
        TS_ASSERT_EQUALS( AuvMath::Min( uiMax, uiMin ), uiMin );
        TS_ASSERT_EQUALS( AuvMath::Min( uiMin, uiMid ), uiMin );
        TS_ASSERT_EQUALS( AuvMath::Min( uiMid, uiMin ), uiMin );
        TS_ASSERT_EQUALS( AuvMath::Min( uiMid, uiMax ), uiMid );
        TS_ASSERT_EQUALS( AuvMath::Min( uiMax, uiMid ), uiMid );
        // float
        float fMin = -INFINITY, fMid = 0, fMax = INFINITY, fNan = nanf( "" ), fRes;
        TS_ASSERT_EQUALS( AuvMath::Min( fMin, fMax ), fMin );
        TS_ASSERT_EQUALS( AuvMath::Min( fMax, fMin ), fMin );
        TS_ASSERT_EQUALS( AuvMath::Min( fMin, fMid ), fMin );
        TS_ASSERT_EQUALS( AuvMath::Min( fMid, fMin ), fMin );
        TS_ASSERT_EQUALS( AuvMath::Min( fMid, fMax ), fMid );
        TS_ASSERT_EQUALS( AuvMath::Min( fMax, fMid ), fMid );
        fRes = AuvMath::Min( fNan, fMax );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Min( fMin, fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Min( fMid, fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );
        // double
        double dMin = -INFINITY, dMid = 0, dMax = INFINITY, dNan = nan( "" ), dRes;
        TS_ASSERT_EQUALS( AuvMath::Min( dMin, dMax ), dMin );
        TS_ASSERT_EQUALS( AuvMath::Min( dMax, dMin ), dMin );
        TS_ASSERT_EQUALS( AuvMath::Min( dMin, dMid ), dMin );
        TS_ASSERT_EQUALS( AuvMath::Min( dMid, dMin ), dMin );
        TS_ASSERT_EQUALS( AuvMath::Min( dMid, dMax ), dMid );
        TS_ASSERT_EQUALS( AuvMath::Min( dMax, dMid ), dMid );
        dRes = AuvMath::Min( dNan, dMax );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Min( dMin, dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Min( dMid, dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// AuvMath::Max %Unit Tests
    void testMax( void )
    {
        // char
        signed char cMin = -128, cMid = 0, cMax = 127;
        TS_ASSERT_EQUALS( AuvMath::Max( cMin, cMax ), cMax );
        TS_ASSERT_EQUALS( AuvMath::Max( cMax, cMin ), cMax );
        TS_ASSERT_EQUALS( AuvMath::Max( cMin, cMid ), cMid );
        TS_ASSERT_EQUALS( AuvMath::Max( cMid, cMin ), cMid );
        TS_ASSERT_EQUALS( AuvMath::Max( cMid, cMax ), cMax );
        TS_ASSERT_EQUALS( AuvMath::Max( cMax, cMid ), cMax );
        // unsigned char
        unsigned char ucMin = 0, ucMid = 128, ucMax = 255;
        TS_ASSERT_EQUALS( AuvMath::Max( ucMin, ucMax ), ucMax );
        TS_ASSERT_EQUALS( AuvMath::Max( ucMax, ucMin ), ucMax );
        TS_ASSERT_EQUALS( AuvMath::Max( ucMin, ucMid ), ucMid );
        TS_ASSERT_EQUALS( AuvMath::Max( ucMid, ucMin ), ucMid );
        TS_ASSERT_EQUALS( AuvMath::Max( ucMid, ucMax ), ucMax );
        TS_ASSERT_EQUALS( AuvMath::Max( ucMax, ucMid ), ucMax );
        // int
        int iMin = -2147483647, iMid = 0, iMax = 2147483647;
        TS_ASSERT_EQUALS( AuvMath::Max( iMin, iMax ), iMax );
        TS_ASSERT_EQUALS( AuvMath::Max( iMax, iMin ), iMax );
        TS_ASSERT_EQUALS( AuvMath::Max( iMin, iMid ), iMid );
        TS_ASSERT_EQUALS( AuvMath::Max( iMid, iMin ), iMid );
        TS_ASSERT_EQUALS( AuvMath::Max( iMid, iMax ), iMax );
        TS_ASSERT_EQUALS( AuvMath::Max( iMax, iMid ), iMax );
        // unsigned int
        unsigned int uiMin = 0, uiMid = 2147483648U, uiMax = 4294967295U;
        TS_ASSERT_EQUALS( AuvMath::Max( uiMin, uiMax ), uiMax );
        TS_ASSERT_EQUALS( AuvMath::Max( uiMax, uiMin ), uiMax );
        TS_ASSERT_EQUALS( AuvMath::Max( uiMin, uiMid ), uiMid );
        TS_ASSERT_EQUALS( AuvMath::Max( uiMid, uiMin ), uiMid );
        TS_ASSERT_EQUALS( AuvMath::Max( uiMid, uiMax ), uiMax );
        TS_ASSERT_EQUALS( AuvMath::Max( uiMax, uiMid ), uiMax );
        // float
        float fMin = -INFINITY, fMid = 0, fMax = INFINITY, fNan = nanf( "" ), fRes;
        TS_ASSERT_EQUALS( AuvMath::Max( fMin, fMax ), fMax );
        TS_ASSERT_EQUALS( AuvMath::Max( fMax, fMin ), fMax );
        TS_ASSERT_EQUALS( AuvMath::Max( fMin, fMid ), fMid );
        TS_ASSERT_EQUALS( AuvMath::Max( fMid, fMin ), fMid );
        TS_ASSERT_EQUALS( AuvMath::Max( fMid, fMax ), fMax );
        TS_ASSERT_EQUALS( AuvMath::Max( fMax, fMid ), fMax );
        fRes = AuvMath::Max( fNan, fMax );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Max( fMin, fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Max( fMid, fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );
        // double
        double dMin = -INFINITY, dMid = 0, dMax = INFINITY, dNan = nan( "" ), dRes;
        TS_ASSERT_EQUALS( AuvMath::Max( dMin, dMax ), dMax );
        TS_ASSERT_EQUALS( AuvMath::Max( dMax, dMin ), dMax );
        TS_ASSERT_EQUALS( AuvMath::Max( dMin, dMid ), dMid );
        TS_ASSERT_EQUALS( AuvMath::Max( dMid, dMin ), dMid );
        TS_ASSERT_EQUALS( AuvMath::Max( dMid, dMax ), dMax );
        TS_ASSERT_EQUALS( AuvMath::Max( dMax, dMid ), dMax );
        dRes = AuvMath::Max( dNan, dMax );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Max( dMin, dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Max( dMid, dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// AuvMath::Swap %Unit Tests
    void testSwap( void )
    {
        // char
        signed char cMin = -128, cMax = 127;
        AuvMath::Swap( cMin, cMax );
        TS_ASSERT_EQUALS( cMin, 127 );
        TS_ASSERT_EQUALS( cMax, -128 );

        // unsigned char
        unsigned char ucMin = 0, ucMax = 255;
        AuvMath::Swap( ucMin, ucMax );
        TS_ASSERT_EQUALS( ucMin, 255 );
        TS_ASSERT_EQUALS( ucMax, 0 );

        // int
        int iMin = -2147483647, iMax = 2147483647;
        AuvMath::Swap( iMin, iMax );
        TS_ASSERT_EQUALS( iMin, 2147483647 );
        TS_ASSERT_EQUALS( iMax, -2147483647 );

        // unsigned int
        unsigned int uiMin = 0, uiMax = 4294967295U;
        AuvMath::Swap( uiMin, uiMax );
        TS_ASSERT_EQUALS( uiMin, 4294967295U );
        TS_ASSERT_EQUALS( uiMax, 0U );

        // float
        float fMin = -INFINITY, fMax = INFINITY, fNan = nanf( "" );
        AuvMath::Swap( fMin, fMax );
        TS_ASSERT_EQUALS( fMin, ( float )INFINITY );
        TS_ASSERT_EQUALS( fMax, ( float ) - INFINITY );
        AuvMath::Swap( fMin, fNan );
        TS_ASSERT_EQUALS( fNan, INFINITY );
        TS_ASSERT_DIFFERS( fMin, fMin );

        // double
        double dMin = -INFINITY, dMax = INFINITY, dNan = nan( "" );
        AuvMath::Swap( dMin, dMax );
        TS_ASSERT_EQUALS( dMin, INFINITY );
        TS_ASSERT_EQUALS( dMax, -INFINITY );
        AuvMath::Swap( dMin, dNan );
        TS_ASSERT_EQUALS( dNan, INFINITY );
        TS_ASSERT_DIFFERS( dMin, dMin );
    }

    /// AuvMath::ModPi %Unit Tests
    void testModPi( void )
    {
        // float
        float fN721 = D2R( -721 ), fN360 = D2R( -360 ), fN181 = D2R( -181 ), fN179 = D2R( -179 ), fN1 = D2R( -1 );
        float f0 = 0, fNan = nanf( "" ), fDelta = 1e-6, fRes;
        float f1 = D2R( 1 ), f179 = D2R( 179 ), f181 = D2R( 181 ), f360 = D2R( 360 ), f721 = D2R( 721 );
        TS_ASSERT_DELTA( AuvMath::ModPi( fN721 ), fN1, fDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( fN360 ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( fN181 ), f179, fDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( fN179 ), fN179, fDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( f0 ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( f179 ), f179, fDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( f181 ), fN179, fDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( f360 ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( f721 ), f1, fDelta );
        fRes = AuvMath::ModPi( fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );
        // double
        double dN721 = D2R( -721 ), dN360 = D2R( -360 ), dN181 = D2R( -181 ), dN179 = D2R( -179 ), dN1 = D2R( -1 );
        double d0 = 0, dNan = nanf( "" ), dDelta = 1e-6, dRes;
        double d1 = D2R( 1 ), d179 = D2R( 179 ), d181 = D2R( 181 ), d360 = D2R( 360 ), d721 = D2R( 721 );
        TS_ASSERT_DELTA( AuvMath::ModPi( dN721 ), dN1, dDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( dN360 ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( dN181 ), d179, dDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( dN179 ), dN179, dDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( d0 ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( d179 ), d179, dDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( d181 ), dN179, dDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( d360 ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::ModPi( d721 ), d1, dDelta );
        dRes = AuvMath::ModPi( dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// AuvMath::NormalizeAngle %Unit Tests
    void testNormalizeAngle( void )
    {
        // float
        float fN721 = D2R( -721 ), fN360 = D2R( -360 ), fN361 = D2R( -361 ), fN359 = D2R( -359 ), fN181 = D2R( -181 ), fN179 = D2R( -179 ), fN1 = D2R( -1 );
        float f0 = 0, fNan = nanf( "" ), fDelta = 1e-6, fRes;
        float f721 = D2R( 721 ), f360 = D2R( 360 ), f361 = D2R( 361 ), f359 = D2R( 359 ), f179 = D2R( 179 ), f181 = D2R( 181 ), f1 = D2R( 1 );

        // 0 deg to 360 deg
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( fN721 ), f359, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( fN360 ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( fN361 ), f359, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( fN359 ), f1, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f0 ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f359 ), f359, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f361 ), f1, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f360 ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f721 ), f1, fDelta );
        fRes = AuvMath::NormalizeAngle( fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );

        // -180 deg to 180 deg
        float fLimitLow = -M_PI, fLmitHi = M_PI;
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( fN721, fLimitLow, fLmitHi ), fN1, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( fN360, fLimitLow, fLmitHi ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( fN181, fLimitLow, fLmitHi ), f179, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( fN179, fLimitLow, fLmitHi ), fN179, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f0, fLimitLow, fLmitHi ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f179, fLimitLow, fLmitHi ), f179, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f181, fLimitLow, fLmitHi ), fN179, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f360, fLimitLow, fLmitHi ), f0, fDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( f721, fLimitLow, fLmitHi ), f1, fDelta );
        fRes = AuvMath::NormalizeAngle( fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );

        // double
        double dN721 = D2R( -721 ), dN360 = D2R( -360 ), dN361 = D2R( -361 ), dN359 = D2R( -359 ), dN181 = D2R( -181 ), dN179 = D2R( -179 ), dN1 = D2R( -1 );
        double d0 = 0, dNan = nanf( "" ), dDelta = 1e-6, dRes;
        double d721 = D2R( 721 ), d360 = D2R( 360 ), d361 = D2R( 361 ), d359 = D2R( 359 ), d179 = D2R( 179 ), d181 = D2R( 181 ), d1 = D2R( 1 );

        // 0 deg to 360 deg
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( dN721 ), d359, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( dN360 ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( dN361 ), d359, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( dN359 ), d1, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d0 ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d359 ), d359, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d361 ), d1, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d360 ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d721 ), d1, dDelta );
        dRes = AuvMath::NormalizeAngle( dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );

        // -180 deg to 180 deg
        double dLimitLow = -M_PI, dLmitHi = M_PI;
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( dN721, dLimitLow, dLmitHi ), dN1, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( dN360, dLimitLow, dLmitHi ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( dN181, dLimitLow, dLmitHi ), d179, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( dN179, dLimitLow, dLmitHi ), dN179, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d0, dLimitLow, dLmitHi ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d179, dLimitLow, dLmitHi ), d179, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d181, dLimitLow, dLmitHi ), dN179, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d360, dLimitLow, dLmitHi ), d0, dDelta );
        TS_ASSERT_DELTA( AuvMath::NormalizeAngle( d721, dLimitLow, dLmitHi ), d1, dDelta );
        dRes = AuvMath::NormalizeAngle( dNan, dLimitLow, dLmitHi );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// AuvMath::NanZero %Unit Tests
    void testNanZero( void )
    {
        // float
        float fMin = -INFINITY, fMid = 0, fMax = INFINITY, fNan = nanf( "" );
        TS_ASSERT_EQUALS( AuvMath::NanZero( fMin ), fMin );
        TS_ASSERT_EQUALS( AuvMath::NanZero( fMid ), fMid );
        TS_ASSERT_EQUALS( AuvMath::NanZero( fMax ), fMax );
        TS_ASSERT_EQUALS( AuvMath::NanZero( fNan ), 0 );
        // double
        double dMin = -INFINITY, dMid = 0, dMax = INFINITY, dNan = nan( "" );
        TS_ASSERT_EQUALS( AuvMath::NanZero( dMin ), dMin );
        TS_ASSERT_EQUALS( AuvMath::NanZero( dMid ), dMid );
        TS_ASSERT_EQUALS( AuvMath::NanZero( dMax ), dMax );
        TS_ASSERT_EQUALS( AuvMath::NanZero( dNan ), 0 );
    }

    /// AuvMath::Round %Unit Tests
    void testRound( void )
    {
        // float
        float fMin = -128, fMid = 0, fMax = 128, fNan = nanf( "" ), fDiv = 3.5, fRes;
        TS_ASSERT_EQUALS( AuvMath::Round( fMin, fDiv ), -129.5 );
        TS_ASSERT_EQUALS( AuvMath::Round( fMid, fDiv ), 0 );
        TS_ASSERT_EQUALS( AuvMath::Round( fMax, fDiv ), 129.5 );
        fRes = AuvMath::Round( fMin, fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Round( fNan, fDiv );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Round( fDiv, fMid );
        TS_ASSERT_DIFFERS( fRes, fRes );
        // double
        double dMin = -128, dMid = 0, dMax = 128, dNan = nanf( "" ), dDiv = 3.5, dRes;
        TS_ASSERT_EQUALS( AuvMath::Round( dMin, dDiv ), -129.5 );
        TS_ASSERT_EQUALS( AuvMath::Round( dMid, dDiv ), 0 );
        TS_ASSERT_EQUALS( AuvMath::Round( dMax, dDiv ), 129.5 );
        dRes = AuvMath::Round( dMin, dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Round( dNan, dDiv );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Round( dDiv, dMid );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }


/// AuvMath::Sign %Unit Tests
    void testSign( void )
    {
        // char
        signed char cMin = -128, cMid = 0, cMax = 127;
        TS_ASSERT_EQUALS( AuvMath::Sign( cMin ), -1 );
        TS_ASSERT_EQUALS( AuvMath::Sign( cMid ), 0 );
        TS_ASSERT_EQUALS( AuvMath::Sign( cMax ), 1 );
        // int
        int iMin = -2147483647, iMid = 0, iMax = 2147483647;
        TS_ASSERT_EQUALS( AuvMath::Sign( iMin ), -1 );
        TS_ASSERT_EQUALS( AuvMath::Sign( iMid ), 0 );
        TS_ASSERT_EQUALS( AuvMath::Sign( iMax ), 1 );
        // unsigned int
        // float
        float fMin = -INFINITY, fMid = 0, fMax = INFINITY, fNan = nanf( "" ), fRes;
        TS_ASSERT_EQUALS( AuvMath::Sign( fMin ), -1 );
        TS_ASSERT_EQUALS( AuvMath::Sign( fMid ), 0 );
        TS_ASSERT_EQUALS( AuvMath::Sign( fMax ), 1 );
        fRes = AuvMath::Sign( fNan );
        TS_ASSERT_DIFFERS( fRes, fRes );
        // double
        double dMin = -INFINITY, dMid = 0, dMax = INFINITY, dNan = nan( "" ), dRes;
        TS_ASSERT_EQUALS( AuvMath::Sign( dMin ), -1 );
        TS_ASSERT_EQUALS( AuvMath::Sign( dMid ), 0 );
        TS_ASSERT_EQUALS( AuvMath::Sign( dMax ), 1 );
        dRes = AuvMath::Sign( dNan );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// FindLtEqIndex %Unit Tests
    void testFindLtEqIndex( void )
    {
        // float
        float foo[] = {1, 2, 3.14159f, 4, 5, 5.12345678f, 6};
        // Out of bounds checks
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 0.0f, 0, 6 ), -1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 1.0f, 1, 6 ), -1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 7.0f, 0, 6 ), -1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 6.0f, 0, 5 ), -1 );
        // Lookup checks
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 1.0f, 0, 6 ), 0 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 1.1f, 0, 6 ), 0 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 2.0f, 0, 6 ), 1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 3.1415f, 0, 6 ), 1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 3.14159f, 0, 6 ), 2 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 3.141592f, 0, 6 ), 2 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 5.2f, 0, 6 ), 5 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( foo, 6.0f, 0, 6 ), 6 );

        // double
        double doo[] = {1, 2, 3.14159, 4, 5, 5.12345678, 6};
        // Out of bounds checks
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 0.0, 0, 6 ), -1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 1.0, 1, 6 ), -1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 7.0, 0, 6 ), -1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 6.0, 0, 5 ), -1 );
        // Lookup checks
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 1.0, 0, 6 ), 0 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 1.1, 0, 6 ), 0 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 2.0, 0, 6 ), 1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 3.1415, 0, 6 ), 1 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 3.14159, 0, 6 ), 2 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 3.141592, 0, 6 ), 2 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 5.2, 0, 6 ), 5 );
        TS_ASSERT_EQUALS( AuvMath::FindLtEqIndex( doo, 6.0, 0, 6 ), 6 );

    }

    /// AuvMath::Interpolate1D %Unit Tests
    void testInterpolate1D( void )
    {
        // float
        float foo[] = {1.0, 5.0}, fRes;
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 1.00f, foo[ 0 ], foo[ 1 ], 1.0f, 2.0f ), 1.0f );
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 1.25f, foo[ 0 ], foo[ 1 ], 1.0f, 2.0f ), 2.0f );
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 1.50f, foo[ 0 ], foo[ 1 ], 1.0f, 2.0f ), 3.0f );
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 1.75f, foo[ 0 ], foo[ 1 ], 1.0f, 2.0f ), 4.0f );
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 2.00f, foo[ 0 ], foo[ 1 ], 1.0f, 2.0f ), 5.0f );
        fRes = AuvMath::Interpolate1D( 2.00f, foo[ 0 ], foo[ 1 ], 1.0f, 1.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );

        // double
        double doo[] = {1.0, 5.0}, dRes;
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 1.00, doo[ 0 ], doo[ 1 ], 1.0, 2.0 ), 1.0 );
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 1.25, doo[ 0 ], doo[ 1 ], 1.0, 2.0 ), 2.0 );
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 1.50, doo[ 0 ], doo[ 1 ], 1.0, 2.0 ), 3.0 );
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 1.75, doo[ 0 ], doo[ 1 ], 1.0, 2.0 ), 4.0 );
        TS_ASSERT_EQUALS( AuvMath::Interpolate1D( 2.00, doo[ 0 ], doo[ 1 ], 1.0, 2.0 ), 5.0 );
        dRes = AuvMath::Interpolate1D( 2.00, doo[ 0 ], doo[ 1 ], 1.0, 1.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// AuvMath::Interpolate2D %Unit Tests
    void testInterpolate2D( void )
    {
        // float
        float foo[ 2 ][ 2 ] = {{1.0, 5.0}, {3.0, 7.0}}, fRes;
        TS_ASSERT_EQUALS( AuvMath::Interpolate2D( 1.5f, 3.5f, foo, 1.0f, 2.0f, 3.0f, 4.0f ), 4.0f );
        fRes = AuvMath::Interpolate2D( 1.5f, 3.5f, foo, 1.0f, 1.0f, 3.0f, 4.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Interpolate2D( 1.5f, 3.5f, foo, 1.0f, 2.0f, 3.0f, 3.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );

        float moo[ 2 ][ 2 ] = { { 20.6948, 9.32573 }, { 36.8355, 62.5137 } };
        TS_ASSERT_DELTA( AuvMath::Interpolate2D( 36.8f, -121.8f, moo, 36.7967f, 36.8067f, -121.8054f, -121.7954f ), 26.5f, 1.0f );

        // double
        double doo[ 2 ][ 2 ] = {{1.0, 5.0}, {3.0, 7.0}}, dRes;
        TS_ASSERT_EQUALS( AuvMath::Interpolate2D( 1.5, 3.5, doo, 1.0, 2.0, 3.0, 4.0 ), 4.0 );
        dRes = AuvMath::Interpolate2D( 1.5, 3.5, doo, 1.0, 1.0, 3.0, 4.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Interpolate2D( 1.5, 3.5, doo, 1.0, 2.0, 3.0, 3.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// AuvMath::Interpolate3D %Unit Tests
    void testInterpolate3D( void )
    {
        // float
        float foo[ 2 ][ 2 ][ 2 ] = {{{1.0, 5.0}, {3.0, 7.0}}, {{5.0, 9.0}, {7.0, 11.0}}}, fRes;
        TS_ASSERT_EQUALS( AuvMath::Interpolate3D( 1.5f, 3.5f, 5.5f, foo, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f ), 6.0f );
        fRes = AuvMath::Interpolate3D( 1.5f, 3.5f, 5.5f, foo, 1.0f, 1.0f, 3.0f, 4.0f, 5.0f, 6.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Interpolate3D( 1.5f, 3.5f, 5.5f, foo, 1.0f, 2.0f, 3.0f, 3.0f, 5.0f, 6.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Interpolate3D( 1.5f, 3.5f, 5.5f, foo, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 5.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );

        // double
        double doo[ 2 ][ 2 ][ 2 ] = {{{1.0, 5.0}, {3.0, 7.0}}, {{5.0, 9.0}, {7.0, 11.0}}}, dRes;
        TS_ASSERT_EQUALS( AuvMath::Interpolate3D( 1.5, 3.5, 5.5, doo, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 ), 6.0 );
        dRes = AuvMath::Interpolate3D( 1.5, 3.5, 5.5, doo, 1.0, 1.0, 3.0, 4.0, 5.0, 6.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Interpolate3D( 1.5, 3.5, 5.5, doo, 1.0, 2.0, 3.0, 3.0, 5.0, 6.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Interpolate3D( 1.5, 3.5, 5.5, doo, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    /// AuvMath::Interpolate4D %Unit Tests
    void testInterpolate4D( void )
    {
        // float
        float foo[ 2 ][ 2 ][ 2 ][ 2 ] = {{{{1.0, 5.0}, {3.0, 7.0}}, {{5.0, 9.0}, {7.0, 11.0}}}, {{{11.0, 15.0}, {13.0, 17.0}}, {{15.0, 19.0}, {17.0, 21.0}}}}, fRes;
        TS_ASSERT_EQUALS( AuvMath::Interpolate4D( 1.5f, 3.5f, 5.5f, 7.5f, foo, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f ), 11.0f );
        fRes = AuvMath::Interpolate4D( 1.5f, 3.5f, 5.5f, 7.5f, foo, 1.0f, 1.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Interpolate4D( 1.5f, 3.5f, 5.5f, 7.5f, foo, 1.0f, 2.0f, 3.0f, 3.0f, 5.0f, 6.0f, 7.0f, 8.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Interpolate4D( 1.5f, 3.5f, 5.5f, 7.5f, foo, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 5.0f, 7.0f, 8.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );
        fRes = AuvMath::Interpolate4D( 1.5f, 3.5f, 5.5f, 7.5f, foo, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 7.0f );
        TS_ASSERT_DIFFERS( fRes, fRes );

        // double
        double doo[ 2 ][ 2 ][ 2 ][ 2 ] = {{{{1.0, 5.0}, {3.0, 7.0}}, {{5.0, 9.0}, {7.0, 11.0}}}, {{{11.0, 15.0}, {13.0, 17.0}}, {{15.0, 19.0}, {17.0, 21.0}}}}, dRes;
        TS_ASSERT_EQUALS( AuvMath::Interpolate4D( 1.5, 3.5, 5.5, 7.5, doo, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 ), 11.0 );
        dRes = AuvMath::Interpolate4D( 1.5, 3.5, 5.5, 7.5, doo, 1.0, 1.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Interpolate4D( 1.5, 3.5, 5.5, 7.5, doo, 1.0, 2.0, 3.0, 3.0, 5.0, 6.0, 7.0, 8.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Interpolate4D( 1.5, 3.5, 5.5, 7.5, doo, 1.0, 2.0, 3.0, 4.0, 5.0, 5.0, 7.0, 8.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
        dRes = AuvMath::Interpolate4D( 1.5, 3.5, 5.5, 7.5, doo, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 7.0 );
        TS_ASSERT_DIFFERS( dRes, dRes );
    }

    // AuvMath::BulkModulus %Unit Tests
    void testBulkModulus( void )
    {
        TS_ASSERT_DELTA( AuvMath::BulkModulus( 35, 283.15, 4e7 ), 2404604869.0, 1.0 )
        TS_ASSERT_DELTA( AuvMath::BulkModulus( 35, 298.15, 1e8 ), 2710894504.0, 1.0 );
    }

    // AuvMath::Density %Unit Tests
    void testDensity( void )
    {
        TS_ASSERT_DELTA( AuvMath::Density( 34.567, 278.15, 2e7 ), 1036.409, 0.001 );
        TS_ASSERT_DELTA( AuvMath::Density( 35, 298.15, 1e8 ), 1062.53817, 0.00001 );
    }

    // AuvMath::OceanDepth %Unit Tests
    void testOceanDepth( void )
    {
        TS_ASSERT_DELTA( AuvMath::OceanDepth( 5e7, 0.628318531 ), 4906.08, 0.01 );
        TS_ASSERT_DELTA( AuvMath::OceanDepth( 1e8, 1.570796327 ), 9674.23, 0.01 );
        TS_ASSERT_DELTA( AuvMath::OceanDepth( 17e4, 0 ), 17, 0.1 );
    }

    // AuvMath::OceanPressure %Unit Tests
    void testOceanPressure( void )
    {
        TS_ASSERT_DELTA( AuvMath::OceanPressure( 4906.08, 0.628318531 ), 5e7, 4.1e4 );
        TS_ASSERT_DELTA( AuvMath::OceanPressure( 9674.23, 1.570796327 ), 1e8, 7.2e4 );
    }

    // AuvMath::HillRatioAtSP2 %Unit Tests
    void testHillRatioAtSP2( void )
    {
        TS_ASSERT_DELTA( AuvMath::HillRatioAtSP2( 10.0 ), 0.999959, 1e-6 );
        TS_ASSERT_DELTA( AuvMath::HillRatioAtSP2( 2.5 ), 0.999871, 1e-6 );
    }

    // AuvMath::PracticalSalinity %Unit Tests
    void testPracticalSalinity( void )
    {
        TS_ASSERT_DELTA( AuvMath::PracticalSalinity( 22.0, 2.5, 10.0 ), 23.8149, 1e-4 );
        TS_ASSERT_DELTA( AuvMath::PracticalSalinity( 39.9516, 9.4867, 1174.49 ), 36.8879, 1e-4 );
        TS_ASSERT_DELTA( AuvMath::PracticalSalinity( 3.5, 25.0, 0.0 ), 1.83477, 1e-4 );
    }

    // AuvMath::SoundSpeed %Unit Tests
    void testSoundSpeed( void )
    {
        TS_ASSERT_DELTA( AuvMath::SoundSpeed( 35, 10, 100 ), 1491.48, 0.01 );
        TS_ASSERT_DELTA( AuvMath::SoundSpeed( 35, 40, 200 ), 1566.62, 0.01 );
    }

    // AuvMath::Oxsol %Unit Test
    void testOxsol( void )
    {
        double dDelta = 0.01;

        // Data stubs obtained from SBE APPLICATION NOTE NO. 64, Appendix A, 8 pp.
        double t[] = { -2, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32 };
        double sal[] = { 0, 5, 10, 15, 20, 25, 30, 32, 35 };

        double OxSolGroundTruth[18][9] =
        {
            { 10.84, 10.46, 10.10, 9.74, 9.40, 9.07, 8.75, 8.63, 8.45 },
            { 10.23, 9.88, 9.54, 9.21, 8.90, 8.59, 8.30, 8.18, 8.01 },
            { 9.68, 9.35, 9.04, 8.73, 8.44, 8.15, 7.88, 7.77, 7.61 },
            { 9.17, 8.87, 8.58, 8.29, 8.02, 7.75, 7.49, 7.39, 7.24 },
            { 8.71, 8.43, 8.15, 7.89, 7.63, 7.38, 7.14, 7.05, 6.91 },
            { 8.29, 8.02, 7.77, 7.52, 7.28, 7.04, 6.82, 6.73, 6.60 },
            { 7.90, 7.65, 7.41, 7.18, 6.95, 6.73, 6.52, 6.44, 6.31 },
            { 7.54, 7.31, 7.08, 6.86, 6.65, 6.45, 6.25, 6.17, 6.05 },
            { 7.21, 6.99, 6.78, 6.57, 6.37, 6.18, 5.99, 5.92, 5.81 },
            { 6.91, 6.70, 6.50, 6.31, 6.12, 5.93, 5.75, 5.68, 5.58 },
            { 6.62, 6.43, 6.24, 6.06, 5.88, 5.70, 5.53, 5.47, 5.37 },
            { 6.36, 6.18, 6.00, 5.82, 5.65, 5.49, 5.33, 5.27, 5.17 },
            { 6.12, 5.94, 5.77, 5.61, 5.45, 5.29, 5.14, 5.08, 4.99 },
            { 5.89, 5.72, 5.56, 5.41, 5.25, 5.10, 4.96, 4.90, 4.82 },
            { 5.68, 5.52, 5.37, 5.22, 5.07, 4.93, 4.79, 4.74, 4.66 },
            { 5.48, 5.33, 5.18, 5.04, 4.90, 4.77, 4.63, 4.58, 4.51 },
            { 5.29, 5.15, 5.01, 4.87, 4.74, 4.61, 4.49, 4.44, 4.36 },
            { 5.11, 4.98, 4.84, 4.71, 4.59, 4.46, 4.34, 4.30, 4.23 }
        };

        for( unsigned int i = 0; i < sizeof( t ) / sizeof( t[0] ); i++ )
        {
            for( unsigned int j = 0; j < sizeof( sal ) / sizeof( sal[0] ); j++ )
            {
                TS_ASSERT_DELTA( AuvMath::Oxsol( t[i], sal[j] ), OxSolGroundTruth[i][j], dDelta );
            }
        }
    }

    // AuvMath::ShellSort
    void testShellSort( void )
    {
        double array1[]    = {5, 4, 3, 2, 1};
        double sarray1[]   = {1, 2, 3, 4, 5};
        int array1Len    = sizeof( array1 ) / sizeof( array1[0] );

        AuvMath::ShellSort( array1, array1Len );
        TS_ASSERT_SAME_DATA( array1, sarray1, array1Len );

        //int i;
        //for( i=0; i< array1Len; i++ ) printf("array1[%d] = %ld\n",i, array1[i]);

        double array2[]   = {1576130,
                             9705927,
                             9571669,
                             4853756,
                             8002804,
                             1418863,
                             4217612,
                             9157355,
                             7922073,
                             9594924
                            };

        double sarray2[]  = { 1418863,
                              1576130,
                              4217612,
                              4853756,
                              7922073,
                              8002804,
                              9157355,
                              9571669,
                              9594924,
                              9705927
                            };
        int array2Len   = sizeof( array2 ) / sizeof( array2[0] );

        AuvMath::ShellSort( array2, array2Len );
        TS_ASSERT_SAME_DATA( array2, sarray2, array2Len );

        //for( i=0; i< array2Len; i++ ) printf("array2[%d] = %ld\n",i, array2[i]);

        double array3[]    = {5, -4, 3, -2, 1};
        double sarray3[]   = { -4, -2, 1, 3, 5};
        int array3Len    = sizeof( array3 ) / sizeof( array3[0] );

        AuvMath::ShellSort( array3, array3Len );
        TS_ASSERT_SAME_DATA( array3, sarray3, array3Len );
    }
};

#endif // _AUVMATH_TEST_H
