Files
Vadim Zeitlin 1ee2480841 Avoid undefined behaviour in wxLongLong unit tests
There were several instances of signed integer overflow, avoid them by
either restricting the range or switching to unsigned.
2024-10-20 17:29:24 +02:00

242 lines
6.2 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: tests/longlong/longlong.cpp
// Purpose: wxLongLong unit test
// Author: Vadim Zeitlin, Wlodzimierz ABX Skiba
// Created: 2004-04-01
// Copyright: (c) 2004 Vadim Zeitlin, Wlodzimierz Skiba
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/longlong.h"
#include "wx/timer.h"
// ----------------------------------------------------------------------------
// helpers for testing
// ----------------------------------------------------------------------------
// number of iterations in loops
#define ITEMS 1000
// get a random 64 bit number
#define RAND_LL() wxLongLong(rand(), rand())
static const long testLongs[] =
{
0,
1,
-1,
LONG_MAX,
LONG_MIN,
0x1234,
-0x1234
};
// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------
class LongLongTestCase : public CppUnit::TestCase
{
public:
LongLongTestCase();
private:
CPPUNIT_TEST_SUITE( LongLongTestCase );
CPPUNIT_TEST( Conversion );
CPPUNIT_TEST( Comparison );
CPPUNIT_TEST( Addition );
CPPUNIT_TEST( Multiplication );
CPPUNIT_TEST( Division );
CPPUNIT_TEST( BitOperations );
CPPUNIT_TEST( ToString );
CPPUNIT_TEST( LoHi );
CPPUNIT_TEST( Limits );
CPPUNIT_TEST_SUITE_END();
void Conversion();
void Comparison();
void Addition();
void Multiplication();
void Division();
void BitOperations();
void ToString();
void LoHi();
void Limits();
wxDECLARE_NO_COPY_CLASS(LongLongTestCase);
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( LongLongTestCase );
// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( LongLongTestCase, "LongLongTestCase" );
LongLongTestCase::LongLongTestCase()
{
srand((unsigned)time(nullptr));
}
void LongLongTestCase::Conversion()
{
for ( size_t n = 0; n < ITEMS; n++ )
{
wxLongLong a = RAND_LL();
wxLongLong b(a.GetHi(), a.GetLo());
CPPUNIT_ASSERT( a == b );
}
}
void LongLongTestCase::Comparison()
{
static const long ls[2] =
{
0x1234,
-0x1234,
};
wxLongLong lls[2];
lls[0] = ls[0];
lls[1] = ls[1];
for ( size_t n = 0; n < WXSIZEOF(testLongs); n++ )
{
for ( size_t m = 0; m < WXSIZEOF(lls); m++ )
{
CPPUNIT_ASSERT( (lls[m] < testLongs[n]) == (ls[m] < testLongs[n]) );
CPPUNIT_ASSERT( (lls[m] > testLongs[n]) == (ls[m] > testLongs[n]) );
CPPUNIT_ASSERT( (lls[m] <= testLongs[n]) == (ls[m] <= testLongs[n]) );
CPPUNIT_ASSERT( (lls[m] >= testLongs[n]) == (ls[m] >= testLongs[n]) );
CPPUNIT_ASSERT( (lls[m] != testLongs[n]) == (ls[m] != testLongs[n]) );
CPPUNIT_ASSERT( (lls[m] == testLongs[n]) == (ls[m] == testLongs[n]) );
}
}
}
void LongLongTestCase::Addition()
{
for ( size_t n = 0; n < ITEMS; n++ )
{
// Avoid overflow by using numbers less than half of the maximum value.
wxLongLong a = RAND_LL() / 2;
wxLongLong b = RAND_LL() / 2;
wxLongLong c = a + b;
CPPUNIT_ASSERT( c.GetValue() == a.GetValue() + b.GetValue() );
}
}
void LongLongTestCase::Multiplication()
{
for ( size_t n = 0; n < ITEMS; n++ )
{
// Avoid signed integer overflow by multiplying unsigned numbers only.
wxULongLong a = RAND_LL().GetValue();
wxULongLong b = RAND_LL().GetValue();
wxULongLong c = a*b;
CPPUNIT_ASSERT( c.GetValue() == a.GetValue() * b.GetValue() );
wxULongLong a1(a.GetHi(), a.GetLo());
wxULongLong b1(b.GetHi(), b.GetLo());
wxULongLong c1 = a1*b1;
CPPUNIT_ASSERT( c1 == c );
}
}
void LongLongTestCase::Division()
{
for ( size_t n = 0; n < ITEMS; n++ )
{
wxLongLong a = RAND_LL();
// get a random (but non null) long (not wxLongLong for now) divider
long l;
do
{
l = rand();
}
while ( !l );
wxLongLong q = a / l;
wxLongLong r = a % l;
CPPUNIT_ASSERT( a == ( q * l + r ) );
}
}
void LongLongTestCase::BitOperations()
{
for ( size_t m = 0; m < ITEMS; m++ )
{
wxLongLong a = RAND_LL();
for ( size_t n = 0; n < 33; n++ )
{
wxLongLong b(a.GetHi(), a.GetLo()), c, d = b, e;
d >>= n;
c = b >> n;
CPPUNIT_ASSERT( c == d );
d <<= n;
e = c << n;
CPPUNIT_ASSERT( d == e );
}
}
}
void LongLongTestCase::ToString()
{
wxString s1, s2;
for ( size_t n = 0; n < WXSIZEOF(testLongs); n++ )
{
wxLongLong a = testLongs[n];
s1 = wxString::Format(wxT("%ld"), testLongs[n]);
s2 = a.ToString();
CPPUNIT_ASSERT( s1 == s2 );
s2 = wxEmptyString;
s2 << a;
CPPUNIT_ASSERT( s1 == s2 );
}
wxLongLong a(0x12345678, 0x87654321);
CPPUNIT_ASSERT( a.ToString() == wxT("1311768467139281697") );
a.Negate();
CPPUNIT_ASSERT( a.ToString() == wxT("-1311768467139281697") );
wxLongLong llMin(-2147483647L - 1L, 0);
CPPUNIT_ASSERT( llMin.ToString() == wxT("-9223372036854775808") );
}
void LongLongTestCase::LoHi()
{
wxLongLong ll(123, 456);
CPPUNIT_ASSERT_EQUAL( 456u, ll.GetLo() );
CPPUNIT_ASSERT_EQUAL( 123, ll.GetHi() );
wxULongLong ull(987, 654);
CPPUNIT_ASSERT_EQUAL( 654u, ull.GetLo() );
CPPUNIT_ASSERT_EQUAL( 987u, ull.GetHi() );
}
void LongLongTestCase::Limits()
{
CPPUNIT_ASSERT( std::numeric_limits<wxLongLong>::is_specialized );
CPPUNIT_ASSERT( std::numeric_limits<wxULongLong>::is_specialized );
wxULongLong maxval = std::numeric_limits<wxULongLong>::max();
CPPUNIT_ASSERT( maxval.ToDouble() > 0 );
}