/* This file is part of the KDE project Copyright 2004 Ariya Hidayat 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 #include #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 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; }