danghungithp's picture
Upload 1398 files
bec48e1 verified
/* TA-LIB Copyright (c) 1999-2007, Mario Fortier
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* - Neither name of author nor the names of its contributors
* may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* List of contributors:
*
* Initial Name/description
* -------------------------------------------------------------------
* MF Mario Fortier
*
*
* Change history:
*
* MMDDYY BY Description
* -------------------------------------------------------------------
* 112400 MF First version.
*
*/
/* Description:
* Provide utility function internally used in ta_regtest only.
*/
/**** Headers ****/
#ifdef WIN32
#include "windows.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "ta_test_priv.h"
#include "ta_utility.h"
#include "ta_memory.h"
/**** External functions declarations. ****/
/* None */
/**** External variables declarations. ****/
extern int nbProfiledCall;
extern double timeInProfiledCall;
extern double worstProfiledCall;
extern int insufficientClockPrecision;
/**** Global variables definitions. ****/
/* Global temporary buffers used while testing. */
#define RESV_PATTERN_MEMGUARD_1 (2.4789205E-150)
#define RESV_PATTERN_MEMGUARD_2 (4.2302468E-165)
#define RESV_PATTERN_PREFIX (9.1349043E-200)
#define RESV_PATTERN_SUFFIX (8.1489031E-158)
#define RESV_PATTERN_IMPROBABLE (-2.849284E-199)
#define RESV_PATTERN_PREFIX_INT (TA_INTEGER_DEFAULT)
#define RESV_PATTERN_SUFFIX_INT (TA_INTEGER_DEFAULT)
#define RESV_PATTERN_IMPROBABLE_INT (TA_INTEGER_DEFAULT)
#define TA_BUF_PREFIX 100
#define TA_BUF_SUFFIX 100
#define TA_BUF_SIZE (TA_BUF_PREFIX+MAX_NB_TEST_ELEMENT+TA_BUF_SUFFIX)
#define TA_NB_OUT 3
#define TA_NB_IN 1
#define TA_NB_OUT_IN (TA_NB_OUT+TA_NB_IN)
TA_Real memoryGuard1 = RESV_PATTERN_MEMGUARD_1; /* Magic number to detect problem. */
TA_Real buf[NB_GLOBAL_BUFFER][TA_NB_OUT_IN][TA_BUF_SIZE]; /* The global buffers. */
TA_Real memoryGuard2 = RESV_PATTERN_MEMGUARD_2; /* Magic number to detect problem. */
#define NB_TOTAL_ELEMENTS (sizeof(buf)/sizeof(TA_Real))
TestBuffer gBuffer[5]; /* See initGlobalBuffer. */
/**** Local declarations. ****/
/* None */
/**** Local functions declarations. ****/
static ErrorNumber doRangeTestFixSize( RangeTestFunction testFunction,
void *opaqueData,
TA_Integer refOutBeg,
TA_Integer refOutNbElement,
TA_Integer refLookback,
const TA_Real *refBuffer,
const TA_Integer *refBufferInt,
TA_FuncUnstId unstId,
TA_Integer fixSize,
unsigned int outputNb,
unsigned int integerTolerance );
static int dataWithinReasonableRange( TA_Real val1, TA_Real val2,
unsigned int outputPosition,
TA_FuncUnstId unstId,
unsigned int integerTolerance );
static ErrorNumber doRangeTestForOneOutput( RangeTestFunction testFunction,
TA_FuncUnstId unstId,
void *opaqueData,
unsigned int outputNb,
unsigned int integerTolerance );
static TA_RetCode CallTestFunction( RangeTestFunction testFunction,
TA_Integer startIdx,
TA_Integer endIdx,
TA_Real *outputBuffer,
TA_Integer *outputBufferInt,
TA_Integer *outBegIdx,
TA_Integer *outNbElement,
TA_Integer *lookback,
void *opaqueData,
unsigned int outputNb,
unsigned int *isOutputInteger );
/**** Local variables definitions. ****/
/* None */
/**** Global functions definitions. ****/
static int ta_g_val = 0;
static const char *ta_g_wheel = "-\\|/";
void showFeedback()
{
if( ta_g_wheel[ta_g_val] == '\0' )
ta_g_val = 0;
putchar('\b');
putchar(ta_g_wheel[ta_g_val]);
fflush(stdout);
ta_g_val++;
}
void hideFeedback()
{
putchar('\b');
fflush(stdout);
ta_g_val = 0;
}
ErrorNumber allocLib()
{
TA_RetCode retCode;
/* Initialize the library. */
retCode = TA_Initialize();
if( retCode != TA_SUCCESS )
{
printf( "TA_Initialize failed [%d]\n", retCode );
return TA_TESTUTIL_INIT_FAILED;
}
return TA_TEST_PASS;
}
ErrorNumber freeLib()
{
TA_RetCode retCode;
/* For testing purpose */
/* TA_FATAL_RET( "Test again", 100, 200, 0 ); */
retCode = TA_Shutdown();
if( retCode != TA_SUCCESS )
{
printf( "TA_Shutdown failed [%d]\n", retCode );
return TA_TESTUTIL_SHUTDOWN_FAILED;
}
return TA_TEST_PASS;
}
void reportError( const char *str, TA_RetCode retCode )
{
TA_RetCodeInfo retCodeInfo;
TA_SetRetCodeInfo( retCode, &retCodeInfo );
printf( "%s,%d==%s\n", str, retCode, retCodeInfo.enumStr );
printf( "[%s]\n", retCodeInfo.infoStr );
}
/* Need to be called only once. */
void initGlobalBuffer( void )
{
gBuffer[0].in = &buf[0][0][TA_BUF_PREFIX];
gBuffer[0].out0 = &buf[0][1][TA_BUF_PREFIX];
gBuffer[0].out1 = &buf[0][2][TA_BUF_PREFIX];
gBuffer[0].out2 = &buf[0][3][TA_BUF_PREFIX];
gBuffer[1].in = &buf[1][0][TA_BUF_PREFIX];
gBuffer[1].out0 = &buf[1][1][TA_BUF_PREFIX];
gBuffer[1].out1 = &buf[1][2][TA_BUF_PREFIX];
gBuffer[1].out2 = &buf[1][3][TA_BUF_PREFIX];
gBuffer[2].in = &buf[2][0][TA_BUF_PREFIX];
gBuffer[2].out0 = &buf[2][1][TA_BUF_PREFIX];
gBuffer[2].out1 = &buf[2][2][TA_BUF_PREFIX];
gBuffer[2].out2 = &buf[2][3][TA_BUF_PREFIX];
gBuffer[3].in = &buf[3][0][TA_BUF_PREFIX];
gBuffer[3].out0 = &buf[3][1][TA_BUF_PREFIX];
gBuffer[3].out1 = &buf[3][2][TA_BUF_PREFIX];
gBuffer[3].out2 = &buf[3][3][TA_BUF_PREFIX];
gBuffer[4].in = &buf[4][0][TA_BUF_PREFIX];
gBuffer[4].out0 = &buf[4][1][TA_BUF_PREFIX];
gBuffer[4].out1 = &buf[4][2][TA_BUF_PREFIX];
gBuffer[4].out2 = &buf[4][3][TA_BUF_PREFIX];
}
/* Will set some values in the buffers allowing
* to detect later if the function is writing
* out-of-bound (and to make sure the
* function is writing exactly the number
* of values it pretends to do).
*/
void clearAllBuffers( void )
{
unsigned int i,j,k;
for( i=0; i < NB_GLOBAL_BUFFER; i++ )
{
for( j=0; j < TA_NB_OUT_IN; j++ )
{
for( k=0; k < TA_BUF_PREFIX; k++ )
buf[i][j][k] = RESV_PATTERN_PREFIX;
for( ; k < TA_BUF_SIZE; k++ )
buf[i][j][k] = RESV_PATTERN_SUFFIX;
}
}
}
void setInputBuffer( unsigned int i, const TA_Real *data, unsigned int nbElement )
{
unsigned int j;
for( j=0; j < nbElement; j++ )
buf[i][0][j+TA_BUF_PREFIX] = data[j];
}
void setInputBufferValue( unsigned int i, const TA_Real data, unsigned int nbElement )
{
unsigned int j;
for( j=0; j < nbElement; j++ )
buf[i][0][j+TA_BUF_PREFIX] = data;
}
/* Check that a buffer (within a TestBuffer) is not containing
* NAN (or any reserved "impossible" value) within the specified
* range (it also checks that all out-of-bound values are untouch).
*
* Return 1 on success.
*/
ErrorNumber checkForNAN( const TA_Real *buffer,
unsigned int nbElement )
{
unsigned int i;
unsigned int idx;
const TA_Real *theBuffer;
theBuffer = buffer - TA_BUF_PREFIX;
/* Check that the prefix are all still untouch. */
for( idx=0; idx < TA_BUF_PREFIX; idx++ )
{
if( theBuffer[idx] != RESV_PATTERN_PREFIX )
{
printf( "Fail: Out of range writing in prefix buffer (%d,%f)\n", idx, theBuffer[idx] );
return TA_TEST_TFRR_OVERLAP_OR_NAN_0;
}
}
if( nbElement > MAX_NB_TEST_ELEMENT )
{
printf( "Fail: outNbElement is out of range 0 (%d)\n", nbElement );
return TA_TEST_TFRR_NB_ELEMENT_OUT_OF_RANGE;
}
/* Check that no NAN (or reserved "impossible" value) exist
* in the specified range.
*/
for( i=0; i < nbElement; i++,idx++ )
{
/* TODO Add back some nan/inf checking
if( trio_isnan(theBuffer[idx]) )
{
printf( "Fail: Not a number find within the data (%d,%f)\n", i, theBuffer[idx] );
return TA_TEST_TFRR_OVERLAP_OR_NAN_1;
}
if( trio_isinf(theBuffer[idx]) )
{
printf( "Fail: Not a number find within the data (%d,%f)\n", i, theBuffer[idx] );
return TA_TEST_TFRR_OVERLAP_OR_NAN_2;
}*/
if( theBuffer[idx] == RESV_PATTERN_PREFIX )
{
printf( "Fail: Not a number find within the data (%d,%f)\n", i, theBuffer[idx] );
return TA_TEST_TFRR_OVERLAP_OR_NAN_3;
}
if( theBuffer[idx] == RESV_PATTERN_SUFFIX )
{
printf( "Fail: Not a number find within the data (%d,%f)\n", i, theBuffer[idx] );
return TA_TEST_TFRR_OVERLAP_OR_NAN_4;
}
}
/* Make sure that the remaining of the buffer is untouch. */
for( ; idx < TA_BUF_SIZE; idx++ )
{
if( theBuffer[idx] != RESV_PATTERN_SUFFIX )
{
printf( "Fail: Out of range writing in suffix buffer (%d,%f)\n", idx, theBuffer[idx] );
return TA_TEST_TFRR_OVERLAP_OR_NAN_5;
}
idx++;
}
/* Make sure the global memory guard are untouch. */
if( memoryGuard1 != RESV_PATTERN_MEMGUARD_1 )
{
printf( "Fail: MemoryGuard1 have been modified (%f,%f)\n", memoryGuard1, RESV_PATTERN_MEMGUARD_1 );
return TA_TEST_TFRR_OVERLAP_OR_NAN_6;
}
if( memoryGuard2 != RESV_PATTERN_MEMGUARD_2 )
{
printf( "Fail: MemoryGuard2 have been modified (%f,%f)\n", memoryGuard2, RESV_PATTERN_MEMGUARD_2 );
return TA_TEST_TFRR_OVERLAP_OR_NAN_7;
}
/* Everything looks good! */
return TA_TEST_PASS;
}
/* Return 1 on success */
ErrorNumber checkSameContent( TA_Real *buffer1,
TA_Real *buffer2 )
{
const TA_Real *theBuffer1;
const TA_Real *theBuffer2;
unsigned int i;
theBuffer1 = buffer1 - TA_BUF_PREFIX;
theBuffer2 = buffer2 - TA_BUF_PREFIX;
for( i=0; i < TA_BUF_SIZE; i++ )
{
/* TODO Add back nan/inf checking
(!trio_isnan(theBuffer1[i])) &&
(!trio_isinf(theBuffer1[i])) &&
*/
if( (theBuffer1[i] != RESV_PATTERN_SUFFIX) &&
(theBuffer1[i] != RESV_PATTERN_PREFIX) )
{
if(!TA_REAL_EQ( theBuffer1[i], theBuffer2[i], 0.000001))
{
printf( "Fail: Large difference found between two value expected identical (%f,%f,%d)\n",
theBuffer1[i], theBuffer2[i], i );
return TA_TEST_TFRR_CHECK_SAME_CONTENT;
}
}
}
return TA_TEST_PASS;
}
ErrorNumber checkDataSame( const TA_Real *data,
const TA_Real *originalInput,
unsigned int nbElement )
{
unsigned int i;
ErrorNumber errNb;
errNb = checkForNAN( data, nbElement );
if( errNb != TA_TEST_PASS )
return errNb;
if( nbElement > MAX_NB_TEST_ELEMENT )
{
printf( "Fail: outNbElement is out of range 1 (%d)\n", nbElement );
return TA_TEST_TFRR_NB_ELEMENT_OUT_OF_RANGE;
}
for( i=0; i < nbElement; i++ )
{
if( originalInput[i] != data[i] )
{
printf( "Fail: Data was wrongly modified (%f,%f,%d)\n",
originalInput[i],
data[i], i );
return TA_TEST_TFRR_INPUT_HAS_BEEN_MODIFIED;
}
}
return TA_TEST_PASS;
}
ErrorNumber checkExpectedValue( const TA_Real *data,
TA_RetCode retCode, TA_RetCode expectedRetCode,
unsigned int outBegIdx, unsigned int expectedBegIdx,
unsigned int outNbElement, unsigned int expectedNbElement,
TA_Real oneOfTheExpectedOutReal,
unsigned int oneOfTheExpectedOutRealIndex )
{
if( retCode != expectedRetCode )
{
printf( "Fail: RetCode %d different than expected %d\n", retCode, expectedRetCode );
return TA_TESTUTIL_TFRR_BAD_RETCODE;
}
if( retCode != TA_SUCCESS )
{
/* An error did occured, but it
* was expected. No need to go
* further.
*/
return TA_TEST_PASS;
}
if( outNbElement > MAX_NB_TEST_ELEMENT )
{
printf( "Fail: outNbElement is out of range 2 (%d)\n", outNbElement );
return TA_TEST_TFRR_NB_ELEMENT_OUT_OF_RANGE;
}
/* Make sure the range of output does not contains NAN. */
/* TODO Add back nan/inf checking
for( i=0; i < outNbElement; i++ )
{
if( trio_isnan(data[i]) )
{
printf( "Fail: Not a number find within the data (%d,%f)\n", i, data[i] );
return TA_TEST_TFRR_OVERLAP_OR_NAN_3;
}
}*/
/* Verify that the expected output is there. */
if( outNbElement != expectedNbElement )
{
printf( "Fail: outNbElement expected %d but got %d\n",
expectedNbElement, outNbElement );
return TA_TESTUTIL_TFRR_BAD_OUTNBELEMENT;
}
if( expectedNbElement > 0 )
{
if( !TA_REAL_EQ( oneOfTheExpectedOutReal, data[oneOfTheExpectedOutRealIndex], 0.01 ) )
{
printf( "Fail: For index %d, Expected value = %f but calculate value is %f\n",
oneOfTheExpectedOutRealIndex,
oneOfTheExpectedOutReal,
data[oneOfTheExpectedOutRealIndex] );
return TA_TESTUTIL_TFRR_BAD_CALCULATION;
}
if( expectedBegIdx != outBegIdx )
{
printf( "Fail: outBegIdx expected %d but got %d\n", expectedBegIdx, outBegIdx );
return TA_TESTUTIL_TFRR_BAD_BEGIDX;
}
}
/* Succeed. */
return TA_TEST_PASS;
}
ErrorNumber doRangeTest( RangeTestFunction testFunction,
TA_FuncUnstId unstId,
void *opaqueData,
unsigned int nbOutput,
unsigned int integerTolerance )
{
unsigned int outputNb;
ErrorNumber errNb;
/* Test all the outputs individually. */
for( outputNb=0; outputNb < nbOutput; outputNb++ )
{
errNb = doRangeTestForOneOutput( testFunction,
unstId,
opaqueData,
outputNb,
integerTolerance );
if( errNb != TA_TEST_PASS )
{
printf( "Failed: For output #%d of %d\n", outputNb+1, nbOutput );
return errNb;
}
}
return TA_TEST_PASS;
}
void printRetCode( TA_RetCode retCode )
{
TA_RetCodeInfo retCodeInfo;
TA_SetRetCodeInfo( retCode, &retCodeInfo );
printf( "\nFailed: ErrorCode %d=%s:[%s]\n", retCode,
retCodeInfo.enumStr,
retCodeInfo.infoStr );
}
/**** Local functions definitions. ****/
static ErrorNumber doRangeTestForOneOutput( RangeTestFunction testFunction,
TA_FuncUnstId unstId,
void *opaqueData,
unsigned int outputNb,
unsigned int integerTolerance )
{
TA_RetCode retCode;
TA_Integer refOutBeg, refOutNbElement, refLookback;
TA_Integer fixSize;
TA_Real *refBuffer;
TA_Integer *refBufferInt;
ErrorNumber errNb;
TA_Integer unstablePeriod, temp;
unsigned int outputIsInteger;
showFeedback();
/* Caculate the whole range. This is going
* to be the reference for all subsequent test.
*/
refBuffer = (TA_Real *)TA_Malloc( MAX_RANGE_SIZE * sizeof( TA_Real ) );
if( !refBuffer )
return TA_TESTUTIL_DRT_ALLOC_ERR;
refBufferInt = (TA_Integer *)TA_Malloc( MAX_RANGE_SIZE * sizeof( TA_Integer ) );
if( !refBufferInt )
{
TA_Free( refBuffer );
return TA_TESTUTIL_DRT_ALLOC_ERR;
}
if( unstId != TA_FUNC_UNST_NONE )
{
/* Caller wish to test for a range of unstable
* period values. But the reference is calculated
* on the whole range by keeping that unstable period
* to zero.
*/
TA_SetUnstablePeriod( unstId, 0 );
}
outputIsInteger = 0;
retCode = CallTestFunction( testFunction, 0, MAX_RANGE_END, refBuffer, refBufferInt,
&refOutBeg, &refOutNbElement, &refLookback,
opaqueData, outputNb, &outputIsInteger );
if( retCode != TA_SUCCESS )
{
printf( "Fail: doRangeTest whole range failed (%d)\n", retCode );
TA_Free( refBuffer );
TA_Free( refBufferInt );
return TA_TESTUTIL_DRT_REF_FAILED;
}
/* When calculating for the whole range, the lookback and the
* refOutBeg are supppose to be equal.
*/
if( refLookback != refOutBeg )
{
printf( "Fail: doRangeTest refLookback != refOutBeg (%d != %d)\n", refLookback, refOutBeg );
TA_Free( refBuffer );
TA_Free( refBufferInt );
return TA_TESTUTIL_DRT_LOOKBACK_INCORRECT;
}
temp = MAX_RANGE_SIZE-refLookback;
if( temp != refOutNbElement )
{
printf( "Fail: doRangeTest either refOutNbElement or refLookback bad (%d,%d)\n", temp, refOutNbElement );
TA_Free( refBuffer );
TA_Free( refBufferInt );
return TA_TESTUTIL_DRT_REF_OUTPUT_INCORRECT;
}
/* Calculate each value ONE by ONE and make sure it is identical
* to the reference.
*
* Then repeat the test but calculate TWO by TWO and so on...
*/
for( fixSize=1; fixSize <= MAX_RANGE_SIZE; fixSize++ )
{
/* When a function has an unstable period, verify some
* unstable period between 0 and MAX_RANGE_SIZE.
*/
if( unstId == TA_FUNC_UNST_NONE )
{
errNb = doRangeTestFixSize( testFunction, opaqueData,
refOutBeg, refOutNbElement, refLookback,
refBuffer, refBufferInt,
unstId, fixSize, outputNb, integerTolerance );
if( errNb != TA_TEST_PASS)
{
TA_Free( refBuffer );
TA_Free( refBufferInt );
return errNb;
}
}
else
{
for( unstablePeriod=0; unstablePeriod <= MAX_RANGE_SIZE; unstablePeriod++ )
{
TA_SetUnstablePeriod( unstId, unstablePeriod );
errNb = doRangeTestFixSize( testFunction, opaqueData,
refOutBeg, refOutNbElement, refLookback,
refBuffer, refBufferInt,
unstId, fixSize, outputNb, integerTolerance );
if( errNb != TA_TEST_PASS)
{
printf( "Fail: Using unstable period %d\n", unstablePeriod );
TA_Free( refBuffer );
TA_Free( refBufferInt );
return errNb;
}
/* Randomly skip the test of some unstable period (limit case are
* always tested though).
*/
if( (unstablePeriod > 5) && (unstablePeriod < 240) )
{
/* Randomly skips from 0 to 239 tests. Never
* make unstablePeriod exceed 240.
*/
temp = (rand() % 240);
unstablePeriod += temp;
if( unstablePeriod > 240 )
unstablePeriod = 240;
}
}
/* Because the tests with an unstable period are very intensive
* and kinda repetitive, skip the test of some fixSize (limit
* case are always tested though).
*/
if( (fixSize > 5) && (fixSize < 240) )
{
/* Randomly skips from 0 to 239 tests. Never
* make fixSize exceed 240.
*/
temp = (rand() % 239);
fixSize += temp;
if( fixSize > 240 )
fixSize = 240;
}
}
}
TA_Free( refBuffer );
TA_Free( refBufferInt );
return TA_TEST_PASS;
}
static ErrorNumber doRangeTestFixSize( RangeTestFunction testFunction,
void *opaqueData,
TA_Integer refOutBeg,
TA_Integer refOutNbElement,
TA_Integer refLookback,
const TA_Real *refBuffer,
const TA_Integer *refBufferInt,
TA_FuncUnstId unstId,
TA_Integer fixSize,
unsigned int outputNb,
unsigned int integerTolerance )
{
TA_RetCode retCode;
TA_Real *outputBuffer;
TA_Real val1, val2;
TA_Integer i, temp;
TA_Integer outputBegIdx, outputNbElement, lookback;
TA_Integer startIdx, endIdx, relativeIdx, outputSizeByOptimalLogic;
TA_Integer *outputBufferInt;
unsigned int outputIsInteger;
(void)refLookback;
/* Allocate the output buffer (+prefix and suffix memory guard). */
outputBuffer = (TA_Real *)TA_Malloc( (fixSize+2) * sizeof( TA_Real ) );
if( !outputBuffer )
return TA_TESTUTIL_DRT_ALLOC_ERR;
outputBufferInt = (TA_Integer *)TA_Malloc( (fixSize+2) * sizeof( TA_Integer ) );
if( !refBufferInt )
{
TA_Free( outputBuffer );
return TA_TESTUTIL_DRT_ALLOC_ERR;
}
outputBuffer[0] = RESV_PATTERN_PREFIX;
outputBuffer[fixSize+1] = RESV_PATTERN_SUFFIX;
outputBufferInt[0] = RESV_PATTERN_PREFIX_INT;
outputBufferInt[fixSize+1] = RESV_PATTERN_SUFFIX_INT;
/* Initialize the outputs with improbable values. */
for( i=1; i <= fixSize; i++ )
{
outputBuffer[i] = RESV_PATTERN_IMPROBABLE;
outputBufferInt[i] = RESV_PATTERN_IMPROBABLE_INT;
}
/* Test for a large number of possible startIdx */
for( startIdx=0; startIdx <= (MAX_RANGE_SIZE-fixSize); startIdx++ )
{
/* Call the TA function. */
endIdx = startIdx+fixSize-1;
retCode = CallTestFunction( testFunction, startIdx, endIdx,
&outputBuffer[1], &outputBufferInt[1],
&outputBegIdx, &outputNbElement, &lookback,
opaqueData, outputNb, &outputIsInteger );
if( retCode != TA_SUCCESS )
{
/* No call shall never fail here. When the range
* is "out-of-range" the function shall still return
* TA_SUCCESS with the outNbElement equal to zero.
*/
printf( "Fail: doRangeTestFixSize testFunction return error=(%d) (%d,%d)\n", retCode, fixSize, startIdx );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_RETCODE_ERR;
}
else
{
/* Possible startIdx gap of the output shall be always the
* same regardless of the range.
*/
if( outputNbElement == 0 )
{
/* Trap cases where there is no output. */
if( (startIdx > lookback) || (endIdx > lookback) )
{
/* Whenever startIdx is greater than lookback, some data
* shall be return. Same idea with endIdx.
*
* Note:
* some output will never start at the startIdx, particularly
* when a TA function have multiple output. Usually, the first output
* will be between startIdx/endIdx and other outputs may have a "gap"
* from the startIdx.
*
* Example:
* Stochastic %K is between startIdx/endIdx, but %D output will
* have less data because it is a MA of %K. A gap will then
* exist for the %D output.
*/
printf( "Fail: doRangeTestFixSize data missing (%d,%d,%d)\n", startIdx, endIdx, lookback );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_MISSING_DATA;
}
}
else
{
/* Some output was returned. Are the returned index correct? */
if( (outputBegIdx < startIdx) || (outputBegIdx > endIdx) || (outputBegIdx < refOutBeg))
{
printf( "Fail: doRangeTestFixSize bad outBegIdx\n" );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_BAD_OUTBEGIDX;
}
if( (outputNbElement > fixSize) || (outputNbElement > refOutNbElement) )
{
printf( "Fail: doRangeTestFixSize Incorrect outputNbElement\n" );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
return TA_TESTUTIL_DRT_BAD_OUTNBLEMENT;
}
/* Is the calculated lookback too high? */
if( outputBegIdx < lookback )
{
printf( "Fail: doRangeTestFixSize Lookback calculation too high? (%d)\n", lookback );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_LOOKBACK_TOO_HIGH;
}
/* Is the output identical to the reference? */
relativeIdx = outputBegIdx-refOutBeg;
for( i=0; i < outputNbElement; i++ )
{
if( outputIsInteger )
{
if( outputBufferInt[1+i] != refBufferInt[relativeIdx+i] )
{
printf( "Fail: doRangeTestFixSize diff data for idx=%d (%d,%d)\n", i,
outputBufferInt[1+i], refBufferInt[relativeIdx+i] );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_DATA_DIFF_INT;
}
}
else
{
val1 = outputBuffer[1+i];
val2 = refBuffer[relativeIdx+i];
if( !dataWithinReasonableRange( val1, val2, i, unstId, integerTolerance ) )
{
printf( "Fail: doRangeTestFixSize diff data for idx=%d (%e,%e)\n", i, val1, val2 );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
if( val1 != 0.0 )
printf( "Fail: Diff %g %%\n", ((val2-val1)/val1)*100.0 );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_DATA_DIFF;
}
}
/* Randomly skip the verification of some value. Limit
* cases are always checked though.
*/
if( outputNbElement > 30 )
{
temp = outputNbElement-20;
if( (i > 20) && (i < temp) )
{
/* Randomly skips from 0 to 200 verification.
* Never make it skip the last 20 values.
*/
i += (rand() % 200);
if( i > temp )
i = temp;
}
}
}
/* Verify out-of-bound writing in the output buffer. */
outputSizeByOptimalLogic = max(lookback,startIdx);
if( outputSizeByOptimalLogic > endIdx )
outputSizeByOptimalLogic = 0;
else
outputSizeByOptimalLogic = endIdx-outputSizeByOptimalLogic+1;
if( (fixSize != outputNbElement) && (outputBuffer[1+outputSizeByOptimalLogic] != RESV_PATTERN_IMPROBABLE) )
{
printf( "Fail: doRangeTestFixSize out-of-bound output (%e)\n", outputBuffer[1+outputSizeByOptimalLogic] );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_OUT_OF_BOUND_OUT;
}
if( (fixSize != outputNbElement) && (outputBufferInt[1+outputSizeByOptimalLogic] != RESV_PATTERN_IMPROBABLE_INT) )
{
printf( "Fail: doRangeTestFixSize out-of-bound output (%d)\n", outputBufferInt[1+outputSizeByOptimalLogic] );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_OUT_OF_BOUND_OUT_INT;
}
/* Verify that the memory guard were preserved. */
if( outputBuffer[0] != RESV_PATTERN_PREFIX )
{
printf( "Fail: doRangeTestFixSize bad RESV_PATTERN_PREFIX (%e)\n", outputBuffer[0] );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_BAD_PREFIX;
}
if( outputBufferInt[0] != RESV_PATTERN_PREFIX_INT )
{
printf( "Fail: doRangeTestFixSize bad RESV_PATTERN_PREFIX_INT (%d)\n", outputBufferInt[0] );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_BAD_PREFIX;
}
if( outputBuffer[fixSize+1] != RESV_PATTERN_SUFFIX )
{
printf( "Fail: doRangeTestFixSize bad RESV_PATTERN_SUFFIX (%e)\n", outputBuffer[fixSize+1] );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_BAD_SUFFIX;
}
if( outputBufferInt[fixSize+1] != RESV_PATTERN_SUFFIX_INT )
{
printf( "Fail: doRangeTestFixSize bad RESV_PATTERN_SUFFIX_INT (%d)\n", outputBufferInt[fixSize+1] );
printf( "Fail: doRangeTestFixSize (%d,%d,%d,%d,%d)\n", startIdx, endIdx, outputBegIdx, outputNbElement, fixSize );
printf( "Fail: doRangeTestFixSize refOutBeg,refOutNbElement (%d,%d)\n", refOutBeg, refOutNbElement );
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TESTUTIL_DRT_BAD_SUFFIX;
}
/* Clean-up for next test. */
if( outputIsInteger )
{
for( i=1; i <= fixSize; i++ )
outputBufferInt[i] = RESV_PATTERN_IMPROBABLE_INT;
}
else
{
for( i=1; i <= fixSize; i++ )
outputBuffer[i] = RESV_PATTERN_IMPROBABLE;
}
}
/* Skip some startIdx at random. Limit case are still
* tested though.
*/
if( (startIdx > 30) && ((startIdx+100) <= (MAX_RANGE_SIZE-fixSize)) )
{
/* Randomly skips from 40 to 100 tests. */
temp = (rand() % 100)+40;
startIdx += temp;
}
}
/* Loop and move forward for the next startIdx to test. */
}
TA_Free( outputBuffer );
TA_Free( outputBufferInt );
return TA_TEST_PASS;
}
/* This function compares two value.
* The value is determined to be equal
* if it is within a certain error range.
*/
static int dataWithinReasonableRange( TA_Real val1, TA_Real val2,
unsigned int outputPosition,
TA_FuncUnstId unstId,
unsigned int integerTolerance )
{
TA_Real difference, tolerance, temp;
unsigned int val1_int, val2_int, tempInt, periodToIgnore;
if( integerTolerance == TA_DO_NOT_COMPARE )
return 1; /* Don't compare, says that everything is fine */
/* If the function does not have an unstable period,
* the compared value shall be identical.
*
* Because the algo may vary slightly allow for
* a small epsilon error because of the nature
* of floating point operations.
*/
if( unstId == TA_FUNC_UNST_NONE )
return TA_REAL_EQ( val1, val2, 0.000000001 );
/* In the context of the TA functions, all value
* below 0.00001 are considered equal to zero and
* are considered to be equal within a reasonable range.
* (the percentage difference might be large, but
* unsignificant at that level, so no tolerance
* check is being done).
*/
if( (val1 < 0.00001) && (val2 < 0.00001) )
return 1;
/* When the function is unstable, the comparison
* tolerate at first a large difference.
*
* As the number of "outputPosition" is higher
* the tolerance is reduced.
*
* In the same way, as the unstable period
* increase, the tolerance is reduced (that's
* what the unstable period is for... reducing
* difference).
*
* When dealing with an unstable period, the
* first 100 values are ignored.
*
* Following 100, the tolerance is
* progressively reduced as follow:
*
* 1 == 0.5/1 == 50 %
* 2 == 0.5/2 == 25 %
* ...
* 100 == 0.5/100 == 0.005 %
* ...
*
* Overall, the following is a fair estimation:
* When using a unstable period of 200, you
* can expect the output to not vary more
* than 0.005 %
*
* The logic is sligthly different if the
* output are rounded integer, but it is
* the same idea.
*
* The following describe the special meaning of
* the integerTolerance:
*
* Value 10 -> A tolerance of 1/10 is used.
*
* Value 100 -> A tolerance of 1/100 is used.
*
* Value 1000 -> A tolerance of 1/1000 is used.
*
* Value 360 -> Useful when the output are
* degrees. In that case, a fix
* tolerance of 1 degree is used.
*
* Value TA_DO_NOT_COMPARE ->
* Indicate that NO COMPARISON take
* place. This is useful for functions
* that cannot be compare when changing
* the range (like the accumulative
* algorithm used for TA_AD and TA_ADOSC).
*/
/* Some functions requires a longer unstable period.
* These are trap here.
*/
switch( unstId )
{
case TA_FUNC_UNST_T3:
periodToIgnore = 200;
break;
default:
periodToIgnore = 100;
break;
}
if( integerTolerance == 1000 )
{
/* Check for no difference of more
* than 1/1000
*/
if( val1 > val2 )
difference = (val1-val2);
else
difference = (val2-val1);
difference *= 1000.0;
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1;
if( temp <= periodToIgnore )
{
/* Pretend it is fine. */
return 1;
}
else if( (int)difference > 1 )
{
printf( "\nFail: Value diffferent by more than 1/1000 (%f)\n", difference );
return 0;
}
}
else if( integerTolerance == 100 )
{
/* Check for no difference of more
* than 1/1000
*/
if( val1 > val2 )
difference = (val1-val2);
else
difference = (val2-val1);
difference *= 100.0;
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1;
if( temp <= periodToIgnore )
{
/* Pretend it is fine. */
return 1;
}
else if( (int)difference > 1 )
{
printf( "\nFail: Value diffferent by more than 1/100 (%f)\n", difference );
return 0;
}
}
else if( integerTolerance == 10 )
{
/* Check for no difference of more
* than 1/1000
*/
if( val1 > val2 )
difference = (val1-val2);
else
difference = (val2-val1);
difference *= 10.0;
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1;
if( temp <= periodToIgnore )
{
/* Pretend it is fine. */
return 1;
}
else if( (int)difference > 1 )
{
printf( "\nFail: Value diffferent by more than 1/10 (%f)\n", difference );
return 0;
}
}
else if( integerTolerance == 360 )
{
/* Check for no difference of no more
* than 10% when the value is higher than
* 1 degree.
*
* Difference of less than 1 degree are not significant.
*/
val1_int = (unsigned int)val1;
val2_int = (unsigned int)val2;
if( val1_int > val2_int )
tempInt = val1_int - val2_int;
else
tempInt = val2_int - val1_int;
if( val1 > val2 )
difference = (val1-val2)/val1;
else
difference = (val2-val1)/val2;
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1;
if( temp <= periodToIgnore )
{
/* Pretend it is fine. */
return 1;
}
else if( (tempInt > 1) && (difference > 0.10) )
{
printf( "\nFail: Value diffferent by more than 10 percent over 1 degree (%d)\n", tempInt );
return 0;
}
}
else if( integerTolerance )
{
/* Check that the integer part of the value
* is not different more than the specified
* integerTolerance.
*/
val1_int = (unsigned int)val1;
val2_int = (unsigned int)val2;
if( val1_int > val2_int )
tempInt = val1_int - val2_int;
else
tempInt = val2_int - val1_int;
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1;
if( temp <= periodToIgnore )
{
/* Pretend it is fine. */
return 1;
}
else if( temp < 100 )
{
if( tempInt >= 3*integerTolerance )
{
printf( "\nFail: Value out of 3*tolerance range (%d,%d)\n", tempInt, integerTolerance );
return 0; /* Value considered different */
}
}
else if( temp < 150 )
{
if( tempInt >= 2*integerTolerance )
{
printf( "\nFail: Value out of 2*tolerance range (%d,%d)\n", tempInt, integerTolerance );
return 0; /* Value considered different */
}
}
else if( temp < 200 )
{
if( tempInt >= integerTolerance )
{
printf( "\nFail: Value out of tolerance range (%d,%d)\n", tempInt, integerTolerance );
return 0; /* Value considered different */
}
}
else if( tempInt >= 1 )
{
printf( "\nFail: Value not equal (difference is %d)\n", tempInt );
return 0; /* Value considered different */
}
}
else
{
if( val1 > val2 )
difference = (val1-val2)/val1;
else
difference = (val2-val1)/val2;
temp = outputPosition+TA_GetUnstablePeriod(unstId)+1;
if( temp <= periodToIgnore )
{
/* Pretend it is fine. */
return 1;
}
else
{
temp -= periodToIgnore;
tolerance = 0.5/temp;
}
if( difference > tolerance )
{
printf( "\nFail: Value out of tolerance range (%g,%g)\n", difference, tolerance );
return 0; /* Out of tolerance... values are not equal. */
}
}
return 1; /* Value equal within tolerance. */
}
static TA_RetCode CallTestFunction( RangeTestFunction testFunction,
TA_Integer startIdx,
TA_Integer endIdx,
TA_Real *outputBuffer,
TA_Integer *outputBufferInt,
TA_Integer *outBegIdx,
TA_Integer *outNbElement,
TA_Integer *lookback,
void *opaqueData,
unsigned int outputNb,
unsigned int *isOutputInteger )
{
/* Call the function and do profiling. */
TA_RetCode retCode;
double clockDelta;
#ifdef WIN32
LARGE_INTEGER startClock;
LARGE_INTEGER endClock;
#else
clock_t startClock;
clock_t endClock;
#endif
#ifdef WIN32
QueryPerformanceCounter(&startClock);
#else
startClock = clock();
#endif
retCode = testFunction( startIdx,
endIdx,
outputBuffer,
outputBufferInt,
outBegIdx,
outNbElement,
lookback,
opaqueData,
outputNb,
isOutputInteger );
/* Profile only functions producing at least 20 values. */
if( *outNbElement < 20 )
{
return retCode;
}
#ifdef WIN32
QueryPerformanceCounter(&endClock);
clockDelta = (double)((__int64)endClock.QuadPart - (__int64) startClock.QuadPart);
#else
endClock = clock();
clockDelta = (double)(endClock - startClock);
#endif
if( clockDelta <= 0 )
{
insufficientClockPrecision = 1;
}
else
{
if( clockDelta > worstProfiledCall )
worstProfiledCall = clockDelta;
timeInProfiledCall += clockDelta;
nbProfiledCall++;
}
return retCode;
}