|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright 2004 Ariya Hidayat <ariya@kde.org>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "tester.h"
|
|
|
|
#include "value_tester.h"
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
#include <kspread_value.h>
|
|
|
|
|
|
|
|
#define CHECK(x,y) check(__FILE__,__LINE__,#x,x,y)
|
|
|
|
#define CHECK_DATE(d,x) check(__FILE__,__LINE__,TQString(d->asDate().toString()).latin1(),d->asFloat(),x)
|
|
|
|
|
|
|
|
using namespace KSpread;
|
|
|
|
|
|
|
|
ValueTester::ValueTester(): Tester()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString ValueTester::name()
|
|
|
|
{
|
|
|
|
return TQString("Value");
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void ValueTester::check( const char *file, int line, const char* msg, const T& result,
|
|
|
|
const T& expected )
|
|
|
|
{
|
|
|
|
testCount++;
|
|
|
|
if( result != expected )
|
|
|
|
{
|
|
|
|
TQString message;
|
|
|
|
TQTextStream ts( &message, IO_WriteOnly );
|
|
|
|
ts << msg;
|
|
|
|
ts << " Result:";
|
|
|
|
ts << result;
|
|
|
|
ts << ", ";
|
|
|
|
ts << "Expected:";
|
|
|
|
ts << expected;
|
|
|
|
fail( file, line, message );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ValueTester::check( const char *file, int line, const char* msg, bool result, bool expected )
|
|
|
|
{
|
|
|
|
testCount++;
|
|
|
|
if( result != expected )
|
|
|
|
{
|
|
|
|
TQString message;
|
|
|
|
TQTextStream ts( &message, IO_WriteOnly );
|
|
|
|
ts << msg;
|
|
|
|
ts << " Result: ";
|
|
|
|
if( result ) ts << "True"; else ts << "False";
|
|
|
|
ts << ", ";
|
|
|
|
ts << "Expected: ";
|
|
|
|
if( expected ) ts << "True"; else ts << "False";
|
|
|
|
fail( file, line, message );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ValueTester::run()
|
|
|
|
{
|
|
|
|
testCount = 0;
|
|
|
|
errorList.clear();
|
|
|
|
|
|
|
|
Value* v1;
|
|
|
|
Value* v2;
|
|
|
|
|
|
|
|
// empty value
|
|
|
|
v1 = new Value();
|
|
|
|
CHECK( v1->type(), Value::Empty );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// boolean value (true)
|
|
|
|
v1 = new Value( true );
|
|
|
|
CHECK( v1->type(), Value::Boolean );
|
|
|
|
CHECK( v1->asBoolean(), true );
|
|
|
|
v1->setValue( 1 ); // dummy
|
|
|
|
v1->setValue( true );
|
|
|
|
CHECK( v1->type(), Value::Boolean );
|
|
|
|
CHECK( v1->asBoolean(), true );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// boolean value (false)
|
|
|
|
v1 = new Value( false );
|
|
|
|
CHECK( v1->type(), Value::Boolean );
|
|
|
|
CHECK( v1->asBoolean(), false );
|
|
|
|
v1->setValue( 4 ); // dummy
|
|
|
|
v1->setValue( false );
|
|
|
|
CHECK( v1->type(), Value::Boolean );
|
|
|
|
CHECK( v1->asBoolean(), false );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// integer value
|
|
|
|
v1 = new Value( 1977 );
|
|
|
|
CHECK( v1->type(), Value::Integer );
|
|
|
|
CHECK( v1->asInteger(), (long)1977 );
|
|
|
|
v1->setValue( false ); // dummy
|
|
|
|
v1->setValue( 14 );
|
|
|
|
CHECK( v1->type(), Value::Integer );
|
|
|
|
CHECK( v1->isInteger(), true );
|
|
|
|
CHECK( v1->isFloat(), false );
|
|
|
|
CHECK( v1->isString(), false );
|
|
|
|
CHECK( v1->isNumber(), true );
|
|
|
|
CHECK( v1->asInteger(), (long)14 );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// floating-point value
|
|
|
|
v1 = new Value( M_PI );
|
|
|
|
CHECK( v1->type(), Value::Float );
|
|
|
|
CHECK( v1->asFloat(), M_PI );
|
|
|
|
v1->setValue( false ); // dummy
|
|
|
|
v1->setValue( 14.03 );
|
|
|
|
CHECK( v1->type(), Value::Float );
|
|
|
|
CHECK( v1->isInteger(), false );
|
|
|
|
CHECK( v1->isFloat(), true );
|
|
|
|
CHECK( v1->isString(), false );
|
|
|
|
CHECK( v1->isNumber(), true );
|
|
|
|
CHECK( v1->asFloat(), 14.03 );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// string value
|
|
|
|
v1 = new Value( TQString("Ailinon" ) );
|
|
|
|
CHECK( v1->type(), Value::String );
|
|
|
|
CHECK( v1->asString(), TQString("Ailinon" ) );
|
|
|
|
v1->setValue( 7 ); // dummy
|
|
|
|
v1->setValue( TQString("spreadsheet" ) );
|
|
|
|
CHECK( v1->type(), Value::String );
|
|
|
|
CHECK( v1->isInteger(), false );
|
|
|
|
CHECK( v1->isFloat(), false );
|
|
|
|
CHECK( v1->isString(), true );
|
|
|
|
CHECK( v1->isNumber(), false );
|
|
|
|
CHECK( v1->asString(), TQString("spreadsheet" ) );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// check all (valid) dates from 1900 to 2050
|
|
|
|
// note: bail on first error immediately
|
|
|
|
TQDate refDate( 1899, 12, 31 );
|
|
|
|
v1 = new Value();
|
|
|
|
bool date_error = 0;
|
|
|
|
for( unsigned y = 1900; !date_error && y < 2050; y++ )
|
|
|
|
for( unsigned m = 1; !date_error && m <= 12; m++ )
|
|
|
|
for( unsigned d = 1; !date_error && d <= 31; d++ )
|
|
|
|
{
|
|
|
|
TQDate dv1 = TQDate( y, m, d );
|
|
|
|
if( !dv1.isValid() ) continue;
|
|
|
|
double serialNo = -dv1.daysTo( refDate ) + 1.0;
|
|
|
|
v1->setValue( dv1 );
|
|
|
|
CHECK_DATE(v1,serialNo);
|
|
|
|
date_error = v1->asFloat() != serialNo;
|
|
|
|
}
|
|
|
|
|
|
|
|
// time value
|
|
|
|
v1 = new Value();
|
|
|
|
v1->setValue( TQTime( 0, 0, 0 ) );
|
|
|
|
CHECK( v1->type(), Value::Integer );
|
|
|
|
int time_error = 0; // used to save time, bail on first error
|
|
|
|
for( unsigned h = 0; !time_error && h < 24; h++ )
|
|
|
|
for( unsigned m = 0; !time_error && m < 60; m++ )
|
|
|
|
for( unsigned s = 0; !time_error && s < 60; s++ )
|
|
|
|
{
|
|
|
|
TQTime t1 = TQTime( h, m, s );
|
|
|
|
v1->setValue( t1 );
|
|
|
|
TQTime t2 = v1->asTime();
|
|
|
|
if( t1.hour() != t2.hour() ) time_error++;
|
|
|
|
if( t1.minute() != t2.minute() ) time_error++;
|
|
|
|
if( t1.second() != t2.second() ) time_error++;
|
|
|
|
if( t1.msec() != t2.msec() ) time_error++;
|
|
|
|
}
|
|
|
|
CHECK( time_error, 0 );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// time value (msec)
|
|
|
|
v1 = new Value();
|
|
|
|
v1->setValue( TQTime( 0, 0, 0 ) );
|
|
|
|
CHECK( v1->type(), Value::Integer );
|
|
|
|
int msec_error = 0; // used to save time, bail on first error
|
|
|
|
for( unsigned ms= 0;ms < 1000;ms++ )
|
|
|
|
{
|
|
|
|
TQTime t1 = TQTime( 1, 14, 2, ms );
|
|
|
|
v1->setValue( t1 );
|
|
|
|
TQTime t2 = v1->asTime();
|
|
|
|
if( t1.hour() != t2.hour() ) msec_error++;
|
|
|
|
if( t1.minute() != t2.minute() ) msec_error++;
|
|
|
|
if( t1.second() != t2.second() ) msec_error++;
|
|
|
|
if( t1.msec() != t2.msec() ) msec_error++;
|
|
|
|
if( msec_error ) break;
|
|
|
|
}
|
|
|
|
CHECK( msec_error, 0 );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
|
|
|
|
// TODO error values
|
|
|
|
|
|
|
|
// TODO compare values
|
|
|
|
// TODO add, sub, mul, div values
|
|
|
|
// TODO pow
|
|
|
|
|
|
|
|
// array
|
|
|
|
v1 = new Value( 10, 3 ); // 10 columns, 3 rows
|
|
|
|
CHECK( v1->type(), Value::Array );
|
|
|
|
CHECK( v1->columns(), (unsigned)10 );
|
|
|
|
CHECK( v1->rows(), (unsigned)3 );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// check empty value in array
|
|
|
|
v1 = new Value( 1, 1 );
|
|
|
|
CHECK( v1->type(), Value::Array );
|
|
|
|
v2 = new Value( v1->element( 0, 0 ) );
|
|
|
|
CHECK( v2->type(), Value::Empty );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// fill simple 1x1 array
|
|
|
|
v1 = new Value( 1, 1 );
|
|
|
|
CHECK( v1->type(), Value::Array );
|
|
|
|
v2 = new Value( 14.3 );
|
|
|
|
v1->setElement( 0, 0, *v2 );
|
|
|
|
delete v2;
|
|
|
|
v2 = new Value( v1->element( 0, 0 ) );
|
|
|
|
CHECK( v2->type(), Value::Float );
|
|
|
|
CHECK( v2->asFloat(), 14.3 );
|
|
|
|
delete v2;
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// stress test, array of 1000x1000
|
|
|
|
v1 = new Value( 1000, 1000 );
|
|
|
|
CHECK( v1->type(), Value::Array );
|
|
|
|
for( unsigned c=0; c<1000; c++ )
|
|
|
|
for( unsigned r=0; r<1000; r++ )
|
|
|
|
{
|
|
|
|
int index = 1000*r + c;
|
|
|
|
v1->setElement( c, r, Value( index ) );
|
|
|
|
}
|
|
|
|
int array_error = 0;
|
|
|
|
for( unsigned c=0; !array_error && c<1000; c++ )
|
|
|
|
for( unsigned r=0; !array_error && r<1000; r++ )
|
|
|
|
{
|
|
|
|
int index = 1000*r + c;
|
|
|
|
v2 = new Value( v1->element( c, r ) );
|
|
|
|
if( v2->type() != Value::Integer ) array_error++;
|
|
|
|
if( v2->asInteger() != index ) array_error++;
|
|
|
|
delete v2;
|
|
|
|
}
|
|
|
|
CHECK( array_error, (int)0 );
|
|
|
|
delete v1;
|
|
|
|
|
|
|
|
// assignment of array value
|
|
|
|
v1 = new Value( 1, 1 );
|
|
|
|
CHECK( v1->type(), Value::Array );
|
|
|
|
v1->setElement( 0, 0, Value( 14.3) );
|
|
|
|
v2 = new Value( *v1 ); // v2 is now also an array
|
|
|
|
delete v1;
|
|
|
|
v1 = new Value( v2->element( 0, 0 ) );
|
|
|
|
CHECK( v1->type(), Value::Float );
|
|
|
|
CHECK( v1->asFloat(), 14.3 );
|
|
|
|
delete v1;
|
|
|
|
delete v2;
|
|
|
|
|
|
|
|
// copy value
|
|
|
|
v1 = new Value();
|
|
|
|
v1->setValue( 14.3 );
|
|
|
|
v2 = new Value( *v1 );
|
|
|
|
CHECK( v1->type(), Value::Float );
|
|
|
|
CHECK( v2->type(), Value::Float );
|
|
|
|
CHECK( v1->asFloat(), 14.3 );
|
|
|
|
CHECK( v2->asFloat(), 14.3 );
|
|
|
|
delete v1;
|
|
|
|
delete v2;
|
|
|
|
|
|
|
|
// value assignment
|
|
|
|
v1 = new Value( 14.3 );
|
|
|
|
v2 = new Value( true );
|
|
|
|
v2->assign( *v1 );
|
|
|
|
CHECK( v1->type(), Value::Float );
|
|
|
|
CHECK( v2->type(), Value::Float );
|
|
|
|
CHECK( v1->asFloat(), 14.3 );
|
|
|
|
CHECK( v2->asFloat(), 14.3 );
|
|
|
|
delete v1;
|
|
|
|
delete v2;
|
|
|
|
|
|
|
|
// verify detachment
|
|
|
|
v1 = new Value( 14.3 );
|
|
|
|
v2 = new Value( *v1 );
|
|
|
|
v2->detach(); // v1 and v2 don't share data anymore
|
|
|
|
CHECK( v1->type(), Value::Float );
|
|
|
|
CHECK( v2->type(), Value::Float );
|
|
|
|
CHECK( v1->asFloat(), 14.3 );
|
|
|
|
CHECK( v2->asFloat(), 14.3 );
|
|
|
|
delete v1;
|
|
|
|
delete v2;
|
|
|
|
}
|