Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

1
test/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/engine-data

5
test/README Normal file
View File

@@ -0,0 +1,5 @@
This directory contains some unit tests for ScummVM. They are based on
CxxTest <http://cxxtest.com/>, which you can find in the cxxtest
subdirectory, including its manual.
To run the unit tests, simply use "make test".

208
test/audio/audiostream.h Normal file
View File

@@ -0,0 +1,208 @@
#include <cxxtest/TestSuite.h>
#include "audio/audiostream.h"
#include "helper.h"
class AudioStreamTestSuite : public CxxTest::TestSuite
{
public:
void test_convertTimeToStreamPos() {
const Audio::Timestamp a = Audio::convertTimeToStreamPos(Audio::Timestamp(500, 1000), 11025, true);
// The last bit has to be 0 in any case for a stereo stream.
TS_ASSERT_EQUALS(a.totalNumberOfFrames() & 1, 0);
// TODO: This test is rather hacky... actually converTimeToStreamPos might also return 11026
// instead of 11024 and it would still be a valid sample position for ~500ms.
TS_ASSERT_EQUALS(a.totalNumberOfFrames(), 11024);
const Audio::Timestamp b = Audio::convertTimeToStreamPos(Audio::Timestamp(500, 1000), 11025, false);
TS_ASSERT_EQUALS(b.totalNumberOfFrames(), 500 * 11025 / 1000);
// Test Audio CD positioning
// for 44kHz and stereo
const Audio::Timestamp c = Audio::convertTimeToStreamPos(Audio::Timestamp(0, 50, 75), 44100, true);
TS_ASSERT_EQUALS(c.totalNumberOfFrames(), 50 * 44100 * 2 / 75);
// for 11kHz and mono
const Audio::Timestamp d = Audio::convertTimeToStreamPos(Audio::Timestamp(0, 50, 75), 11025, false);
TS_ASSERT_EQUALS(d.totalNumberOfFrames(), 50 * 11025 / 75);
// Some misc test
const Audio::Timestamp e = Audio::convertTimeToStreamPos(Audio::Timestamp(1, 1, 4), 11025, false);
TS_ASSERT_EQUALS(e.totalNumberOfFrames(), 5 * 11025 / 4);
}
private:
void testLoopingAudioStreamFixedIter(const int sampleRate, const bool isStereo) {
const int secondLength = sampleRate * (isStereo ? 2 : 1);
int16 *sine = 0;
Audio::SeekableAudioStream *s = createSineStream<int16>(sampleRate, 1, &sine, false, isStereo);
Audio::LoopingAudioStream *loop = new Audio::LoopingAudioStream(s, 7);
int16 *buffer = new int16[secondLength * 3];
// Check parameters
TS_ASSERT_EQUALS(loop->isStereo(), isStereo);
TS_ASSERT_EQUALS(loop->getRate(), sampleRate);
TS_ASSERT_EQUALS(loop->endOfData(), false);
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)0);
// Read one second
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), secondLength);
TS_ASSERT_EQUALS(memcmp(buffer, sine, secondLength * sizeof(int16)), 0);
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)1);
TS_ASSERT_EQUALS(loop->endOfData(), false);
// Read two seconds
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength * 2), secondLength * 2);
TS_ASSERT_EQUALS(memcmp(buffer, sine, secondLength * sizeof(int16)), 0);
TS_ASSERT_EQUALS(memcmp(buffer + secondLength, sine, secondLength * sizeof(int16)), 0);
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)3);
TS_ASSERT_EQUALS(loop->endOfData(), false);
// Read three seconds
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength * 3), secondLength * 3);
TS_ASSERT_EQUALS(memcmp(buffer, sine, secondLength * sizeof(int16)), 0);
TS_ASSERT_EQUALS(memcmp(buffer + secondLength, sine, secondLength * sizeof(int16)), 0);
TS_ASSERT_EQUALS(memcmp(buffer + secondLength * 2, sine, secondLength * sizeof(int16)), 0);
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)6);
TS_ASSERT_EQUALS(loop->endOfData(), false);
// Read the last second in two parts
const int firstStep = secondLength / 2;
const int secondStep = secondLength - firstStep;
TS_ASSERT_EQUALS(loop->readBuffer(buffer, firstStep), firstStep);
TS_ASSERT_EQUALS(memcmp(buffer, sine, firstStep * sizeof(int16)), 0);
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)6);
TS_ASSERT_EQUALS(loop->endOfData(), false);
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), secondStep);
TS_ASSERT_EQUALS(memcmp(buffer, sine + firstStep, secondStep * sizeof(int16)), 0);
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)7);
TS_ASSERT_EQUALS(loop->endOfData(), true);
// Try to read beyond the end of the stream
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), 0);
TS_ASSERT_EQUALS(loop->getCompleteIterations(), (uint)7);
TS_ASSERT_EQUALS(loop->endOfData(), true);
delete[] buffer;
delete loop;
delete[] sine;
}
public:
void test_looping_audio_stream_mono_11025_fixed_iter() {
testLoopingAudioStreamFixedIter(11025, false);
}
void test_looping_audio_stream_mono_22050_fixed_iter() {
testLoopingAudioStreamFixedIter(22050, false);
}
void test_looping_audio_stream_stereo_11025_fixed_iter() {
testLoopingAudioStreamFixedIter(11025, true);
}
void test_looping_audio_stream_stereo_22050_fixed_iter() {
testLoopingAudioStreamFixedIter(22050, true);
}
private:
void testSubLoopingAudioStreamFixedIter(const int sampleRate, const bool isStereo, const int time, const int loopEndTime) {
const int secondLength = sampleRate * (isStereo ? 2 : 1);
const Audio::Timestamp loopStart(500, 1000), loopEnd(loopEndTime * 1000, 1000);
const int32 loopStartPos = Audio::convertTimeToStreamPos(loopStart, sampleRate, isStereo).totalNumberOfFrames();
const int32 loopEndPos = Audio::convertTimeToStreamPos(loopEnd, sampleRate, isStereo).totalNumberOfFrames();
const int32 loopIteration = loopEndPos - loopStartPos;
int16 *sine = 0;
Audio::SeekableAudioStream *s = createSineStream<int16>(sampleRate, time, &sine, false, isStereo);
Audio::SubLoopingAudioStream *loop = new Audio::SubLoopingAudioStream(s, 5, loopStart, loopEnd);
const int32 bufferLen = MAX<int32>(loopIteration * 3, loopEndPos);
int16 *buffer = new int16[bufferLen];
// Check parameters
TS_ASSERT_EQUALS(loop->isStereo(), isStereo);
TS_ASSERT_EQUALS(loop->getRate(), sampleRate);
TS_ASSERT_EQUALS(loop->endOfData(), false);
// Read the non-looped part + one iteration
TS_ASSERT_EQUALS(loop->readBuffer(buffer, loopEndPos), loopEndPos);
TS_ASSERT_EQUALS(memcmp(buffer, sine, loopEndPos * sizeof(int16)), 0);
TS_ASSERT_EQUALS(loop->endOfData(), false);
// We should have one full iteration now
// Read another loop iteration
TS_ASSERT_EQUALS(loop->readBuffer(buffer, loopIteration), loopIteration);
TS_ASSERT_EQUALS(memcmp(buffer, sine + loopStartPos, loopIteration * sizeof(int16)), 0);
TS_ASSERT_EQUALS(loop->endOfData(), false);
// We should have two full iterations now
// Read three loop iterations at once
TS_ASSERT_EQUALS(loop->readBuffer(buffer, loopIteration * 3), loopIteration * 3);
TS_ASSERT_EQUALS(memcmp(buffer + loopIteration * 0, sine + loopStartPos, loopIteration * sizeof(int16)), 0);
TS_ASSERT_EQUALS(memcmp(buffer + loopIteration * 1, sine + loopStartPos, loopIteration * sizeof(int16)), 0);
TS_ASSERT_EQUALS(memcmp(buffer + loopIteration * 2, sine + loopStartPos, loopIteration * sizeof(int16)), 0);
TS_ASSERT_EQUALS(loop->endOfData(), true);
// We should have five full iterations now, thus the stream should be done
// Try to read beyond the end of the stream (note this only applies, till we define that SubLoopingAudioStream should
// stop playing after the looped area).
TS_ASSERT_EQUALS(loop->readBuffer(buffer, secondLength), 0);
TS_ASSERT_EQUALS(loop->endOfData(), true);
delete[] buffer;
delete loop;
delete[] sine;
}
public:
void test_sub_looping_audio_stream_mono_11025_mid_fixed_iter() {
testSubLoopingAudioStreamFixedIter(11025, false, 2, 1);
}
void test_sub_looping_audio_stream_mono_22050_mid_fixed_iter() {
testSubLoopingAudioStreamFixedIter(22050, false, 2, 1);
}
void test_sub_looping_audio_stream_stereo_11025_mid_fixed_iter() {
testSubLoopingAudioStreamFixedIter(11025, true, 2, 1);
}
void test_sub_looping_audio_stream_stereo_22050_mid_fixed_iter() {
testSubLoopingAudioStreamFixedIter(22050, true, 2, 1);
}
void test_sub_looping_audio_stream_mono_11025_end_fixed_iter() {
testSubLoopingAudioStreamFixedIter(11025, false, 2, 2);
}
void test_sub_looping_audio_stream_mono_22050_end_fixed_iter() {
testSubLoopingAudioStreamFixedIter(22050, false, 2, 2);
}
void test_sub_looping_audio_stream_stereo_11025_end_fixed_iter() {
testSubLoopingAudioStreamFixedIter(11025, true, 2, 2);
}
void test_sub_looping_audio_stream_stereo_22050_end_fixed_iter() {
testSubLoopingAudioStreamFixedIter(22050, true, 2, 2);
}
};

68
test/audio/helper.h Normal file
View File

@@ -0,0 +1,68 @@
#ifndef TEST_SOUND_HELPER_H
#define TEST_SOUND_HELPER_H
#include "audio/decoders/raw.h"
#include "common/stream.h"
#include "common/endian.h"
#include <math.h>
#include <limits>
template<typename T>
static T *createSine(const int sampleRate, const int time) {
T *sine = (T *)malloc(sizeof(T) * time * sampleRate);
const bool isUnsigned = !std::numeric_limits<T>::is_signed;
const T xorMask = isUnsigned ? (1 << (std::numeric_limits<T>::digits - 1)) : 0;
const T maxValue = std::numeric_limits<T>::max() ^ xorMask;
for (int i = 0; i < time * sampleRate; ++i)
sine[i] = ((T)(sin((double)i / sampleRate * 2 * M_PI) * maxValue)) ^ xorMask;
return sine;
}
template<typename T>
static Audio::SeekableAudioStream *createSineStream(const int sampleRate, const int time, int16 **comp, bool le, bool isStereo) {
T *sine = createSine<T>(sampleRate, time * (isStereo ? 2 : 1));
const bool isUnsigned = !std::numeric_limits<T>::is_signed;
const T xorMask = isUnsigned ? (1 << (std::numeric_limits<T>::digits - 1)) : 0;
const bool is16Bits = (sizeof(T) == 2);
assert(sizeof(T) == 2 || sizeof(T) == 1);
const int samples = sampleRate * time * (isStereo ? 2 : 1);
if (comp) {
*comp = new int16[samples];
for (int i = 0; i < samples; ++i) {
if (is16Bits)
(*comp)[i] = sine[i] ^ xorMask;
else
(*comp)[i] = (sine[i] ^ xorMask) << 8;
}
}
if (is16Bits) {
if (le) {
for (int i = 0; i < samples; ++i)
WRITE_LE_UINT16(&sine[i], sine[i]);
} else {
for (int i = 0; i < samples; ++i)
WRITE_BE_UINT16(&sine[i], sine[i]);
}
}
Audio::SeekableAudioStream *s = 0;
Common::SeekableReadStream *sD = new Common::MemoryReadStream((const byte *)sine, sizeof(T) * samples, DisposeAfterUse::YES);
s = Audio::makeRawStream(sD, sampleRate,
(is16Bits ? Audio::FLAG_16BITS : 0)
| (isUnsigned ? Audio::FLAG_UNSIGNED : 0)
| (le ? Audio::FLAG_LITTLE_ENDIAN : 0)
| (isStereo ? Audio::FLAG_STEREO : 0));
return s;
}
#endif

291
test/audio/raw.h Normal file
View File

@@ -0,0 +1,291 @@
#include <cxxtest/TestSuite.h>
#include "audio/decoders/raw.h"
#include "audio/audiostream.h"
#include "helper.h"
class RawStreamTestSuite : public CxxTest::TestSuite
{
private:
template<typename T>
void readBufferTestTemplate(const int sampleRate, const int time, const bool le, const bool isStereo) {
int16 *sine;
Audio::SeekableAudioStream *s = createSineStream<int8>(sampleRate, time, &sine, le, isStereo);
const int totalSamples = sampleRate * time * (isStereo ? 2 : 1);
int16 *buffer = new int16[totalSamples];
TS_ASSERT_EQUALS(s->readBuffer(buffer, totalSamples), totalSamples);
TS_ASSERT_EQUALS(memcmp(sine, buffer, sizeof(int16) * totalSamples), 0);
TS_ASSERT_EQUALS(s->endOfData(), true);
delete[] sine;
delete[] buffer;
delete s;
}
public:
void test_read_buffer_8_bit_signed_mono() {
readBufferTestTemplate<int8>(11025, 2, false, false);
}
void test_read_buffer_8_bit_signed_stereo() {
readBufferTestTemplate<int8>(11025, 2, false, true);
}
void test_read_buffer_8_bit_unsigned_mono() {
readBufferTestTemplate<uint8>(11025, 2, false, false);
}
void test_read_buffer_16_bit_signed_be_mono() {
readBufferTestTemplate<int16>(11025, 2, false, false);
}
void test_read_buffer_16_bit_signed_be_stereo() {
readBufferTestTemplate<int16>(11025, 2, false, true);
}
void test_read_buffer_16_bit_unsigned_be_mono() {
readBufferTestTemplate<uint16>(11025, 2, false, false);
}
void test_read_buffer_16_bit_unsigned_be_stereo() {
readBufferTestTemplate<uint16>(11025, 2, false, true);
}
void test_read_buffer_16_bit_signed_le_mono() {
readBufferTestTemplate<int16>(11025, 2, true, false);
}
void test_read_buffer_16_bit_signed_le_stereo() {
readBufferTestTemplate<int16>(11025, 2, true, true);
}
void test_read_buffer_16_bit_unsigned_le_mono() {
readBufferTestTemplate<uint16>(11025, 2, true, false);
}
void test_read_buffer_16_bit_unsigned_le_stereo() {
readBufferTestTemplate<uint16>(11025, 2, true, true);
}
private:
void partialReadTest() {
const int sampleRate = 11025;
const int time = 4;
int16 *sine;
Audio::SeekableAudioStream *s = createSineStream<int8>(sampleRate, time, &sine, false, false);
int16 *buffer = new int16[sampleRate * time];
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate), sampleRate);
TS_ASSERT_EQUALS(memcmp(sine, buffer, sampleRate), 0);
TS_ASSERT_EQUALS(s->endOfData(), false);
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * 2), sampleRate * 2);
TS_ASSERT_EQUALS(memcmp(sine + sampleRate, buffer, sampleRate * 2), 0);
TS_ASSERT_EQUALS(s->endOfData(), false);
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate), sampleRate);
TS_ASSERT_EQUALS(memcmp(sine + sampleRate * 3, buffer, sampleRate), 0);
TS_ASSERT_EQUALS(s->endOfData(), true);
delete[] sine;
delete[] buffer;
delete s;
}
public:
void test_partial_read() {
partialReadTest();
}
private:
void readAfterEndTest() {
const int sampleRate = 11025;
const int time = 1;
Audio::SeekableAudioStream *s = createSineStream<int8>(sampleRate, time, 0, false, false);
int16 *buffer = new int16[sampleRate * time];
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * time), sampleRate * time);
TS_ASSERT_EQUALS(s->endOfData(), true);
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * time), 0);
TS_ASSERT_EQUALS(s->endOfData(), true);
delete[] buffer;
delete s;
}
public:
void test_read_after_end() {
readAfterEndTest();
}
private:
void rewindTest() {
const int sampleRate = 11025;
const int time = 2;
Audio::SeekableAudioStream *s = createSineStream<int8>(sampleRate, time, 0, false, false);
int16 *buffer = new int16[sampleRate * time];
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * time), sampleRate * time);
TS_ASSERT_EQUALS(s->endOfData(), true);
s->rewind();
TS_ASSERT_EQUALS(s->endOfData(), false);
TS_ASSERT_EQUALS(s->readBuffer(buffer, sampleRate * time), sampleRate * time);
TS_ASSERT_EQUALS(s->endOfData(), true);
delete[] buffer;
delete s;
}
public:
void test_rewind() {
rewindTest();
}
private:
void lengthTest() {
int sampleRate = 0;
const int time = 4;
Audio::SeekableAudioStream *s = 0;
// 11025 Hz tests
sampleRate = 11025;
s = createSineStream<int8>(sampleRate, time, 0, false, false);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
s = createSineStream<uint16>(sampleRate, time, 0, false, false);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
// 48000 Hz tests
sampleRate = 48000;
s = createSineStream<int8>(sampleRate, time, 0, false, false);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
s = createSineStream<uint16>(sampleRate, time, 0, true, false);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
// 11840 Hz tests
sampleRate = 11840;
s = createSineStream<int8>(sampleRate, time, 0, false, false);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
s = createSineStream<uint16>(sampleRate, time, 0, false, false);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
// 11111 Hz tests
sampleRate = 11111;
s = createSineStream<int8>(sampleRate, time, 0, false, false);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
s = createSineStream<uint16>(sampleRate, time, 0, false, false);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
// 22050 Hz stereo test
sampleRate = 22050;
s = createSineStream<int8>(sampleRate, time, 0, false, true);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
s = createSineStream<uint16>(sampleRate, time, 0, true, true);
TS_ASSERT_EQUALS(s->getLength().totalNumberOfFrames(), sampleRate * time);
delete s;
}
public:
void test_length() {
lengthTest();
}
private:
void seekTest(const int sampleRate, const int time, const bool isStereo) {
const int totalFrames = sampleRate * time * (isStereo ? 2 : 1);
int readData = 0, offset = 0;
int16 *buffer = new int16[totalFrames];
Audio::SeekableAudioStream *s = 0;
int16 *sine = 0;
s = createSineStream<int8>(sampleRate, time, &sine, false, isStereo);
// Seek to 500ms
const Audio::Timestamp a(0, 1, 2);
offset = Audio::convertTimeToStreamPos(a, sampleRate, isStereo).totalNumberOfFrames();
readData = totalFrames - offset;
TS_ASSERT_EQUALS(s->seek(a), true);
TS_ASSERT_EQUALS(s->endOfData(), false);
TS_ASSERT_EQUALS(s->readBuffer(buffer, readData), readData);
TS_ASSERT_EQUALS(memcmp(buffer, sine + offset, readData * sizeof(int16)), 0);
TS_ASSERT_EQUALS(s->endOfData(), true);
// Seek to 3/4 of a second
const Audio::Timestamp b(0, 3, 4);
offset = Audio::convertTimeToStreamPos(b, sampleRate, isStereo).totalNumberOfFrames();
readData = totalFrames - offset;
TS_ASSERT_EQUALS(s->seek(b), true);
TS_ASSERT_EQUALS(s->endOfData(), false);
TS_ASSERT_EQUALS(s->readBuffer(buffer, readData), readData);
TS_ASSERT_EQUALS(memcmp(buffer, sine + offset, readData * sizeof(int16)), 0);
TS_ASSERT_EQUALS(s->endOfData(), true);
// Seek to the start of the stream
TS_ASSERT_EQUALS(s->seek(0), true);
TS_ASSERT_EQUALS(s->endOfData(), false);
// Seek to the mid of the stream
const Audio::Timestamp c(time * 1000 / 2, 1000);
offset = Audio::convertTimeToStreamPos(c, sampleRate, isStereo).totalNumberOfFrames();
readData = totalFrames - offset;
TS_ASSERT_EQUALS(s->seek(c), true);
TS_ASSERT_EQUALS(s->endOfData(), false);
TS_ASSERT_EQUALS(s->readBuffer(buffer, readData), readData);
TS_ASSERT_EQUALS(memcmp(buffer, sine + offset, readData * sizeof(int16)), 0);
TS_ASSERT_EQUALS(s->endOfData(), true);
// Seek to the 1/4th of the last second of the stream
const Audio::Timestamp d(time - 1, 1, 4);
offset = Audio::convertTimeToStreamPos(d, sampleRate, isStereo).totalNumberOfFrames();
readData = totalFrames - offset;
TS_ASSERT_EQUALS(s->seek(d), true);
TS_ASSERT_EQUALS(s->endOfData(), false);
TS_ASSERT_EQUALS(s->readBuffer(buffer, readData), readData);
TS_ASSERT_EQUALS(memcmp(buffer, sine + offset, readData * sizeof(int16)), 0);
TS_ASSERT_EQUALS(s->endOfData(), true);
// Try to seek after the end of the stream
TS_ASSERT_EQUALS(s->seek(Audio::Timestamp(time, 1, 100000)), false);
TS_ASSERT_EQUALS(s->endOfData(), true);
// Try to seek exactly at the end of the stream
TS_ASSERT_EQUALS(s->seek(Audio::Timestamp(time * 1000, 1000)), true);
TS_ASSERT_EQUALS(s->endOfData(), true);
delete[] sine;
delete s;
delete[] buffer;
}
public:
void test_seek_mono() {
seekTest(11025, 2, false);
}
void test_seek_stereo() {
seekTest(11025, 2, true);
}
};

252
test/audio/timestamp.h Normal file
View File

@@ -0,0 +1,252 @@
#include <cxxtest/TestSuite.h>
#include "audio/timestamp.h"
class TimestampTestSuite : public CxxTest::TestSuite
{
public:
void test_diff_add_frames() {
const Audio::Timestamp a(10000, 1000);
const Audio::Timestamp b(10001, 1000);
const Audio::Timestamp c(10002, 1000);
TS_ASSERT_EQUALS(a.frameDiff(b), -1);
TS_ASSERT_EQUALS(b.frameDiff(a), 1);
TS_ASSERT_EQUALS(c.frameDiff(a), 2);
TS_ASSERT_EQUALS(b.addFrames(2000).frameDiff(a), 2001);
TS_ASSERT_EQUALS(a.frameDiff(b), -1);
TS_ASSERT_EQUALS(b.frameDiff(a), 1);
TS_ASSERT_EQUALS(c.frameDiff(a), 2);
TS_ASSERT_EQUALS(b.addFrames(2000).frameDiff(a.addFrames(-1000)), 3001);
TS_ASSERT_EQUALS(a.frameDiff(b), -1);
TS_ASSERT_EQUALS(b.frameDiff(a), 1);
TS_ASSERT_EQUALS(c.frameDiff(a), 2);
}
void test_diff_add_msecs() {
Audio::Timestamp ts0(3, 22050);
Audio::Timestamp ts1(0, 22050);
Audio::Timestamp ts2(0, 22050);
TS_ASSERT_EQUALS(ts0.msecs(), 3);
TS_ASSERT_EQUALS(ts0.totalNumberOfFrames(), 3 * 22050 / 1000);
TS_ASSERT_EQUALS(ts0.numberOfFrames(), 3 * 22050 / 1000);
ts1 = ts1.addFrames(53248);
TS_ASSERT_EQUALS(ts1.secs(), 2);
TS_ASSERT_EQUALS(ts1.msecs(), 53248 * 1000 / 22050);
TS_ASSERT_EQUALS(ts1.totalNumberOfFrames(), 53248);
TS_ASSERT_EQUALS(ts1.numberOfFrames(), 53248 - 2 * 22050);
ts1 = ts1.addMsecs(47);
TS_ASSERT_EQUALS(ts1.secs(), 2);
TS_ASSERT_EQUALS(ts1.msecs(), 2414+47);
TS_ASSERT_EQUALS(ts1.totalNumberOfFrames(), 47*22050 / 1000 + 53248);
TS_ASSERT_EQUALS(ts1.numberOfFrames(), 47*22050 / 1000 + 53248 - 2 * 22050);
ts2 = ts2.addMsecs(47);
TS_ASSERT_EQUALS(ts2.secs(), 0);
TS_ASSERT_EQUALS(ts2.msecs(), 47);
TS_ASSERT_EQUALS(ts2.totalNumberOfFrames(), 47*22050 / 1000);
TS_ASSERT_EQUALS(ts2.numberOfFrames(), 47*22050 / 1000);
ts2 = ts2.addFrames(53248);
TS_ASSERT_EQUALS(ts2.secs(), 2);
TS_ASSERT_EQUALS(ts2.msecs(), 2414+47);
TS_ASSERT_EQUALS(ts2.totalNumberOfFrames(), 47*22050 / 1000 + 53248);
TS_ASSERT_EQUALS(ts2.numberOfFrames(), 47*22050 / 1000 + 53248 - 2 * 22050);
}
void test_ticks() {
const Audio::Timestamp a(1234, 60);
const Audio::Timestamp b(5678, 60);
TS_ASSERT_EQUALS(a.msecs(), 1234);
TS_ASSERT_EQUALS(b.msecs(), 5678);
TS_ASSERT_EQUALS(a.secs(), 1);
TS_ASSERT_EQUALS(b.secs(), 5);
TS_ASSERT_EQUALS(a.msecsDiff(b), 1234 - 5678);
TS_ASSERT_EQUALS(b.msecsDiff(a), 5678 - 1234);
TS_ASSERT_EQUALS(a.frameDiff(b), (1234 - 5678) * 60 / 1000);
TS_ASSERT_EQUALS(b.frameDiff(a), (5678 - 1234) * 60 / 1000);
TS_ASSERT_EQUALS(a.addFrames(1).msecs(), (1234 + 1000 * 1/60));
TS_ASSERT_EQUALS(a.addFrames(59).msecs(), (1234 + 1000 * 59/60));
TS_ASSERT_EQUALS(a.addFrames(60).msecs(), (1234 + 1000 * 60/60));
// As soon as we go back even by only one frame, the msec value
// has to drop by at least one.
TS_ASSERT_EQUALS(a.addFrames(-1).msecs(), (1234 - 1000 * 1/60 - 1));
TS_ASSERT_EQUALS(a.addFrames(-59).msecs(), (1234 - 1000 * 59/60 - 1));
TS_ASSERT_EQUALS(a.addFrames(-60).msecs(), (1234 - 1000 * 60/60));
}
void test_more_add_diff() {
const Audio::Timestamp c(10002, 1000);
for (int i = -10000; i < 10000; i++) {
int v = c.addFrames(i).frameDiff(c);
TS_ASSERT_EQUALS(v, i);
}
}
void test_negate() {
const Audio::Timestamp a = Audio::Timestamp(0, 60).addFrames(13);
const Audio::Timestamp b = -a;
TS_ASSERT_EQUALS(a.msecs() + 1, -b.msecs());
TS_ASSERT_EQUALS(a.totalNumberOfFrames(), -b.totalNumberOfFrames());
TS_ASSERT_EQUALS(a.numberOfFrames(), 60 - b.numberOfFrames());
}
void test_add_sub() {
const Audio::Timestamp a = Audio::Timestamp(0, 60).addFrames(13);
const Audio::Timestamp b = -a;
const Audio::Timestamp c = Audio::Timestamp(0, 60).addFrames(20);
TS_ASSERT_EQUALS((a+a).secs(), 0);
TS_ASSERT_EQUALS((a+a).numberOfFrames(), 2*13);
TS_ASSERT_EQUALS((a+b).secs(), 0);
TS_ASSERT_EQUALS((a+b).numberOfFrames(), 0);
TS_ASSERT_EQUALS((a+c).secs(), 0);
TS_ASSERT_EQUALS((a+c).numberOfFrames(), 13+20);
TS_ASSERT_EQUALS((a-a).secs(), 0);
TS_ASSERT_EQUALS((a-a).numberOfFrames(), 0);
TS_ASSERT_EQUALS((a-b).secs(), 0);
TS_ASSERT_EQUALS((a-b).numberOfFrames(), 2*13);
TS_ASSERT_EQUALS((a-c).secs(), -1);
TS_ASSERT_EQUALS((a-c).numberOfFrames(), 60 + (13 - 20));
}
void test_diff_with_conversion() {
const Audio::Timestamp a = Audio::Timestamp(10, 1000).addFrames(20);
const Audio::Timestamp b = Audio::Timestamp(10, 1000/5).addFrames(20/5);
const Audio::Timestamp c = Audio::Timestamp(10, 1000*2).addFrames(20*2);
TS_ASSERT_EQUALS(a.frameDiff(a), 0);
TS_ASSERT_EQUALS(a.frameDiff(b), 0);
TS_ASSERT_EQUALS(a.frameDiff(c), 0);
TS_ASSERT_EQUALS(b.frameDiff(a), 0);
TS_ASSERT_EQUALS(b.frameDiff(b), 0);
TS_ASSERT_EQUALS(b.frameDiff(c), 0);
TS_ASSERT_EQUALS(c.frameDiff(a), 0);
TS_ASSERT_EQUALS(c.frameDiff(b), 0);
TS_ASSERT_EQUALS(c.frameDiff(c), 0);
}
void test_convert() {
const Audio::Timestamp a = Audio::Timestamp(10, 1000).addFrames(20);
const Audio::Timestamp b = Audio::Timestamp(10, 1000/5).addFrames(20/5);
const Audio::Timestamp c = Audio::Timestamp(10, 1000*2).addFrames(20*2);
TS_ASSERT_EQUALS(a.convertToFramerate(1000/5), b);
TS_ASSERT_EQUALS(a.convertToFramerate(1000*2), c);
}
void test_equals() {
const Audio::Timestamp a = Audio::Timestamp(500, 1000);
Audio::Timestamp b = Audio::Timestamp(0, 1000);
Audio::Timestamp c = Audio::Timestamp(0, 100);
TS_ASSERT_EQUALS(a, Audio::Timestamp(0, 500, 1000));
TS_ASSERT(a != b);
TS_ASSERT(a != c);
TS_ASSERT(b == c);
b = b.addFrames(500);
c = c.addFrames(50);
TS_ASSERT(a == b);
TS_ASSERT(a == c);
TS_ASSERT(b == c);
}
void test_compare() {
const Audio::Timestamp a = Audio::Timestamp(60, 1000);
Audio::Timestamp b = Audio::Timestamp(60, 60);
Audio::Timestamp c = Audio::Timestamp(60, 44100);
TS_ASSERT(a <= b);
TS_ASSERT(b <= c);
TS_ASSERT(a <= c);
TS_ASSERT(b >= a);
TS_ASSERT(c >= b);
TS_ASSERT(c >= a);
b = b.addFrames(60 / 12);
c = c.addFrames(44100 / 10);
TS_ASSERT(a < b);
TS_ASSERT(b < c);
TS_ASSERT(a < c);
TS_ASSERT(b > a);
TS_ASSERT(c > b);
TS_ASSERT(c > a);
TS_ASSERT(a <= b);
TS_ASSERT(b <= c);
TS_ASSERT(a <= c);
TS_ASSERT(b >= a);
TS_ASSERT(c >= b);
TS_ASSERT(c >= a);
}
void test_framerate() {
const Audio::Timestamp a = Audio::Timestamp(500, 1000);
const Audio::Timestamp b = Audio::Timestamp(500, 67);
const Audio::Timestamp c = Audio::Timestamp(500, 100);
const Audio::Timestamp d = Audio::Timestamp(500, 44100);
TS_ASSERT_EQUALS(a.framerate(), (uint)1000);
TS_ASSERT_EQUALS(b.framerate(), (uint)67);
TS_ASSERT_EQUALS(c.framerate(), (uint)100);
TS_ASSERT_EQUALS(d.framerate(), (uint)44100);
}
void test_direct_query() {
const Audio::Timestamp a = Audio::Timestamp(0, 22050);
const Audio::Timestamp b = a.addFrames(11025);
const Audio::Timestamp c = Audio::Timestamp(1500, 22050);
TS_ASSERT_EQUALS(a.secs(), 0);
TS_ASSERT_EQUALS(a.msecs(), 0);
TS_ASSERT_EQUALS(a.numberOfFrames(), 0);
TS_ASSERT_EQUALS(a.totalNumberOfFrames(), 0);
TS_ASSERT_EQUALS(b.secs(), 0);
TS_ASSERT_EQUALS(b.msecs(), 500);
TS_ASSERT_EQUALS(b.numberOfFrames(), 11025);
TS_ASSERT_EQUALS(b.totalNumberOfFrames(), 11025);
TS_ASSERT_EQUALS(c.secs(), 1);
TS_ASSERT_EQUALS(c.msecs(), 1500);
TS_ASSERT_EQUALS(c.numberOfFrames(), 11025);
TS_ASSERT_EQUALS(c.totalNumberOfFrames(), 33075);
}
void test_no_overflow() {
// The constructor should not overflow and give incoherent values
const Audio::Timestamp a = Audio::Timestamp(0, UINT_MAX, 1000);
int secs = UINT_MAX / 1000;
int frames = UINT_MAX % 1000;
TS_ASSERT_EQUALS(a.secs(), secs);
TS_ASSERT_EQUALS(a.numberOfFrames(), frames);
}
};

273
test/common/algorithm.h Normal file
View File

@@ -0,0 +1,273 @@
#include <cxxtest/TestSuite.h>
#include "common/util.h"
#include "common/func.h"
#include "common/algorithm.h"
#include "common/list.h"
#include "common/array.h"
#include "common/str.h"
class AlgorithmTestSuite : public CxxTest::TestSuite {
template<typename T, class StrictWeakOrdering>
bool checkSort(T first, T last, StrictWeakOrdering comp = StrictWeakOrdering()) {
if (first == last)
return true;
// Check whether the container is sorted by the given binary predicate, which
// decides whether the first value passed precedes the second value passed.
//
// To do that it checks an item and its follower in the container with the
// given predicate in reverse order, when it returns false everything is
// fine, when it returns false, the follower precedes the item and thus
// the order is violated.
for (T prev = first++; first != last; ++prev, ++first) {
if (comp(*first, *prev))
return false;
}
return true;
}
/**
* Auxiliary function to check the equality of two generic collections (A and B), from one_first to one_last.
*
* @note: It assumes that other has at least (one_last - one-first) length, starting from other_first.
*
* @param one_first: The first element of the first collection to be compared.
* @param one_last: The last element of the first collection to be compared.
* @param other_first: The first element of the collection to be compared.
* @return true if, for each index i in [one_first, one_last), A[i] == B[i], false otherwise.
*/
template<typename It>
bool checkEqual(It one_first, It one_last, It other_first) {
if (one_first == one_last)
return true;
// Check whether two containers have the same items in the same order,
// starting from some iterators one_first and other_first
//
// It iterates through the containers, comparing the elements one by one.
// If it finds a discrepancy, it returns false. Otherwise, it returns true.
for (; one_first != one_last; ++one_first, ++other_first)
if (*one_first != *other_first)
return false;
return true;
}
struct Item {
int value;
Item(int v) : value(v) {}
bool operator<(const Item &r) const {
return value < r.value;
}
};
public:
void test_check_sort() {
const int arraySorted[] = { 1, 2, 3, 3, 4, 5 };
const int arrayUnsorted[] = { 5, 3, 1, 2, 4, 3 };
TS_ASSERT_EQUALS(checkSort(arraySorted, ARRAYEND(arraySorted), Common::Less<int>()), true);
TS_ASSERT_EQUALS(checkSort(arraySorted, ARRAYEND(arraySorted), Common::Greater<int>()), false);
TS_ASSERT_EQUALS(checkSort(arrayUnsorted, ARRAYEND(arrayUnsorted), Common::Less<int>()), false);
TS_ASSERT_EQUALS(checkSort(arrayUnsorted, ARRAYEND(arrayUnsorted), Common::Greater<int>()), false);
}
void test_pod_sort() {
{
int dummy;
Common::sort(&dummy, &dummy);
TS_ASSERT_EQUALS(checkSort(&dummy, &dummy, Common::Less<int>()), true);
}
{
int array[] = { 12 };
Common::sort(array, ARRAYEND(array));
TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
// already sorted
Common::sort(array, ARRAYEND(array));
TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
}
{
int array[] = { 63, 11, 31, 72, 1, 48, 32, 69, 38, 31 };
Common::sort(array, ARRAYEND(array));
TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
int sortedArray[] = { 1, 11, 31, 31, 32, 38, 48, 63, 69, 72 };
for (size_t i = 0; i < 10; ++i)
TS_ASSERT_EQUALS(array[i], sortedArray[i]);
// already sorted
Common::sort(array, ARRAYEND(array));
TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
}
{
int array[] = { 90, 80, 70, 60, 50, 40, 30, 20, 10 };
Common::sort(array, ARRAYEND(array));
TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Less<int>()), true);
Common::sort(array, ARRAYEND(array), Common::Greater<int>());
TS_ASSERT_EQUALS(checkSort(array, ARRAYEND(array), Common::Greater<int>()), true);
}
}
void test_container_sort() {
const int n = 1000;
Common::List<Item> list;
for(int i = 0; i < n; ++i)
list.push_back(Item(i * 0xDEADBEEF % 1337));
Common::sort(list.begin(), list.end(), Common::Less<Item>());
TS_ASSERT_EQUALS(checkSort(list.begin(), list.end(), Common::Less<Item>()), true);
// already sorted
Common::sort(list.begin(), list.end());
TS_ASSERT_EQUALS(checkSort(list.begin(), list.end(), Common::Less<Item>()), true);
}
void test_string_replace() {
Common::String original = "Hello World";
Common::String expected = "Hells Wsrld";
Common::replace(original.begin(), original.end(), 'o', 's');
TS_ASSERT_EQUALS(original, expected);
}
void test_container_replace() {
Common::List<int> original;
Common::List<int> expected;
for (int i = 0; i < 6; ++i) {
original.push_back(i);
if (i == 3) {
expected.push_back(5);
} else {
expected.push_back(i);
}
}
Common::replace(original.begin(), original.end(), 3, 5);
TS_ASSERT_EQUALS(checkEqual(original.begin(), original.end(), expected.begin()), true);
}
void test_container_remove() {
{
Common::Array<int> original {1, 2, 3, 10, 4, 5};
Common::Array<int> expected {1, 2, 3, 4, 5};
Common::Array<int>::iterator r = Common::remove(original.begin(), original.end(), 10);
TS_ASSERT_EQUALS(checkEqual(original.begin(), r, expected.begin()), true);
}
{
Common::Array<int> original {1, 2, 2, 3, 4, 4, 2, 1, 0};
Common::Array<int> expected {1, 3, 4, 4, 1, 0};
Common::Array<int>::iterator r = Common::remove(original.begin(), original.end(), 2);
TS_ASSERT_EQUALS(checkEqual(original.begin(), r, expected.begin()), true);
}
{
Common::Array<int> original {0, 1, 2, 3, 0, 3, 2, 1, 0};
Common::Array<int> expected {1, 2, 3, 3, 2, 1};
Common::Array<int>::iterator r = Common::remove(original.begin(), original.end(), 0);
TS_ASSERT_EQUALS(checkEqual(original.begin(), r, expected.begin()), true);
}
}
void test_lower_bound_equal_found() {
const auto test = [](const int *first, const int *last, int value) {
const auto it = Common::lowerBound(first, last, value);
TS_ASSERT(first <= it && it < last);
TS_ASSERT_EQUALS(*it, value);
};
const int one[] = {1};
const int values[] = {1, 2, 4, 10, 50, 100, 900, 1000};
test(one, one + ARRAYSIZE(one), 1);
test(values, values + ARRAYSIZE(values), 1);
test(values, values + ARRAYSIZE(values), 1000);
test(values, values + ARRAYSIZE(values), 4);
}
void test_lower_bound_greater_found() {
const auto test = [](const int *first, const int *last, int value, int expected) {
const auto it = Common::lowerBound(first, last, value);
TS_ASSERT(first <= it && it < last);
TS_ASSERT_EQUALS(*it, expected);
};
const int one[] = {1};
const int values[] = {2, 3, 4, 10, 50, 100, 900, 1000};
test(one, one + ARRAYSIZE(one), 0, 1);
test(values, values + ARRAYSIZE(values), 1, 2);
test(values, values + ARRAYSIZE(values), 950, 1000);
test(values, values + ARRAYSIZE(values), 20, 50);
}
void test_lower_bound_element_nothing_found() {
const int values[] = {1, 2, 3, 6, 8, 10, 20, 50};
const auto last = values + ARRAYSIZE(values);
const auto it = Common::lowerBound(values, last, 100);
TS_ASSERT_EQUALS(it, last);
}
void test_lower_bound_empty_input() {
{
const int values[] = {1};
const auto last = values + ARRAYSIZE(values);
const auto it = Common::lowerBound(last, last, 1);
TS_ASSERT_EQUALS(it, last);
}
{
const auto it = Common::lowerBound((int *)nullptr, (int *)nullptr, 1);
TS_ASSERT_EQUALS(it, nullptr);
}
}
void test_upper_bound_element_found() {
const auto test = [](const int *first, const int *last, int value, int expected) {
const auto it = Common::upperBound(first, last, value);
TS_ASSERT(first <= it && it < last);
TS_ASSERT_EQUALS(*it, expected);
};
const int one[] = {1};
const int values[] = {2, 3, 4, 10, 50, 100, 900, 1000};
test(one, one + ARRAYSIZE(one), 0, 1);
test(values, values + ARRAYSIZE(values), 1, 2);
test(values, values + ARRAYSIZE(values), 950, 1000);
test(values, values + ARRAYSIZE(values), 20, 50);
}
void test_upper_bound_nothing_found() {
const int values[] = {1, 2, 3, 6, 8, 10, 20, 50};
const auto last = values + ARRAYSIZE(values);
{
const auto it = Common::upperBound(values, last, 50);
TS_ASSERT_EQUALS(it, last);
}
{
const auto it = Common::upperBound(values, last, 100);
TS_ASSERT_EQUALS(it, last);
}
}
void test_upper_bound_empty_input() {
{
const int values[] = {1};
const auto last = values + ARRAYSIZE(values);
const auto it = Common::upperBound(last, last, 1);
TS_ASSERT_EQUALS(it, last);
}
{
const auto it = Common::upperBound((int *)nullptr, (int *)nullptr, 1);
TS_ASSERT_EQUALS(it, nullptr);
}
}
};

617
test/common/array.h Normal file
View File

@@ -0,0 +1,617 @@
#include <cxxtest/TestSuite.h>
#include "common/array.h"
#include "common/noncopyable.h"
#include "common/str.h"
struct ArrayTestMovable {
ArrayTestMovable() : _value(0), _wasMoveConstructed(false), _wasMovedFrom(false) {}
explicit ArrayTestMovable(int value) : _value(value), _wasMoveConstructed(false), _wasMovedFrom(false) {}
ArrayTestMovable(const ArrayTestMovable &other)
: _value(other._value), _wasMoveConstructed(false), _wasMovedFrom(false) {
}
ArrayTestMovable(ArrayTestMovable &&other) noexcept
: _value(other._value), _wasMoveConstructed(true), _wasMovedFrom(false) {
other._wasMovedFrom = true;
}
int _value;
bool _wasMoveConstructed;
bool _wasMovedFrom;
};
// Hopefully temporary until Common::Pair can be updated to have move constructor/assign operator
struct ArrayTestMovablePair {
ArrayTestMovablePair(ArrayTestMovable &&pFirst, ArrayTestMovable &&pSecond)
: first(Common::move(pFirst)), second(Common::move(pSecond)) {
}
ArrayTestMovablePair(const ArrayTestMovable &&pFirst, const ArrayTestMovable &&pSecond)
: first(pFirst), second(pSecond) {
}
ArrayTestMovable first;
ArrayTestMovable second;
};
class ArrayTestSuite : public CxxTest::TestSuite
{
public:
void test_empty_clear() {
Common::Array<int> array;
TS_ASSERT(array.empty());
array.push_back(17);
array.push_back(33);
TS_ASSERT(!array.empty());
array.clear();
TS_ASSERT(array.empty());
}
void test_iterator() {
Common::Array<int> array;
Common::Array<int>::iterator iter;
// Fill the array with some random data
array.push_back(17);
array.push_back(33);
array.push_back(-11);
// Iterate over the array and verify that we encounter the elements in
// the order we expect them to be.
iter = array.begin();
TS_ASSERT_EQUALS(*iter, 17);
++iter;
TS_ASSERT_DIFFERS(iter, array.end());
TS_ASSERT_EQUALS(*iter, 33);
++iter;
TS_ASSERT_DIFFERS(iter, array.end());
// Also test the postinc
TS_ASSERT_EQUALS(*iter, -11);
iter++;
TS_ASSERT_EQUALS(iter, array.end());
}
void test_erase_iterator() {
Common::Array<int> array;
Common::Array<int>::iterator iter;
// Fill the array with some random data
array.push_back(17);
array.push_back(33);
array.push_back(-11);
iter = array.begin();
++iter;
iter = array.erase(iter);
TS_ASSERT_DIFFERS(iter, array.end());
TS_ASSERT_EQUALS(*iter, -11);
TS_ASSERT_EQUALS(array.size(), (unsigned int)2);
TS_ASSERT_EQUALS(array[0], 17);
TS_ASSERT_EQUALS(array[1], -11);
}
void test_erase_iterator_range() {
Common::Array<int> array;
Common::Array<int>::iterator first, last;
// Fill the array with some random data
array.push_back(17);
array.push_back(33);
array.push_back(66);
array.push_back(99);
array.push_back(-11);
first = array.begin();
++first;
last = array.end();
--last;
first = array.erase(first, last);
TS_ASSERT_DIFFERS(first, array.end());
TS_ASSERT_EQUALS(*first, -11);
TS_ASSERT_EQUALS(array.size(), (unsigned int)2);
TS_ASSERT_EQUALS(array[0], 17);
TS_ASSERT_EQUALS(array[1], -11);
}
void test_insert_iterator() {
Common::Array<int> array;
Common::Array<int>::iterator iter;
// Fill the array with some random data
array.push_back(17);
array.push_back(33);
array.push_back(-11);
iter = array.begin();
++iter;
array.insert(iter, 99);
TS_ASSERT_EQUALS(*iter, 99);
TS_ASSERT_EQUALS(array.size(), (unsigned int)4);
TS_ASSERT_EQUALS(array[0], 17);
TS_ASSERT_EQUALS(array[1], 99);
TS_ASSERT_EQUALS(array[2], 33);
TS_ASSERT_EQUALS(array[3], -11);
}
void test_direct_access() {
Common::Array<int> array;
// Fill the array with some random data
array.push_back(17);
array.push_back(33);
array.push_back(-11);
TS_ASSERT_EQUALS(array[0], 17);
TS_ASSERT_EQUALS(array[1], 33);
TS_ASSERT_EQUALS(array[2], -11);
}
void test_insert_at() {
Common::Array<int> array;
// First of all some data
array.push_back(-12);
array.push_back(17);
array.push_back(25);
array.push_back(-11);
// Insert some data
array.insert_at(2, 33);
TS_ASSERT_EQUALS(array[0], -12);
TS_ASSERT_EQUALS(array[1], 17);
TS_ASSERT_EQUALS(array[2], 33);
TS_ASSERT_EQUALS(array[3], 25);
TS_ASSERT_EQUALS(array[4], -11);
TS_ASSERT_EQUALS(array.size(), (unsigned int)5);
}
void test_insert_at_array() {
Common::Array<int> array;
Common::Array<int> array2;
// First of all some data
array.push_back(-12);
array.push_back(17);
array.push_back(25);
array.push_back(-11);
array2.push_back(42);
array2.push_back(105);
array2.push_back(-1);
// Insert some data
array.insert_at(2, array2);
TS_ASSERT_EQUALS(array.size(), (unsigned int)7);
TS_ASSERT_EQUALS(array[0], -12);
TS_ASSERT_EQUALS(array[1], 17);
TS_ASSERT_EQUALS(array[2], 42);
TS_ASSERT_EQUALS(array[3], 105);
TS_ASSERT_EQUALS(array[4], -1);
TS_ASSERT_EQUALS(array[5], 25);
TS_ASSERT_EQUALS(array[6], -11);
}
void test_self_insert() {
Common::Array<int> array;
int i;
// Insert some data -- and make sure we have enough space for
// *twice* as much data. This way, there is no need to allocate
// new storage, so if the insert() operation is "clever", it
// will try to reuse the existing storage.
// This in turn may uncover bugs if the insertion code does not
// expect self-insertions.
array.reserve(128);
for (i = 0; i < 64; ++i)
array.push_back(i);
// Now insert the array into the middle of itself
array.insert_at(12, array);
// Verify integrity
TS_ASSERT_EQUALS(array.size(), 128UL);
for (i = 0; i < 12; ++i)
TS_ASSERT_EQUALS(array[i], i);
for (i = 0; i < 64; ++i)
TS_ASSERT_EQUALS(array[i+12], i);
for (i = 12; i < 64; ++i)
TS_ASSERT_EQUALS(array[i+64], i);
}
void test_remove_at() {
Common::Array<int> array;
// First of all some data
array.push_back(-12);
array.push_back(17);
array.push_back(33);
array.push_back(25);
array.push_back(-11);
// Remove some data
array.remove_at(1);
TS_ASSERT_EQUALS(array[0], -12);
TS_ASSERT_EQUALS(array[1], 33);
TS_ASSERT_EQUALS(array[2], 25);
TS_ASSERT_EQUALS(array[3], -11);
TS_ASSERT_EQUALS(array.size(), (unsigned int)4);
}
void test_push_back() {
Common::Array<int> array1, array2;
// Some data for both
array1.push_back(-3);
array1.push_back(5);
array1.push_back(9);
array2.push_back(3);
array2.push_back(-2);
array2.push_back(-131);
array1.push_back(array2);
TS_ASSERT_EQUALS(array1[0], -3);
TS_ASSERT_EQUALS(array1[1], 5);
TS_ASSERT_EQUALS(array1[2], 9);
TS_ASSERT_EQUALS(array1[3], 3);
TS_ASSERT_EQUALS(array1[4], -2);
TS_ASSERT_EQUALS(array1[5], -131);
TS_ASSERT_EQUALS(array1.size(), (unsigned int)6);
TS_ASSERT_EQUALS(array2.size(), (unsigned int)3);
}
struct SafeInt {
int val;
SafeInt() : val(0) {}
SafeInt(int v) : val(v) {}
~SafeInt() { val = -1; }
bool operator==(int v) {
return val == v;
}
};
void test_push_back_ex() {
// This test makes sure that inserting an element invalidates
// references/iterators/pointers to elements in the array itself
// only *after* their value has been copied.
Common::Array<SafeInt> array;
array.push_back(42);
for (int i = 0; i < 40; ++i) {
array.push_back(array[0]);
TS_ASSERT_EQUALS(array[i], 42);
}
}
void test_copy_constructor() {
Common::Array<int> array1;
// Some data for both
array1.push_back(-3);
array1.push_back(5);
array1.push_back(9);
Common::Array<int> array2(array1);
// Alter the original array
array1[0] = 7;
array1[1] = -5;
array1[2] = 2;
TS_ASSERT_EQUALS(array2[0], -3);
TS_ASSERT_EQUALS(array2[1], 5);
TS_ASSERT_EQUALS(array2[2], 9);
TS_ASSERT_EQUALS(array2.size(), (unsigned int)3);
}
void test_equals() {
Common::Array<int> array1;
// Some data for both
array1.push_back(-3);
array1.push_back(5);
array1.push_back(9);
Common::Array<int> array2(array1);
TS_ASSERT(array1 == array2);
array1.push_back(42);
TS_ASSERT(array1 != array2);
array2.push_back(42);
TS_ASSERT(array1 == array2);
}
void test_array_constructor() {
const int array1[] = { -3, 5, 9 };
Common::Array<int> array2(array1, 3);
TS_ASSERT_EQUALS(array2[0], -3);
TS_ASSERT_EQUALS(array2[1], 5);
TS_ASSERT_EQUALS(array2[2], 9);
TS_ASSERT_EQUALS(array2.size(), (unsigned int)3);
}
class Copyable {
bool _copied;
int _value;
Copyable &operator=(Copyable &);
public:
Copyable() : _copied(false), _value(1) {}
explicit Copyable(const int v) : _copied(false), _value(v) {}
Copyable(const Copyable &other) : _copied(true), _value(other._value) {}
bool copied() const { return _copied; }
int value() const { return _value; }
};
void test_array_constructor_count() {
Common::Array<int> array(10);
TS_ASSERT_EQUALS(array.size(), 10U);
TS_ASSERT_EQUALS(array[0], 0);
TS_ASSERT_EQUALS(array[9], 0);
// This will fail at compile time if it is not possible to construct an
// array without copy-construction
Common::Array<Common::NonCopyable> nonCopyable(1);
}
void test_array_constructor_list() {
Common::Array<int> array = {1, 42, 255};
TS_ASSERT_EQUALS(array.size(), 3U);
TS_ASSERT_EQUALS(array[0], 1);
TS_ASSERT_EQUALS(array[1], 42);
TS_ASSERT_EQUALS(array[2], 255);
}
void test_array_constructor_count_copy_value() {
Common::Array<int> trivial(5, 1);
TS_ASSERT_EQUALS(trivial.size(), 5U);
TS_ASSERT_EQUALS(trivial[0], 1);
TS_ASSERT_EQUALS(trivial[4], 1);
Copyable c(123);
typedef Common::Array<Copyable> NonTrivialArray;
NonTrivialArray nonTrivialCopy(3, c);
TS_ASSERT_EQUALS(nonTrivialCopy.size(), 3U);
for (NonTrivialArray::size_type i = 0; i < nonTrivialCopy.size(); ++i) {
TS_ASSERT_EQUALS(nonTrivialCopy[0].value(), 123);
TS_ASSERT(nonTrivialCopy[0].copied());
}
NonTrivialArray nonTrivialDefault(3);
TS_ASSERT_EQUALS(nonTrivialDefault.size(), 3U);
for (NonTrivialArray::size_type i = 0; i < nonTrivialDefault.size(); ++i) {
TS_ASSERT_EQUALS(nonTrivialDefault[0].value(), 1);
TS_ASSERT(!nonTrivialDefault[0].copied());
}
}
void test_array_constructor_str() {
const char *array1[] = { "a", "b", "c" };
Common::Array<Common::String> array2(array1, 3);
TS_ASSERT_EQUALS(array2[0], "a");
TS_ASSERT_EQUALS(array2[1], "b");
TS_ASSERT_EQUALS(array2[2], "c");
TS_ASSERT_EQUALS(array2.size(), (unsigned int)3);
}
void test_data() {
Common::Array<int> array;
TS_ASSERT(array.data() == nullptr);
array.resize(2);
TS_ASSERT(array.data() != nullptr);
TS_ASSERT_EQUALS(array.data(), &array.front());
TS_ASSERT_EQUALS(array.data() + array.size() - 1, &array.back());
}
void test_front_back_push_pop() {
Common::Array<int> container;
container.push_back( 42);
container.push_back(-23);
TS_ASSERT_EQUALS(container.front(), 42);
TS_ASSERT_EQUALS(container.back(), -23);
container.front() = -17;
container.back() = 163;
TS_ASSERT_EQUALS(container.front(), -17);
TS_ASSERT_EQUALS(container.back(), 163);
container.pop_back();
TS_ASSERT_EQUALS(container.front(), -17);
TS_ASSERT_EQUALS(container.back(), -17);
}
void test_resize() {
Common::Array<int> array;
array.resize(3);
TS_ASSERT_EQUALS(array.size(), (unsigned int)3);
array[0] = -3;
array[1] = 163;
array[2] = 17;
array.resize(100);
TS_ASSERT_EQUALS(array.size(), (unsigned int)100);
TS_ASSERT_EQUALS(array[0], -3);
TS_ASSERT_EQUALS(array[1], 163);
TS_ASSERT_EQUALS(array[2], 17);
TS_ASSERT_EQUALS(array[99], 0);
array.resize(2);
TS_ASSERT_EQUALS(array.size(), (unsigned int)2);
TS_ASSERT_EQUALS(array[0], -3);
TS_ASSERT_EQUALS(array[1], 163);
array.resize(4, 42);
TS_ASSERT_EQUALS(array.size(), (unsigned int)4);
TS_ASSERT_EQUALS(array[0], -3);
TS_ASSERT_EQUALS(array[1], 163);
TS_ASSERT_EQUALS(array[2], 42);
TS_ASSERT_EQUALS(array[3], 42);
array.resize(2, 42);
TS_ASSERT_EQUALS(array.size(), (unsigned int)2);
TS_ASSERT_EQUALS(array[0], -3);
TS_ASSERT_EQUALS(array[1], 163);
}
void test_swap() {
Common::Array<int> array1, array2;
array1.push_back(-3);
array1.push_back(163);
array1.push_back(17);
array2.push_back(5);
array2.push_back(9);
TS_ASSERT_EQUALS(array1.size(), 3u);
TS_ASSERT_EQUALS(array1[0], -3);
TS_ASSERT_EQUALS(array1[1], 163);
TS_ASSERT_EQUALS(array1[2], 17);
TS_ASSERT_EQUALS(array2.size(), 2u);
TS_ASSERT_EQUALS(array2[0], 5);
TS_ASSERT_EQUALS(array2[1], 9);
array1.swap(array2);
TS_ASSERT_EQUALS(array1.size(), 2u);
TS_ASSERT_EQUALS(array1[0], 5);
TS_ASSERT_EQUALS(array1[1], 9);
TS_ASSERT_EQUALS(array2.size(), 3u);
TS_ASSERT_EQUALS(array2[0], -3);
TS_ASSERT_EQUALS(array2[1], 163);
TS_ASSERT_EQUALS(array2[2], 17);
}
};
struct ListElement {
int value;
int tag;
ListElement(int v, int t = 0) : value(v), tag(t) {}
};
static int compareInts(const void *a, const void *b) {
return ((const ListElement *)a)->value - ((const ListElement *)b)->value;
}
class SortedArrayTestSuite : public CxxTest::TestSuite {
public:
void test_insert() {
Common::SortedArray<ListElement *> container(compareInts);
Common::SortedArray<ListElement *>::iterator iter;
// Fill the container with some random data
container.insert(new ListElement(1));
container.insert(new ListElement(7));
container.insert(new ListElement(8));
container.insert(new ListElement(3));
container.insert(new ListElement(5));
container.insert(new ListElement(4));
container.insert(new ListElement(9));
container.insert(new ListElement(2));
container.insert(new ListElement(6));
// Verify contents are correct
iter = container.begin();
for (int i = 1; i < 10; i++) {
TS_ASSERT_EQUALS((*iter)->value, i);
++iter;
}
TS_ASSERT_EQUALS(iter, container.end());
// Cleanup
for(iter = container.begin(); iter != container.end(); iter++) {
delete *iter;
}
}
void test_stability() {
Common::SortedArray<ListElement *> container(compareInts);
Common::SortedArray<ListElement *>::iterator iter;
// Check stability, using duplicate keys and sequential tags.
container.insert(new ListElement(1, 3));
container.insert(new ListElement(0, 1));
container.insert(new ListElement(4, 8));
container.insert(new ListElement(1, 4));
container.insert(new ListElement(0, 2));
container.insert(new ListElement(2, 6));
container.insert(new ListElement(1, 5));
container.insert(new ListElement(3, 7));
container.insert(new ListElement(4, 9));
// Verify contents are correct
iter = container.begin();
for (int i = 1; i < 10; i++) {
TS_ASSERT_EQUALS((*iter)->tag, i);
++iter;
}
TS_ASSERT_EQUALS(iter, container.end());
// Cleanup
for(iter = container.begin(); iter != container.end(); iter++) {
delete *iter;
}
}
void test_emplace() {
Common::Array<ArrayTestMovablePair> movablePairArray;
movablePairArray.emplace_back(ArrayTestMovable(1), ArrayTestMovable(2));
TS_ASSERT(movablePairArray[0].first._wasMoveConstructed);
TS_ASSERT_EQUALS(movablePairArray[0].first._value, 1);
TS_ASSERT(movablePairArray[0].second._wasMoveConstructed);
TS_ASSERT_EQUALS(movablePairArray[0].second._value, 2);
}
void test_push_back_move() {
ArrayTestMovable movable(3);
Common::Array<ArrayTestMovable> movableArray;
movableArray.push_back(Common::move(movable));
TS_ASSERT(movable._wasMovedFrom);
TS_ASSERT_EQUALS(movableArray[0]._value, 3);
TS_ASSERT(movableArray[0]._wasMoveConstructed);
}
};

128
test/common/base64.h Normal file
View File

@@ -0,0 +1,128 @@
#include <cxxtest/TestSuite.h>
#include "common/base64.h"
#include "common/memstream.h"
static const char *base64_test_string[] = {
"",
"a",
"abc",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
("12345678901234567890123456789012345678901234567890123456789012"
"345678901234567890")
};
static const char *base64_test_encoded[] = {
"",
"YQ==",
"YWJj",
"YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=",
("QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdH"
"V2d3h5ejAxMjM0NTY3ODk="),
("MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Nj"
"c4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTA=")
};
static const char *base64_validate_tests[] = {
"YQ", // missing padding
"!@#$", // characters not in encoding table
"YQ==YWJj", // data after padding
};
#include "common/pack-start.h" // START STRUCT PACKING
struct Base64TestStruct {
uint32 x;
byte y;
uint16 z;
uint32 a;
byte b;
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
class Base64TestSuite : public CxxTest::TestSuite {
public:
void test_b64Validate() {
for (int i = 0; i < 6; i++) {
Common::String encoded = base64_test_encoded[i];
// All of these should return true.
TS_ASSERT_EQUALS(Common::b64Validate(encoded), true);
}
for (int i = 0; i < 3; i++) {
Common::String encoded = base64_validate_tests[i];
// All of these should return false.
TS_ASSERT_EQUALS(Common::b64Validate(encoded), false);
}
}
void test_b64EncodeString() {
for (int i = 0; i < 6; i++) {
Common::String string = base64_test_string[i];
Common::String encoded = Common::b64EncodeString(string);
TS_ASSERT_EQUALS(encoded, base64_test_encoded[i]);
}
}
void test_b64EncodeStream() {
for (int i = 0; i < 6; i++) {
Common::MemoryReadStream stream((const byte *)base64_test_string[i], strlen(base64_test_string[i]));
Common::String encoded = Common::b64EncodeStream(stream);
TS_ASSERT_EQUALS(encoded, base64_test_encoded[i]);
}
}
void test_b64EncodeData() {
Base64TestStruct *test = new Base64TestStruct();
test->x = TO_LE_32(1);
test->y = 2;
test->z = TO_LE_16(3);
test->a = TO_LE_32(4);
test->b = 5;
Common::String encoded = Common::b64EncodeData(test, sizeof(Base64TestStruct));
TS_ASSERT_EQUALS(encoded, "AQAAAAIDAAQAAAAF");
delete test;
}
void test_b64DecodeString() {
for (int i = 0; i < 6; i++) {
Common::String encoded = base64_test_encoded[i];
Common::String string = Common::b64DecodeString(encoded);
TS_ASSERT_EQUALS(string, base64_test_string[i]);
}
}
void test_b64DecodeStream() {
for (int i = 0; i < 6; i++) {
Common::String encoded = base64_test_encoded[i];
Common::MemoryReadStream *stream = Common::b64DecodeStream(encoded, strlen(base64_test_string[i]));
TS_ASSERT_EQUALS(stream->size(), (int64)strlen(base64_test_string[i]));
char *data = (char *)malloc(stream->size());
stream->read(data, stream->size());
delete stream;
Common::String string(data, strlen(base64_test_string[i]));
TS_ASSERT_EQUALS(string, base64_test_string[i]);
free(data);
}
}
void test_b64DecodeData() {
Base64TestStruct *test = new Base64TestStruct();
Common::String encoded = "AQAAAAIDAAQAAAAF";
bool success = Common::b64DecodeData(encoded, test);
TS_ASSERT_EQUALS(success, true);
TS_ASSERT_EQUALS(FROM_LE_32(test->x), 1u);
TS_ASSERT_EQUALS(test->y, 2u);
TS_ASSERT_EQUALS(FROM_LE_16(test->z), 3u);
TS_ASSERT_EQUALS(FROM_LE_32(test->a), 4u);
TS_ASSERT_EQUALS(test->b, 5u);
delete test;
}
};

258
test/common/bitstream.h Normal file
View File

@@ -0,0 +1,258 @@
#include <cxxtest/TestSuite.h>
#include "common/bitstream.h"
#include "common/memstream.h"
class BitStreamTestSuite : public CxxTest::TestSuite
{
private:
template<class MS, class BS>
void tmpl_get_bit() {
byte contents[] = { 'a' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT_EQUALS(bs.getBit(), 0u);
TS_ASSERT_EQUALS(bs.getBit(), 1u);
TS_ASSERT_EQUALS(bs.getBit(), 1u);
TS_ASSERT_EQUALS(bs.pos(), 3u);
TS_ASSERT(!bs.eos());
}
public:
void test_get_bit() {
tmpl_get_bit<Common::MemoryReadStream, Common::BitStream8MSB>();
tmpl_get_bit<Common::BitStreamMemoryStream, Common::BitStreamMemory8MSB>();
}
private:
template<class MS, class BS>
void tmpl_get_bits() {
byte contents[] = { 'a', 'b' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT_EQUALS(bs.getBits(3), 3u);
TS_ASSERT_EQUALS(bs.pos(), 3u);
TS_ASSERT_EQUALS(bs.getBits(8), 11u);
TS_ASSERT_EQUALS(bs.pos(), 11u);
TS_ASSERT(!bs.eos());
}
public:
void test_get_bits() {
tmpl_get_bits<Common::MemoryReadStream, Common::BitStream8MSB>();
tmpl_get_bits<Common::BitStreamMemoryStream, Common::BitStreamMemory8MSB>();
}
private:
template<class MS, class BS>
void tmpl_skip() {
byte contents[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
bs.skip(5);
TS_ASSERT_EQUALS(bs.pos(), 5u);
bs.skip(4);
TS_ASSERT_EQUALS(bs.pos(), 9u);
TS_ASSERT_EQUALS(bs.getBits(3), 6u);
bs.skip(65);
TS_ASSERT_EQUALS(bs.pos(), 77u);
TS_ASSERT(!bs.eos());
}
public:
void test_skip() {
tmpl_skip<Common::MemoryReadStream, Common::BitStream8MSB>();
tmpl_skip<Common::BitStreamMemoryStream, Common::BitStreamMemory8MSB>();
}
private:
template<class MS, class BS>
void tmpl_rewind() {
byte contents[] = { 'a' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
bs.skip(5);
TS_ASSERT_EQUALS(bs.pos(), 5u);
bs.rewind();
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT_EQUALS(bs.getBits(3), 3u);
TS_ASSERT(!bs.eos());
TS_ASSERT_EQUALS(bs.size(), 8u);
}
public:
void test_rewind() {
tmpl_rewind<Common::MemoryReadStream, Common::BitStream8MSB>();
tmpl_rewind<Common::BitStreamMemoryStream, Common::BitStreamMemory8MSB>();
}
private:
template<class MS, class BS>
void tmpl_peek_bit() {
byte contents[] = { 'a' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT_EQUALS(bs.peekBit(), 0u);
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT_EQUALS(bs.getBit(), 0u);
TS_ASSERT_EQUALS(bs.pos(), 1u);
TS_ASSERT_EQUALS(bs.peekBit(), 1u);
TS_ASSERT_EQUALS(bs.pos(), 1u);
TS_ASSERT(!bs.eos());
}
public:
void test_peek_bit() {
tmpl_peek_bit<Common::MemoryReadStream, Common::BitStream8MSB>();
tmpl_peek_bit<Common::BitStreamMemoryStream, Common::BitStreamMemory8MSB>();
}
private:
template<class MS, class BS>
void tmpl_peek_bits() {
byte contents[] = { 'a', 'b' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT_EQUALS(bs.peekBits(3), 3u);
TS_ASSERT_EQUALS(bs.pos(), 0u);
bs.skip(3);
TS_ASSERT_EQUALS(bs.pos(), 3u);
TS_ASSERT_EQUALS(bs.peekBits(8), 11u);
TS_ASSERT_EQUALS(bs.pos(), 3u);
bs.skip(8);
TS_ASSERT_EQUALS(bs.pos(), 11u);
TS_ASSERT_EQUALS(bs.peekBits(6), 4u);
TS_ASSERT(!bs.eos());
}
public:
void test_peek_bits() {
tmpl_peek_bits<Common::MemoryReadStream, Common::BitStream8MSB>();
tmpl_peek_bits<Common::BitStreamMemoryStream, Common::BitStreamMemory8MSB>();
}
private:
template<class MS, class BS>
void tmpl_eos() {
byte contents[] = { 'a', 'b' };
MS ms(contents, sizeof(contents));
BS bs(ms);
bs.skip(11);
TS_ASSERT_EQUALS(bs.pos(), 11u);
TS_ASSERT_EQUALS(bs.getBits(5), 2u);
TS_ASSERT(bs.eos());
bs.rewind();
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT(!bs.eos());
}
public:
void test_eos() {
tmpl_eos<Common::MemoryReadStream, Common::BitStream8MSB>();
tmpl_eos<Common::BitStreamMemoryStream, Common::BitStreamMemory8MSB>();
}
private:
template<class MS, class BS>
void tmpl_get_bits_lsb() {
byte contents[] = { 'a', 'b' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT_EQUALS(bs.getBits(3), 1u);
TS_ASSERT_EQUALS(bs.pos(), 3u);
TS_ASSERT_EQUALS(bs.getBits(8), 76u);
TS_ASSERT_EQUALS(bs.pos(), 11u);
TS_ASSERT(!bs.eos());
}
public:
void test_get_bits_lsb() {
tmpl_get_bits_lsb<Common::MemoryReadStream, Common::BitStream8LSB>();
tmpl_get_bits_lsb<Common::BitStreamMemoryStream, Common::BitStreamMemory8LSB>();
}
private:
template<class MS, class BS>
void tmpl_peek_bits_lsb() {
byte contents[] = { 'a', 'b' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
TS_ASSERT_EQUALS(bs.peekBits(3), 1u);
TS_ASSERT_EQUALS(bs.pos(), 0u);
bs.skip(3);
TS_ASSERT_EQUALS(bs.pos(), 3u);
TS_ASSERT_EQUALS(bs.peekBits(8), 76u);
TS_ASSERT_EQUALS(bs.pos(), 3u);
bs.skip(8);
TS_ASSERT_EQUALS(bs.pos(), 11u);
TS_ASSERT_EQUALS(bs.peekBits(20), 12u);
TS_ASSERT(!bs.eos());
}
public:
void test_peek_bits_lsb() {
tmpl_peek_bits_lsb<Common::MemoryReadStream, Common::BitStream8LSB>();
tmpl_peek_bits_lsb<Common::BitStreamMemoryStream, Common::BitStreamMemory8LSB>();
}
private:
template<class MS, class BS>
void tmpl_align() {
byte contents[] = { 'a', 'b' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
bs.align();
TS_ASSERT_EQUALS(bs.pos(), 0u);
bs.skip(3);
bs.align();
TS_ASSERT_EQUALS(bs.pos(), 8u);
}
public:
void test_align() {
tmpl_align<Common::MemoryReadStream, Common::BitStream8LSB>();
tmpl_align<Common::BitStreamMemoryStream, Common::BitStreamMemory8LSB>();
}
private:
template<class MS, class BS>
void tmpl_align_16() {
byte contents[] = { 'a', 'b' };
MS ms(contents, sizeof(contents));
BS bs(ms);
TS_ASSERT_EQUALS(bs.pos(), 0u);
bs.align();
TS_ASSERT_EQUALS(bs.pos(), 0u);
bs.skip(3);
bs.align();
TS_ASSERT_EQUALS(bs.pos(), 16u);
}
public:
void test_align_16() {
tmpl_align_16<Common::MemoryReadStream, Common::BitStream16BELSB>();
tmpl_align_16<Common::BitStreamMemoryStream, Common::BitStreamMemory16BELSB>();
}
};

View File

@@ -0,0 +1,60 @@
#include <cxxtest/TestSuite.h>
#include "common/memstream.h"
#include "common/bufferedstream.h"
class BufferedReadStreamTestSuite : public CxxTest::TestSuite {
public:
void test_traverse() {
byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Common::MemoryReadStream ms(contents, 10);
// Use a buffer size of 4 -- note that 10 % 4 != 0,
// so we test what happens if the cache can't be completely
// refilled.
Common::ReadStream &srs = *Common::wrapBufferedReadStream(&ms, 4, DisposeAfterUse::NO);
byte i, b;
for (i = 0; i < 10; ++i) {
TS_ASSERT(!srs.eos());
b = srs.readByte();
TS_ASSERT_EQUALS(i, b);
}
TS_ASSERT(!srs.eos());
b = srs.readByte();
TS_ASSERT(srs.eos());
delete &srs;
}
void test_traverse2() {
byte contents[9] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
Common::MemoryReadStream ms(contents, 9);
Common::ReadStream &brs = *Common::wrapBufferedReadStream(&ms, 4, DisposeAfterUse::NO);
// Traverse the stream with reads of 2 bytes. The size is not
// a multiple of 2, so we can test the final partial read.
byte i, b[2];
for (i = 0; i < 4; ++i) {
TS_ASSERT(!brs.eos());
int n = brs.read(b, 2);
TS_ASSERT_EQUALS(n, 2);
}
TS_ASSERT(!brs.eos());
int n = brs.read(b, 2);
TS_ASSERT_EQUALS(n, 1);
TS_ASSERT(brs.eos());
delete &brs;
}
};

View File

@@ -0,0 +1,94 @@
#include <cxxtest/TestSuite.h>
#include "common/memstream.h"
#include "common/bufferedstream.h"
class BufferedSeekableReadStreamTestSuite : public CxxTest::TestSuite {
public:
void test_traverse() {
byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Common::MemoryReadStream ms(contents, 10);
Common::SeekableReadStream &ssrs
= *Common::wrapBufferedSeekableReadStream(&ms, 4, DisposeAfterUse::NO);
byte i, b;
for (i = 0; i < 10; ++i) {
TS_ASSERT(!ssrs.eos());
TS_ASSERT_EQUALS(i, ssrs.pos());
ssrs.read(&b, 1);
TS_ASSERT_EQUALS(i, b);
}
TS_ASSERT(!ssrs.eos());
TS_ASSERT_EQUALS((uint)0, ssrs.read(&b, 1));
TS_ASSERT(ssrs.eos());
delete &ssrs;
}
void test_seek() {
byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Common::MemoryReadStream ms(contents, 10);
Common::SeekableReadStream &ssrs
= *Common::wrapBufferedSeekableReadStream(&ms, 4, DisposeAfterUse::NO);
byte b;
TS_ASSERT_EQUALS(ssrs.pos(), 0);
ssrs.seek(1, SEEK_SET);
TS_ASSERT_EQUALS(ssrs.pos(), 1);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 1);
ssrs.seek(5, SEEK_CUR);
TS_ASSERT_EQUALS(ssrs.pos(), 7);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 7);
ssrs.seek(-3, SEEK_CUR);
TS_ASSERT_EQUALS(ssrs.pos(), 5);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 5);
ssrs.seek(0, SEEK_END);
TS_ASSERT_EQUALS(ssrs.pos(), 10);
TS_ASSERT(!ssrs.eos());
b = ssrs.readByte();
TS_ASSERT(ssrs.eos());
ssrs.seek(-3, SEEK_END);
TS_ASSERT(!ssrs.eos());
TS_ASSERT_EQUALS(ssrs.pos(), 7);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 7);
ssrs.seek(-8, SEEK_END);
TS_ASSERT_EQUALS(ssrs.pos(), 2);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 2);
ssrs.seek(5, SEEK_CUR);
TS_ASSERT_EQUALS(ssrs.pos(), 8);
ssrs.seek(-1, SEEK_CUR);
TS_ASSERT_EQUALS(ssrs.pos(), 7);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 7);
byte readBuffer[8];
ssrs.seek(0, SEEK_SET);
TS_ASSERT_EQUALS(ssrs.pos(), 0);
ssrs.readByte();
b = ssrs.read(&readBuffer, 8);
ssrs.seek(-1, SEEK_CUR);
TS_ASSERT_EQUALS(ssrs.pos(), 8);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 8);
delete &ssrs;
}
};

View File

@@ -0,0 +1,97 @@
#include <cxxtest/TestSuite.h>
#include "common/compression/huffman.h"
#include "common/bitstream.h"
#include "common/memstream.h"
/**
* A test suite for the Huffman decoder in common/compression/huffman.h
* The encoding used comes from the example on the Wikipedia page
* for Huffman.
* TODO: It could be improved by generating one at runtime.
*/
class HuffmanTestSuite : public CxxTest::TestSuite {
public:
void test_get_with_full_symbols() {
/*
* The class can be initialized with or without providing
* a max_length and a symbol table.
* We test with a table.
*
* Encoding (arbitrary, for testing purpouses):
* 0xA=010
* 0xB=011
* 0xC=11
* 0xD=00
* 0xE=10
*/
uint32 codeCount = 5;
uint8 maxLength = 3;
const uint8 lengths[] = {3,3,2,2,2};
const uint32 codes[] = {0x2, 0x3, 0x3, 0x0, 0x2};
const uint32 symbols[] = {0xA, 0xB, 0xC, 0xD, 0xE};
Common::Huffman<Common::BitStream8MSB> h(maxLength, codeCount, codes, lengths, symbols);
byte input[] = {0x4F, 0x20};
// Provided input...
uint32 expected[] = {0xA, 0xB, 0xC, 0xD, 0xE, 0xD, 0xD};
// ..and expected output.
/*
* What should be going on:
* 010 011 11 00 10 00 00 = A B C D E D D
* = 0100 1111 0010 0000 = 0x4F20
*/
Common::MemoryReadStream ms(input, sizeof(input));
Common::BitStream8MSB bs(ms);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[0]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[1]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[2]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[3]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[4]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[5]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[6]);
}
void test_get_without_symbols() {
/*
* This is basically the same as test_get_with_full_symbols, but
* I only pass the minimal required arguments.
* Specifically, I avoid passing the symbols table, so that
* array indices are used instead.
*
* Encoding becomes:
*
* 0=010
* 1=011
* 2=11
* 3=00
* 4=10
*/
uint32 codeCount = 5;
const uint8 lengths[] = {3,3,2,2,2};
const uint32 codes[] = {0x2, 0x3, 0x3, 0x0, 0x2};
Common::Huffman<Common::BitStream8MSB> h(0, codeCount, codes, lengths, 0);
byte input[] = {0x4F, 0x20};
uint32 expected[] = {0, 1, 2, 3, 4, 3 ,3};
Common::MemoryReadStream ms(input, sizeof(input));
Common::BitStream8MSB bs(ms);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[0]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[1]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[2]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[3]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[4]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[5]);
TS_ASSERT_EQUALS(h.getSymbol(bs), expected[6]);
}
};

73
test/common/crc.h Normal file
View File

@@ -0,0 +1,73 @@
#include <cxxtest/TestSuite.h>
#include "common/crc.h"
#include "common/crc_slow.h"
namespace {
const byte *testStringCRC = (const byte *)"The quick brown fox jumps over the lazy dog";
const int testLenCRC = 43;
}
class CrcTestSuite : public CxxTest::TestSuite
{
public:
void test_crc32() {
Common::CRC32 crc;
TS_ASSERT_EQUALS(crc.crcFast(testStringCRC, testLenCRC), 0x414fa339U);
uint32 running = crc.getInitRemainder();
for (const byte *ptr = testStringCRC; *ptr; ptr++) {
running = crc.processByte(*ptr, running);
}
TS_ASSERT_EQUALS(crc.finalize(running), 0x414fa339U);
}
void test_crc16() {
Common::CRC16 crc;
TS_ASSERT_EQUALS(crc.crcFast(testStringCRC, testLenCRC), 0xfcdfU);
uint16 running = crc.getInitRemainder();
for (const byte *ptr = testStringCRC; *ptr; ptr++) {
running = crc.processByte(*ptr, running);
}
TS_ASSERT_EQUALS(crc.finalize(running), 0xfcdfU);
}
void test_crc_ccitt() {
Common::CRC_CCITT crc; // aka ccitt-false
TS_ASSERT_EQUALS(crc.crcFast(testStringCRC, testLenCRC), 0x8fddU);
uint16 running = crc.getInitRemainder();
for (const byte *ptr = testStringCRC; *ptr; ptr++) {
running = crc.processByte(*ptr, running);
}
TS_ASSERT_EQUALS(crc.finalize(running), 0x8fddU);
}
void test_crc_binhex() {
Common::CRC_BINHEX crc; // Aka xmodem
TS_ASSERT_EQUALS(crc.crcFast(testStringCRC, testLenCRC), 0xf0c8U);
uint16 running = crc.getInitRemainder();
for (const byte *ptr = testStringCRC; *ptr; ptr++) {
running = crc.processByte(*ptr, running);
}
TS_ASSERT_EQUALS(crc.finalize(running), 0xf0c8U);
}
void test_crc32_slow() {
Common::CRC32_Slow crc;
TS_ASSERT_EQUALS(crc.crcSlow(testStringCRC, testLenCRC), 0x414fa339U);
}
void test_crc16_slow() {
Common::CRC16_Slow crc;
TS_ASSERT_EQUALS(crc.crcSlow(testStringCRC, testLenCRC), 0xfcdfU);
}
void test_crc_ccitt_slow() {
Common::CRC_CCITT_Slow crc; // aka ccitt-false
TS_ASSERT_EQUALS(crc.crcSlow(testStringCRC, testLenCRC), 0x8fddU);
}
void test_crc_binhex_slow() {
Common::CRC_BINHEX_Slow crc; // Aka xmodem
TS_ASSERT_EQUALS(crc.crcSlow(testStringCRC, testLenCRC), 0xf0c8U);
}
};

274
test/common/encoding.h Normal file
View File

@@ -0,0 +1,274 @@
#include <cxxtest/TestSuite.h>
#include "common/str.h"
#include "common/ustr.h"
#include "../system/null_osystem.h"
// We support CJK on all the platforms but it relies on OSystem to read
// file which *in test environments* is available only on some platforms
#if NULL_OSYSTEM_IS_AVAILABLE
#define TEST_CJK 1
#else
#define TEST_CJK 0
#endif
class EncodingTestSuite : public CxxTest::TestSuite
{
public:
void test_korean() {
#if TEST_CJK
Common::install_null_g_system();
const byte utf8[] = {
0xea, 0xb2, 0x8c, 0xec, 0x9e, 0x84, 0xec, 0xa4,
0x91, 0xec, 0xa7, 0x80, 0x20, 0xea, 0xb3, 0x84,
0xec, 0x86, 0x8d, 0xed, 0x95, 0x98, 0xeb, 0xa0,
0xa4, 0xeb, 0xa9, 0xb4, 0x20, 0xec, 0x8a, 0xa4,
0xed, 0x8e, 0x98, 0xec, 0x9d, 0xb4, 0xec, 0x8a,
0xa4, 0xed, 0x82, 0xa4, 0xeb, 0xa5, 0xbc, 0x20,
0xec, 0xb9, 0x98, 0xec, 0x8b, 0x9c, 0xec, 0x98,
0xa4, 0x2e, 0x00,
};
const Common::u32char_type_t utf32[] = {
0xac8c, 0xc784, 0xc911, 0xc9c0, 0x0020, 0xacc4,
0xc18d, 0xd558, 0xb824, 0xba74, 0x0020, 0xc2a4,
0xd398, 0xc774, 0xc2a4, 0xd0a4, 0xb97c, 0x0020,
0xce58, 0xc2dc, 0xc624, 0x002e, 0
};
const byte uhc[] = {
0xb0, 0xd4, 0xc0, 0xd3, 0xc1, 0xdf, 0xc1, 0xf6,
0x20, 0xb0, 0xe8, 0xbc, 0xd3, 0xc7, 0xcf, 0xb7,
0xc1, 0xb8, 0xe9, 0x20, 0xbd, 0xba, 0xc6, 0xe4,
0xc0, 0xcc, 0xbd, 0xba, 0xc5, 0xb0, 0xb8, 0xa6,
0x20, 0xc4, 0xa1, 0xbd, 0xc3, 0xbf, 0xc0, 0x2e,
0x00
};
Common::U32String ustr_from_utf8((const char *) utf8, Common::kUtf8);
Common::U32String ustr_from_uhc((const char *) uhc, Common::kWindows949);
Common::U32String ustr(utf32);
Common::String utf8_to_uhc = ustr_from_utf8.encode(Common::kWindows949);
Common::String uhc_to_utf8 = ustr_from_uhc.encode(Common::kUtf8);
TS_ASSERT_EQUALS(ustr_from_utf8, ustr);
TS_ASSERT_EQUALS(ustr_from_uhc, ustr);
TS_ASSERT(strcmp((const char *) utf8, uhc_to_utf8.c_str()) == 0);
TS_ASSERT(strcmp((const char *) uhc, utf8_to_uhc.c_str()) == 0);
#endif
}
void test_chinese() {
#if TEST_CJK
Common::install_null_g_system();
const byte utf8[] = {
0xe9, 0x81, 0x8a, 0xe6, 0x88, 0xb2, 0xe6, 0x9a,
0xab, 0xe5, 0x81, 0x9c, 0xe3, 0x80, 0x82, 0xe6,
0x8c, 0x89, 0xe4, 0xb8, 0x8b, 0xe7, 0xa9, 0xba,
0x21, 0xe7, 0x99, 0xbd, 0xe9, 0x8d, 0xb5, 0xe7,
0xb9, 0xbc, 0xe7, 0xba, 0x8c, 0xe9, 0x81, 0x8a,
0xe6, 0x88, 0xb2, 0xe3, 0x80, 0x82, 0x00,
};
const Common::u32char_type_t utf32[] = {
0x904a, 0x6232, 0x66ab, 0x505c, 0x3002, 0x6309,
0x4e0b, 0x7a7a, 0x0021, 0x767d, 0x9375, 0x7e7c,
0x7e8c, 0x904a, 0x6232, 0x3002, 0
};
const byte big5[] = {
0xb9, 0x43, 0xc0, 0xb8, 0xbc, 0xc8, 0xb0, 0xb1,
0xa1, 0x43, 0xab, 0xf6, 0xa4, 0x55, 0xaa, 0xc5,
0x21, 0xa5, 0xd5, 0xc1, 0xe4, 0xc4, 0x7e, 0xc4,
0xf2, 0xb9, 0x43, 0xc0, 0xb8, 0xa1, 0x43, 0x00
};
Common::U32String ustr_from_utf8((const char *) utf8, Common::kUtf8);
Common::U32String ustr_from_big5((const char *) big5, Common::kWindows950);
Common::U32String ustr(utf32);
Common::String utf8_to_big5 = ustr_from_utf8.encode(Common::kWindows950);
Common::String big5_to_utf8 = ustr_from_big5.encode(Common::kUtf8);
TS_ASSERT_EQUALS(ustr_from_utf8, ustr);
TS_ASSERT_EQUALS(ustr_from_big5, ustr);
TS_ASSERT(strcmp((const char *) utf8, big5_to_utf8.c_str()) == 0);
TS_ASSERT(strcmp((const char *) big5, utf8_to_big5.c_str()) == 0);
#endif
}
void test_japanese() {
#if TEST_CJK
Common::install_null_g_system();
const byte utf8[] = {
0xe4, 0xb8, 0x80, 0xe6, 0x99, 0x82, 0xe5, 0x81,
0x9c, 0xe6, 0xad, 0xa2, 0xe3, 0x80, 0x82, 0xe7,
0xb6, 0x9a, 0xe3, 0x81, 0x91, 0xe3, 0x82, 0x8b,
0xe5, 0xa0, 0xb4, 0xe5, 0x90, 0x88, 0xe3, 0x81,
0xaf, 0xe3, 0x82, 0xb9, 0xe3, 0x83, 0x9a, 0xe3,
0x83, 0xbc, 0xe3, 0x82, 0xb9, 0xe3, 0x83, 0x90,
0xe3, 0x83, 0xbc, 0xe3, 0x82, 0x92, 0xe6, 0x8a,
0xbc, 0xe3, 0x81, 0x97, 0xe3, 0x81, 0xa6, 0xe3,
0x81, 0x8f, 0xe3, 0x81, 0xa0, 0xe3, 0x81, 0x95,
0xe3, 0x81, 0x84, 0xe3, 0x80, 0x82, 0
};
const Common::u32char_type_t utf32[] = {
0x4e00, 0x6642, 0x505c, 0x6b62, 0x3002, 0x7d9a,
0x3051, 0x308b, 0x5834, 0x5408, 0x306f, 0x30b9,
0x30da, 0x30fc, 0x30b9, 0x30d0, 0x30fc, 0x3092,
0x62bc, 0x3057, 0x3066, 0x304f, 0x3060, 0x3055,
0x3044, 0x3002, 0
};
const byte cp932[] = {
0x88, 0xea, 0x8e, 0x9e, 0x92, 0xe2, 0x8e, 0x7e,
0x81, 0x42, 0x91, 0xb1, 0x82, 0xaf, 0x82, 0xe9,
0x8f, 0xea, 0x8d, 0x87, 0x82, 0xcd, 0x83, 0x58,
0x83, 0x79, 0x81, 0x5b, 0x83, 0x58, 0x83, 0x6f,
0x81, 0x5b, 0x82, 0xf0, 0x89, 0x9f, 0x82, 0xb5,
0x82, 0xc4, 0x82, 0xad, 0x82, 0xbe, 0x82, 0xb3,
0x82, 0xa2, 0x81, 0x42, 0
};
Common::U32String ustr_from_utf8((const char *) utf8, Common::kUtf8);
Common::U32String ustr_from_cp932((const char *) cp932, Common::kWindows932);
Common::U32String ustr(utf32);
Common::String utf8_to_cp932 = ustr_from_utf8.encode(Common::kWindows932);
Common::String cp932_to_utf8 = ustr_from_cp932.encode(Common::kUtf8);
TS_ASSERT_EQUALS(ustr_from_utf8, ustr);
TS_ASSERT_EQUALS(ustr_from_cp932, ustr);
TS_ASSERT(strcmp((const char *) utf8, cp932_to_utf8.c_str()) == 0);
TS_ASSERT(strcmp((const char *) cp932, utf8_to_cp932.c_str()) == 0);
#endif
}
void test_conversion_unicode_machine_endian() {
// |dolar| cent | euro |
unsigned char utf8[] = {0x24, 0xC2, 0xA2, 0xE2, 0x82, 0xAC, 0};
#ifdef SCUMM_BIG_ENDIAN
//| dolar | cent | euro |
unsigned char utf16be[] = {0, 0x24, 0, 0xA2, 0x20, 0xAC, 0, 0};
//| dolar | cent | euro
unsigned char utf32be[] = {0, 0, 0, 0x24, 0, 0, 0, 0xA2, 0, 0, 0x20, 0xAC, 0, 0, 0, 0};
unsigned char *utf16 = utf16be;
unsigned char *utf32 = utf32be;
#else
//| dolar | cent | euro |
unsigned char utf16le[] = {0x24, 0, 0xA2, 0, 0xAC, 0x20, 0, 0};
//| dolar | cent | euro
unsigned char utf32le[] = {0x24, 0, 0, 0, 0xA2, 0, 0, 0, 0xAC, 0x20, 0, 0, 0, 0, 0, 0};
unsigned char *utf16 = utf16le;
unsigned char *utf32 = utf32le;
#endif
// UTF16 to UTF8
Common::String resultstr8 = Common::U32String::decodeUTF16Native((uint16 *) utf16, 3).encode(Common::kUtf8);
TS_ASSERT(resultstr8.c_str() != NULL);
TS_ASSERT_EQUALS(memcmp(resultstr8.c_str(), utf8, 7), 0)
// UTF32 to UTF8
resultstr8 = Common::U32String((Common::u32char_type_t *) utf32, 3).encode(Common::kUtf8);
TS_ASSERT(resultstr8.c_str() != NULL);
TS_ASSERT_EQUALS(memcmp(resultstr8.c_str(), utf8, 7), 0);
// UTF32 to UTF16
uint16 *result16 = Common::U32String((Common::u32char_type_t *) utf32, 3).encodeUTF16Native(NULL);
TS_ASSERT(result16 != NULL);
TS_ASSERT_EQUALS(memcmp(result16, utf16, 8), 0);
delete[] result16;
// UTF8 to UTF16
result16 = Common::U32String((char *) utf8, 6, Common::kUtf8).encodeUTF16Native(NULL);
TS_ASSERT(result16 != NULL);
TS_ASSERT_EQUALS(memcmp(result16, utf16, 8), 0);
delete[] result16;
// UTF8 to UTF32
Common::U32String resultustr = Common::String((const char *) utf8, 6).decode(Common::kUtf8);
TS_ASSERT_EQUALS(memcmp(resultustr.c_str(), utf32, 16), 0);
// UTF16 to UTF32
resultustr = Common::U32String::decodeUTF16Native((uint16 *) utf16, 3);
TS_ASSERT_EQUALS(memcmp(resultustr.c_str(), utf32, 16), 0);
}
void test_conversion_unicode_big_endian() {
// |dolar| cent | euro |
unsigned char utf8[] = {0x24, 0xC2, 0xA2, 0xE2, 0x82, 0xAC, 0};
//| dolar | cent | euro |
unsigned char utf16be[] = {0, 0x24, 0, 0xA2, 0x20, 0xAC, 0, 0};
// UTF16 to UTF8
Common::String resultstr8 = Common::U32String::decodeUTF16BE((uint16 *) utf16be, 3).encode(Common::kUtf8);
TS_ASSERT(resultstr8.c_str() != NULL);
TS_ASSERT_EQUALS(memcmp(resultstr8.c_str(), utf8, 7), 0);
// UTF8 to UTF16
uint16 *result16 = Common::U32String((char *) utf8, 6, Common::kUtf8).encodeUTF16BE(NULL);
TS_ASSERT(result16 != NULL);
TS_ASSERT_EQUALS(memcmp(result16, utf16be, 8), 0);
delete[] result16;
}
void test_conversion_unicode_little_endian() {
// |dolar| cent | euro |
unsigned char utf8[] = {0x24, 0xC2, 0xA2, 0xE2, 0x82, 0xAC, 0};
//| dolar | cent | euro |
unsigned char utf16le[] = {0x24, 0, 0xA2, 0, 0xAC, 0x20, 0, 0};
// UTF16 to UTF8
Common::String resultstr8 = Common::U32String::decodeUTF16LE((uint16 *) utf16le, 3).encode(Common::kUtf8);
TS_ASSERT(resultstr8.c_str() != NULL);
TS_ASSERT_EQUALS(memcmp(resultstr8.c_str(), utf8, 7), 0);
// UTF8 to UTF16
uint16 *result16 = Common::U32String((char *) utf8, 6, Common::kUtf8).encodeUTF16LE(NULL);
TS_ASSERT(result16 != NULL);
TS_ASSERT_EQUALS(memcmp(result16, utf16le, 8), 0);
delete[] result16;
}
void test_cyrillic_transliteration() {
unsigned char utf8[] = {/* Z */0xD0, 0x97, /* d */ 0xD0, 0xB4, /* r */ 0xD1, 0x80, /* a */ 0xD0, 0xB0, /* v */ 0xD0, 0xB2, /* s */ 0xD1, 0x81, /* t */ 0xD1, 0x82, /* v */ 0xD0, 0xB2, /* u */ 0xD1, 0x83, /* j */ 0xD0, 0xB9, /* t */ 0xD1, 0x82, /* e */ 0xD0, 0xB5, 0};
unsigned char iso_8859_5[] = {0xB7, 0xD4, 0xE0, 0xD0, 0xD2, 0xE1, 0xE2, 0xD2, 0xE3, 0xD9, 0xE2, 0xD5, 0};
unsigned char ascii[] = "Zdravstvujte";
Common::String result = Common::U32String((const char *) utf8, 24, Common::kUtf8).encode(Common::kASCII);
TS_ASSERT_EQUALS(memcmp(result.c_str(), ascii, 13), 0);
result = Common::U32String((const char *) iso_8859_5, 12, Common::kISO8859_5).encode(Common::kASCII);
TS_ASSERT_EQUALS(memcmp(result.c_str(), ascii, 13), 0);
result = Common::U32String((const char *) iso_8859_5, 12, Common::kISO8859_5).encode(Common::kUtf8);
TS_ASSERT_EQUALS(memcmp(result.c_str(), utf8, 25), 0);
result = Common::U32String((const char *) utf8, 24, Common::kUtf8).encode(Common::kISO8859_5);
TS_ASSERT_EQUALS(memcmp(result.c_str(), iso_8859_5, 13), 0);
// this should stay the same
result = Common::U32String((const char *) ascii, 12, Common::kASCII).encode(Common::kISO8859_5);
TS_ASSERT_EQUALS(memcmp(result.c_str(), ascii, 13), 0);
}
void test_other_conversions() {
unsigned char cp850[] = {0x99, 0xE0, 0xEA, 0x41, 0x64, 0};
unsigned char utf8_1[] = {0xC3, 0x96, 0xC3, 0x93, 0xC3, 0x9B, 0x41, 0x64, 0};
unsigned char iso_8859_2[] = {0xA9, 0xE1, 0x6C, 0x65, 0xE8, 0x65, 0x6B, 0};
unsigned char utf8_2[] = {0xC5, 0xA0, 0xC3, 0xA1, 0x6C, 0x65, 0xC4, 0x8D, 0x65, 0x6B, 0};
Common::String result = Common::U32String((const char *) cp850, sizeof(cp850)-1, Common::kDos850).encode(Common::kUtf8);
TS_ASSERT_EQUALS(memcmp(result.c_str(), utf8_1, sizeof(utf8_1)), 0);
result = Common::U32String((const char *) utf8_1, sizeof(utf8_1)-1, Common::kUtf8).encode(Common::kDos850);
TS_ASSERT_EQUALS(memcmp(result.c_str(), cp850, sizeof(cp850)), 0);
result = Common::U32String((const char *) iso_8859_2, sizeof(iso_8859_2)-1, Common::kISO8859_2).encode(Common::kUtf8);
TS_ASSERT_EQUALS(memcmp(result.c_str(), utf8_2, sizeof(utf8_2)), 0);
result = Common::U32String((const char *) utf8_2, sizeof(utf8_2)-1, Common::kUtf8).encode(Common::kISO8859_2);
TS_ASSERT_EQUALS(memcmp(result.c_str(), iso_8859_2, sizeof(iso_8859_2)), 0);
}
};

114
test/common/endian.h Normal file
View File

@@ -0,0 +1,114 @@
#include <cxxtest/TestSuite.h>
#include "common/endian.h"
class EndianTestSuite : public CxxTest::TestSuite
{
public:
void test_MKTAG() {
const char *str_tag = "ABCD";
uint32 tag = READ_BE_UINT32(str_tag);
TS_ASSERT_EQUALS(MKTAG('A','B','C','D'), tag);
}
void test_READ_BE_UINT64() {
const byte data[8] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF};
uint64 value = READ_BE_UINT64(data);
TS_ASSERT_EQUALS(value, 0x123456789ABCDEFFULL);
}
void test_READ_LE_UINT64() {
const byte data[8] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xFF};
uint64 value = READ_LE_UINT64(data);
TS_ASSERT_EQUALS(value, 0xFFDEBC9A78563412ULL);
}
void test_READ_BE_UINT32() {
const char data[4] = { 0x12, 0x34, 0x56, 0x78 };
uint32 value = READ_BE_UINT32(data);
TS_ASSERT_EQUALS(value, 0x12345678UL);
}
void test_READ_LE_UINT32() {
const char data[4] = { 0x12, 0x34, 0x56, 0x78 };
uint32 value = READ_LE_UINT32(data);
TS_ASSERT_EQUALS(value, 0x78563412UL);
}
void test_READ_BE_UINT16() {
const char data[4] = { 0x12, 0x34, 0x56, 0x78 };
uint32 value = READ_BE_UINT16(data);
TS_ASSERT_EQUALS(value, 0x1234UL);
}
void test_READ_LE_UINT16() {
const char data[4] = { 0x12, 0x34, 0x56, 0x78 };
uint32 value = READ_LE_UINT16(data);
TS_ASSERT_EQUALS(value, 0x3412UL);
}
void test_READ_BE_FLOAT32() {
const uint8 data[4] = { 0x40, 0x49, 0x0f, 0xdc };
float value = READ_BE_FLOAT32(data);
TS_ASSERT_EQUALS(value, 3.141593f);
}
void test_READ_LE_FLOAT32() {
const uint8 data[4] = { 0xdc, 0x0f, 0x49, 0x40 };
float value = READ_LE_FLOAT32(data);
TS_ASSERT_EQUALS(value, 3.141593f);
}
void test_READ_BE_FLOAT64() {
const uint8 data[8] = { 0x40, 0x09, 0x21, 0xfb, 0x82, 0xc2, 0xbd, 0x7f };
double value = READ_BE_FLOAT64(data);
TS_ASSERT_EQUALS(value, 3.141593);
}
void test_READ_LE_FLOAT64() {
const uint8 data[8] = { 0x7f, 0xbd, 0xc2, 0x82, 0xfb, 0x21, 0x09, 0x40 };
double value = READ_LE_FLOAT64(data);
TS_ASSERT_EQUALS(value, 3.141593);
}
void test_READ_FPA_FLOAT64() {
const uint8 data[8] = { 0xfb, 0x21, 0x09, 0x40, 0x7f, 0xbd, 0xc2, 0x82 };
double value = READ_FPA_FLOAT64(data);
TS_ASSERT_EQUALS(value, 3.141593);
}
void test_WRITE_BE_FLOAT32() {
const uint8 data[4] = { 0x40, 0x49, 0x0f, 0xdc };
uint8 out[4];
WRITE_BE_FLOAT32(out, 3.141593f);
TS_ASSERT_EQUALS(memcmp(data, out, 4), 0);
}
void test_WRITE_LE_FLOAT32() {
const uint8 data[4] = { 0xdc, 0x0f, 0x49, 0x40 };
uint8 out[4];
WRITE_LE_FLOAT32(out, 3.141593f);
TS_ASSERT_EQUALS(memcmp(data, out, 4), 0);
}
void test_WRITE_BE_FLOAT64() {
const uint8 data[8] = { 0x40, 0x09, 0x21, 0xfb, 0x82, 0xc2, 0xbd, 0x7f };
uint8 out[8];
WRITE_BE_FLOAT64(out, 3.141593);
TS_ASSERT_EQUALS(memcmp(data, out, 8), 0);
}
void test_WRITE_LE_FLOAT64() {
const uint8 data[8] = { 0x7f, 0xbd, 0xc2, 0x82, 0xfb, 0x21, 0x09, 0x40 };
uint8 out[8];
WRITE_LE_FLOAT64(out, 3.141593);
TS_ASSERT_EQUALS(memcmp(data, out, 8), 0);
}
void test_WRITE_FPA_FLOAT64() {
const uint8 data[8] = { 0xfb, 0x21, 0x09, 0x40, 0x7f, 0xbd, 0xc2, 0x82 };
uint8 out[8];
WRITE_FPA_FLOAT64(out, 3.141593);
TS_ASSERT_EQUALS(memcmp(data, out, 8), 0);
}
};

83
test/common/fixedstack.h Normal file
View File

@@ -0,0 +1,83 @@
#include <cxxtest/TestSuite.h>
#include "common/stack.h"
class FixedStackTestSuite : public CxxTest::TestSuite {
public:
void test_empty_clear() {
Common::FixedStack<int> stack;
TS_ASSERT(stack.empty());
stack.push(1);
stack.push(2);
TS_ASSERT(!stack.empty());
stack.clear();
TS_ASSERT(stack.empty());
}
void test_size() {
typedef Common::FixedStack<int> Stack;
Stack stack;
TS_ASSERT_EQUALS(stack.size(), (Stack::size_type)0);
stack.push(5);
TS_ASSERT_EQUALS(stack.size(), (Stack::size_type)1);
stack.push(9);
stack.push(0);
TS_ASSERT_EQUALS(stack.size(), (Stack::size_type)3);
stack.pop();
TS_ASSERT_EQUALS(stack.size(), (Stack::size_type)2);
}
void test_top_pop() {
Common::FixedStack<int> stack;
stack.push( 42);
stack.push(-23);
TS_ASSERT_EQUALS(stack[0], 42);
TS_ASSERT_EQUALS(stack.top(), -23);
stack[0] = -23;
stack.top() = 42;
TS_ASSERT_EQUALS(stack[0], -23);
TS_ASSERT_EQUALS(stack.top(), 42);
stack.pop();
TS_ASSERT_EQUALS(stack[0], -23);
}
void test_assign() {
Common::FixedStack<int> q1, q2;
for (int i = 0; i <= 4; ++i) {
q1.push(4-i);
q2.push(i);
}
Common::FixedStack<int> q3(q1);
for (int i = 0; i < 5; ++i) {
TS_ASSERT_EQUALS(q3.top(), i);
q3.pop();
}
TS_ASSERT(q3.empty());
q3 = q2;
for (int i = 4; i >= 0; --i) {
TS_ASSERT_EQUALS(q3.top(), i);
q3.pop();
}
TS_ASSERT(q3.empty());
TS_ASSERT(!q1.empty());
TS_ASSERT(!q2.empty());
}
};

View File

@@ -0,0 +1,83 @@
#include <cxxtest/TestSuite.h>
#include "common/util.h"
#include "common/formats/quicktime.h"
static const byte VALID_MOOV_DATA[] = { // a minimally 'correct' quicktime file.
// size 'moov' size 'mdat'
0x0, 0x0, 0x0, 0x8, 0x6d, 0x6f, 0x6f, 0x76, 0x0, 0x0, 0x0, 0x8, 0x6d, 0x64, 0x61, 0x74
};
static const byte VALID_MHDR_DATA[] = { // a 'correct' quicktime file with a header
// size (incl mvhd) 'moov'
0x0, 0x0, 0x0, 0x74, 0x6d, 0x6f, 0x6f, 0x76,
//size (27*4) 'mvhd' vers 3bytes flags
0x0, 0x0, 0x0, 0x6c, 0x6d, 0x76, 0x68, 0x64, 0x00, 0xff, 0xff, 0xff,
// creation modification timescale (60?) length (999 * 60)+ 1
0x65, 0x52, 0xef, 0x5b, 0x65, 0x52, 0xef, 0x5b, 0x0, 0x0, 0x0, 0x3c, 0x0, 0x0, 0xea, 0x25,
// preferred scale, vol, [10 bytes reserved]
0x0, 0x0, 0x0, 0x1, 0x0, 0x10, 0,0,0,0,0,0,0,0,0,0,
// display matrix, mostly ignored by parser except xMod (0x8000) and yMod (0xa000)
0x0, 0x0, 0x80, 0x0, 0,0,0,0,0,0,0,0,0,0,0,0, 0x0, 0x0, 0xa0, 0x0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
// 7 more 32-bit values
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
// size 'mdat'
0x0, 0x0, 0x0, 0x8, 0x6d, 0x64, 0x61, 0x74
};
class QuickTimeTestParser : public Common::QuickTimeParser {
public:
uint32 getDuration() const { return _duration; }
const Common::Rational &getScaleFactorX() const { return _scaleFactorX; }
const Common::Rational &getScaleFactorY() const { return _scaleFactorY; }
const Common::Array<Track *> &getTracks() const { return _tracks; }
SampleDesc *readSampleDesc(Track *track, uint32 format, uint32 descSize) override {
return nullptr;
}
};
class QuicktimeParserTestSuite : public CxxTest::TestSuite {
public:
void test_streamAtEOS() {
QuickTimeTestParser parser;
const byte data[] = "";
Common::MemoryReadStream stream(data, sizeof(data));
stream.readByte(); // read the null char
bool result = parser.parseStream(&stream, DisposeAfterUse::NO);
TS_ASSERT(!result);
}
void test_streamInvalid() {
QuickTimeTestParser parser;
const byte data[] = "not a moov";
Common::MemoryReadStream stream(data, sizeof(data));
bool result = parser.parseStream(&stream, DisposeAfterUse::NO);
TS_ASSERT(!result);
}
void test_moov() {
QuickTimeTestParser parser;
Common::MemoryReadStream stream(VALID_MOOV_DATA, sizeof(VALID_MOOV_DATA));
bool result = parser.parseStream(&stream, DisposeAfterUse::NO);
TS_ASSERT(result);
}
void test_mhdr() {
QuickTimeTestParser parser;
Common::MemoryReadStream stream(VALID_MHDR_DATA, sizeof(VALID_MHDR_DATA));
bool result = parser.parseStream(&stream, DisposeAfterUse::NO);
TS_ASSERT(result);
TS_ASSERT_EQUALS(parser.getDuration(), 999*60 + 1);
TS_ASSERT_EQUALS(parser.getScaleFactorX(), Common::Rational(0x10000, 0x8000));
TS_ASSERT_EQUALS(parser.getScaleFactorY(), Common::Rational(0x10000, 0xa000));
}
void test_mhdrEarlyEOF() {
QuickTimeTestParser parser;
Common::MemoryReadStream stream(VALID_MHDR_DATA, sizeof(VALID_MHDR_DATA) - 10);
bool result = parser.parseStream(&stream, DisposeAfterUse::NO);
TS_ASSERT(!result);
}
};

60
test/common/func.h Normal file
View File

@@ -0,0 +1,60 @@
#include <cxxtest/TestSuite.h>
#include "common/func.h"
void myFunction1(int &dst, const int src) { dst = src; }
void myFunction2(const int src, int &dst) { dst = src; }
class FuncTestSuite : public CxxTest::TestSuite
{
public:
void test_bind1st() {
int dst = 0;
Common::bind1st(Common::ptr_fun(myFunction1), dst)(1);
TS_ASSERT_EQUALS(dst, 1);
}
void test_bind2nd() {
int dst = 0;
Common::bind2nd(Common::ptr_fun(myFunction2), dst)(1);
TS_ASSERT_EQUALS(dst, 1);
}
struct Foo {
void fooAdd(int &foo) {
++foo;
}
void fooSub(int &foo) const {
--foo;
}
};
void test_mem_fun_ref() {
Foo myFoos[4];
int counter = 0;
Common::for_each(myFoos, myFoos+4, Common::bind2nd(Common::mem_fun_ref(&Foo::fooAdd), counter));
TS_ASSERT_EQUALS(counter, 4);
Common::for_each(myFoos, myFoos+4, Common::bind2nd(Common::mem_fun_ref(&Foo::fooSub), counter));
TS_ASSERT_EQUALS(counter, 0);
}
void test_mem_fun() {
Foo *myFoos[4];
for (int i = 0; i < 4; ++i)
myFoos[i] = new Foo;
int counter = 0;
Common::for_each(myFoos, myFoos+4, Common::bind2nd(Common::mem_fun(&Foo::fooAdd), counter));
TS_ASSERT_EQUALS(counter, 4);
Common::for_each(myFoos, myFoos+4, Common::bind2nd(Common::mem_fun(&Foo::fooSub), counter));
TS_ASSERT_EQUALS(counter, 0);
for (int i = 0; i < 4; ++i)
delete myFoos[i];
}
};

164
test/common/hash-str.h Normal file
View File

@@ -0,0 +1,164 @@
#include <cxxtest/TestSuite.h>
#include "common/hash-str.h"
/**
* Test suite for common/hash-str.h
* We test a number of case sensitive/insensitive hash and compare functions
* using example strings and known hashes, trying to tackle
* as much edge cases as possible.
*/
class HashStrTestSuite : public CxxTest::TestSuite {
public:
void test_case_sensitive_string_equal_to() {
// Name says it all.
// This verifies that the function returns true
// for exactly the same string, false for the same
// string in mixed case and false for some edge cases
// with various spacings plus one character replaced
// by itself+128 (if there's some processing done after
// conversion to 7-bit ASCII this might yield funny results).
const Common::String lower("test");
const Common::String lower1("test");
const Common::String mixed("tESt");
const Common::String spaced("test ");
const Common::String doublespaced("test ");
const Common::String tabbed("test\t");
const Common::String plus128("t\345est");
// 'e'+128 = 0xE5 = 0o345
Common::CaseSensitiveString_EqualTo css_et;
TS_ASSERT_EQUALS(css_et(lower, mixed), false);
TS_ASSERT_EQUALS(css_et(lower, lower1), true);
TS_ASSERT_EQUALS(css_et(lower, lower), true);
// Different sorts of whitespace are to be treated differently.
TS_ASSERT_EQUALS(css_et(lower, spaced), false);
TS_ASSERT_EQUALS(css_et(lower, tabbed), false);
TS_ASSERT_EQUALS(css_et(spaced, tabbed), false);
TS_ASSERT_EQUALS(css_et(spaced, doublespaced), false);
TS_ASSERT_EQUALS(css_et(lower, plus128), false);
}
void test_ignore_case_equal_to() {
// This should be probably called case_insensitive_string_equal_to
// or something,but it's basically the same thing as
// test_case_sensitive_string_equal_to, only it's case
// insensitive.
const Common::String lower("test");
const Common::String lower1("test");
const Common::String mixed("tESt");
const Common::String spaced("test ");
const Common::String mixedspaced("tESt ");
const Common::String doublespaced("test ");
const Common::String tabbed("test\t");
const Common::String plus128("t\345est");
Common::IgnoreCase_EqualTo ic_et;
TS_ASSERT_EQUALS(ic_et(lower, mixed), true);
TS_ASSERT_EQUALS(ic_et(lower, lower1), true);
TS_ASSERT_EQUALS(ic_et(lower, lower), true);
// Edge case:
TS_ASSERT_EQUALS(ic_et(spaced, mixedspaced), true);
// Different sorts of whitespace are to be treated differently.
TS_ASSERT_EQUALS(ic_et(lower, spaced), false);
TS_ASSERT_EQUALS(ic_et(lower, tabbed), false);
TS_ASSERT_EQUALS(ic_et(spaced, tabbed), false);
TS_ASSERT_EQUALS(ic_et(spaced, doublespaced), false);
TS_ASSERT_EQUALS(ic_et(lower, plus128), false);
}
void test_case_sensitive_string_hash() {
// Here we compute string hashes for different
// strings and see that the functor is case sensitive
// and does not ignore spaces.
const Common::String lower("test");
const Common::String lower1("test");
const Common::String mixed("tESt");
const Common::String spaced("test ");
const Common::String mixedspaced("tESt ");
const Common::String doublespaced("test ");
const Common::String tabbed("test\t");
Common::CaseSensitiveString_Hash css_h;
TS_ASSERT_EQUALS(css_h(lower), css_h(lower1));
TS_ASSERT_DIFFERS(css_h(mixed), css_h(lower));
TS_ASSERT_DIFFERS(css_h(spaced), css_h(lower));
TS_ASSERT_DIFFERS(css_h(tabbed), css_h(spaced));
TS_ASSERT_DIFFERS(css_h(spaced), css_h(doublespaced));
}
void test_ignore_case_hash() {
// Same as test_case_sensitive_string_hash, but case insensitive.
const Common::String lower("test");
const Common::String lower1("test");
const Common::String mixed("tESt");
const Common::String spaced("test ");
const Common::String mixedspaced("tESt ");
const Common::String doublespaced("test ");
const Common::String tabbed("test\t");
Common::IgnoreCase_Hash ic_h;
TS_ASSERT_EQUALS(ic_h(lower), ic_h(lower1));
TS_ASSERT_EQUALS(ic_h(mixed), ic_h(lower));
TS_ASSERT_EQUALS(ic_h(spaced), ic_h(mixedspaced));
TS_ASSERT_DIFFERS(ic_h(tabbed), ic_h(lower));
TS_ASSERT_DIFFERS(ic_h(spaced), ic_h(doublespaced));
}
void test_cpp_string_hash()
{
// We run the same tests with Hash<String>,
// a template specialization of Hash, also a functor.
// It is supposed to be case sensitive.
const Common::String lower("test");
const Common::String lower1("test");
const Common::String mixed("tESt");
const Common::String spaced("test ");
const Common::String mixedspaced("tESt ");
const Common::String doublespaced("test ");
const Common::String tabbed("test\t");
Common::Hash<Common::String> h;
TS_ASSERT_EQUALS(h(lower), h(lower1));
TS_ASSERT_DIFFERS(h(mixed), h(lower));
TS_ASSERT_DIFFERS(h(spaced), h(lower));
TS_ASSERT_DIFFERS(h(tabbed), h(spaced));
TS_ASSERT_DIFFERS(h(spaced), h(doublespaced));
}
void test_c_style_string_hash()
{
// Same as test_cpp_string_hash but with Hash<const char*>,
// a template specialization of Hash, also a functor,
// that works with C-Style strings.
// It is supposed to be case sensitive.
char lower[] = "test";
char lower1[] = "test";
char mixed[] = "tESt";
char spaced[] = "test ";
char mixedspaced[] = "tESt ";
char doublespaced[] = "test ";
char tabbed[] = "test\t";
Common::Hash<const char *> h;
TS_ASSERT_EQUALS(h(lower), h(lower1));
TS_ASSERT_DIFFERS(h(mixed), h(lower));
TS_ASSERT_DIFFERS(h(spaced), h(lower));
TS_ASSERT_DIFFERS(h(spaced), h(mixedspaced));
TS_ASSERT_DIFFERS(h(tabbed), h(spaced));
TS_ASSERT_DIFFERS(h(spaced), h(doublespaced));
}
};

234
test/common/hashmap.h Normal file
View File

@@ -0,0 +1,234 @@
#include <cxxtest/TestSuite.h>
#include "common/hashmap.h"
#include "common/hash-str.h"
class HashMapTestSuite : public CxxTest::TestSuite
{
public:
void test_empty_clear() {
Common::HashMap<int, int> container;
TS_ASSERT(container.empty());
container[0] = 17;
container[1] = 33;
TS_ASSERT(!container.empty());
container.clear();
TS_ASSERT(container.empty());
Common::StringMap container2;
TS_ASSERT(container2.empty());
container2["foo"] = "bar";
container2["quux"] = "blub";
TS_ASSERT(!container2.empty());
container2.clear();
TS_ASSERT(container2.empty());
}
void test_contains() {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = 33;
TS_ASSERT(container.contains(0));
TS_ASSERT(container.contains(1));
TS_ASSERT(!container.contains(17));
TS_ASSERT(!container.contains(-1));
Common::StringMap container2;
container2["foo"] = "bar";
container2["quux"] = "blub";
TS_ASSERT(container2.contains("foo"));
TS_ASSERT(container2.contains("quux"));
TS_ASSERT(!container2.contains("bar"));
TS_ASSERT(!container2.contains("asdf"));
}
void test_add_remove() {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = 33;
container[2] = 45;
container[3] = 12;
container[4] = 96;
TS_ASSERT(container.contains(1));
container.erase(1);
TS_ASSERT(!container.contains(1));
container[1] = 42;
TS_ASSERT(container.contains(1));
container.erase(0);
TS_ASSERT(!container.empty());
container.erase(1);
TS_ASSERT(!container.empty());
container.erase(2);
TS_ASSERT(!container.empty());
container.erase(3);
TS_ASSERT(!container.empty());
container.erase(4);
TS_ASSERT(container.empty());
container[1] = 33;
TS_ASSERT(container.contains(1));
TS_ASSERT(!container.empty());
container.erase(1);
TS_ASSERT(container.empty());
}
void test_add_remove_iterator() {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = 33;
container[2] = 45;
container[3] = 12;
container[4] = 96;
TS_ASSERT(container.contains(1));
container.erase(container.find(1));
TS_ASSERT(!container.contains(1));
container[1] = 42;
TS_ASSERT(container.contains(1));
container.erase(container.find(0));
TS_ASSERT(!container.empty());
container.erase(container.find(1));
TS_ASSERT(!container.empty());
container.erase(container.find(2));
TS_ASSERT(!container.empty());
container.erase(container.find(3));
TS_ASSERT(!container.empty());
container.erase(container.find(4));
TS_ASSERT(container.empty());
container[1] = 33;
TS_ASSERT(container.contains(1));
TS_ASSERT(!container.empty());
container.erase(container.find(1));
TS_ASSERT(container.empty());
}
void test_lookup() {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = -1;
container[2] = 45;
container[3] = 12;
container[4] = 96;
TS_ASSERT_EQUALS(container[0], 17);
TS_ASSERT_EQUALS(container[1], -1);
TS_ASSERT_EQUALS(container[2], 45);
TS_ASSERT_EQUALS(container[3], 12);
TS_ASSERT_EQUALS(container[4], 96);
}
void test_lookup_with_default() {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = -1;
container[2] = 45;
container[3] = 12;
container[4] = 96;
// We take a const ref now to ensure that the map
// is not modified by getValOrDefault.
const Common::HashMap<int, int> &containerRef = container;
TS_ASSERT_EQUALS(containerRef.getValOrDefault(0), 17);
TS_ASSERT_EQUALS(containerRef.getValOrDefault(17), 0);
TS_ASSERT_EQUALS(containerRef.getValOrDefault(0, -10), 17);
TS_ASSERT_EQUALS(containerRef.getValOrDefault(17, -10), -10);
}
void test_iterator_begin_end() {
Common::HashMap<int, int> container;
// The container is initially empty ...
TS_ASSERT_EQUALS(container.begin(), container.end());
// ... then non-empty ...
container[324] = 33;
TS_ASSERT_DIFFERS(container.begin(), container.end());
// ... and again empty.
container.clear();
TS_ASSERT_EQUALS(container.begin(), container.end());
}
void test_hash_map_copy() {
Common::HashMap<int, int> map1, container2;
map1[323] = 32;
container2 = map1;
TS_ASSERT_EQUALS(container2[323], 32);
}
void test_collision() {
// NB: The usefulness of this example depends strongly on the
// specific hashmap implementation.
// It is constructed to insert multiple colliding elements.
Common::HashMap<int, int> h;
h[5] = 1;
h[32+5] = 1;
h[64+5] = 1;
h[128+5] = 1;
TS_ASSERT(h.contains(5));
TS_ASSERT(h.contains(32+5));
TS_ASSERT(h.contains(64+5));
TS_ASSERT(h.contains(128+5));
h.erase(32+5);
TS_ASSERT(h.contains(5));
TS_ASSERT(h.contains(64+5));
TS_ASSERT(h.contains(128+5));
h.erase(5);
TS_ASSERT(h.contains(64+5));
TS_ASSERT(h.contains(128+5));
h[32+5] = 1;
TS_ASSERT(h.contains(32+5));
TS_ASSERT(h.contains(64+5));
TS_ASSERT(h.contains(128+5));
h[5] = 1;
TS_ASSERT(h.contains(5));
TS_ASSERT(h.contains(32+5));
TS_ASSERT(h.contains(64+5));
TS_ASSERT(h.contains(128+5));
h.erase(5);
TS_ASSERT(h.contains(32+5));
TS_ASSERT(h.contains(64+5));
TS_ASSERT(h.contains(128+5));
h.erase(64+5);
TS_ASSERT(h.contains(32+5));
TS_ASSERT(h.contains(128+5));
h.erase(128+5);
TS_ASSERT(h.contains(32+5));
h.erase(32+5);
TS_ASSERT(h.empty());
}
void test_iterator() {
Common::HashMap<int, int> container;
container[0] = 17;
container[1] = 33;
container[2] = 45;
container[3] = 12;
container[4] = 96;
container.erase(1);
container[1] = 42;
container.erase(0);
container.erase(1);
int found = 0;
Common::HashMap<int, int>::iterator i;
for (i = container.begin(); i != container.end(); ++i) {
int key = i->_key;
TS_ASSERT(key >= 0 && key <= 4);
TS_ASSERT(!(found & (1 << key)));
found |= 1 << key;
}
TS_ASSERT(found == 16+8+4);
found = 0;
Common::HashMap<int, int>::const_iterator j;
for (j = container.begin(); j != container.end(); ++j) {
int key = j->_key;
TS_ASSERT(key >= 0 && key <= 4);
TS_ASSERT(!(found & (1 << key)));
found |= 1 << key;
}
TS_ASSERT(found == 16+8+4);
}
// TODO: Add test cases for iterators, find, ...
};

172
test/common/ini-file.h Normal file
View File

@@ -0,0 +1,172 @@
#include <cxxtest/TestSuite.h>
#include "common/formats/ini-file.h"
#include "common/memstream.h"
class IniFileTestSuite : public CxxTest::TestSuite {
public:
void test_blank_ini_file() {
Common::INIFile inifile;
TS_ASSERT(!inifile.hasSection("abc"));
Common::INIFile::SectionList sections = inifile.getSections();
TS_ASSERT_EQUALS(sections.size(), 0U);
}
void test_simple_ini_file() {
static const unsigned char inistr[] = "#comment\n[s]\nabc=1\ndef=xyz";
Common::MemoryReadStream ms(inistr, sizeof(inistr));
Common::INIFile inifile;
bool result = inifile.loadFromStream(ms);
TS_ASSERT(result);
Common::INIFile::SectionList sections = inifile.getSections();
TS_ASSERT_EQUALS(sections.size(), 1U);
TS_ASSERT(inifile.hasSection("s"));
TS_ASSERT(inifile.hasKey("abc", "s"));
Common::String val;
TS_ASSERT(inifile.getKey("abc", "s", val));
TS_ASSERT_EQUALS(val, "1");
TS_ASSERT(inifile.getKey("def", "s", val));
TS_ASSERT_EQUALS(val, "xyz");
inifile.setKey("abc", "s", "newval");
TS_ASSERT(inifile.getKey("abc", "s", val));
TS_ASSERT_EQUALS(val, "newval");
}
void test_multisection_ini_file() {
static const unsigned char inistr[] = "[s]\nabc=1\ndef=xyz\n#comment=no\n[empty]\n\n[s2]\n abc = 2 \n ; comment=no";
Common::MemoryReadStream ms(inistr, sizeof(inistr));
Common::INIFile inifile;
bool result = inifile.loadFromStream(ms);
TS_ASSERT(result);
Common::INIFile::SectionList sections = inifile.getSections();
TS_ASSERT_EQUALS(sections.size(), 3U);
TS_ASSERT(inifile.hasSection("s"));
TS_ASSERT(inifile.hasSection("empty"));
TS_ASSERT(inifile.hasSection("s2"));
TS_ASSERT(inifile.hasKey("abc", "s"));
TS_ASSERT(inifile.hasKey("abc", "s2"));
Common::String val;
TS_ASSERT(inifile.getKey("abc", "s", val));
TS_ASSERT_EQUALS(val, "1");
TS_ASSERT(inifile.getKey("abc", "s2", val));
TS_ASSERT_EQUALS(val, "2");
inifile.clear();
sections = inifile.getSections();
TS_ASSERT_EQUALS(sections.size(), 0U);
TS_ASSERT(!inifile.hasSection("s"));
}
void test_modify_ini_file() {
Common::INIFile inifile;
TS_ASSERT(!inifile.hasSection("s"));
inifile.addSection("s");
TS_ASSERT(inifile.hasSection("s"));
inifile.setKey("k", "s", "val");
TS_ASSERT(inifile.hasKey("k", "s"));
inifile.setKey("k2", "s", "val2");
TS_ASSERT(inifile.hasKey("k2", "s"));
inifile.removeKey("k2", "s");
TS_ASSERT(!inifile.hasKey("k2", "s"));
inifile.renameSection("s", "t");
TS_ASSERT(!inifile.hasSection("s"));
TS_ASSERT(inifile.hasSection("t"));
TS_ASSERT(inifile.hasKey("k", "t"));
inifile.removeSection("t");
TS_ASSERT(!inifile.hasSection("t"));
}
void test_name_validity() {
Common::INIFile inifile;
inifile.addSection("s*");
TS_ASSERT(!inifile.hasSection("s*"));
inifile.addSection("");
TS_ASSERT(!inifile.hasSection(""));
// Valid is alphanum plus [-_:. ]
inifile.addSection("sEcT10N -_..Name:");
TS_ASSERT(inifile.hasSection("sEcT10N -_..Name:"));
const char invalids[] = "!\"#$%&'()=~[]()+?<>\r\t\n";
for (uint i = 0; i < sizeof(invalids) - 1; i++) {
char c = invalids[i];
const Common::String s(c);
inifile.addSection(s);
TS_ASSERT(!inifile.hasSection(s));
}
inifile.clear();
inifile.allowNonEnglishCharacters();
for (uint i = 0; i < sizeof(invalids) - 1; i++) {
char c = invalids[i];
if (c == '[' || c == ']' || c == '#' || c == '=' || c == '\r' || c == '\n')
continue;
const Common::String s(c);
inifile.addSection(s);
TS_ASSERT(inifile.hasSection(s));
}
}
void test_write_simple_ini_file() {
byte buf[1024];
Common::INIFile inifile;
{
static const unsigned char inistr[] = "#comment\n[s]\nabc=1\ndef=xyz";
Common::MemoryReadStream mrs(inistr, sizeof(inistr));
TS_ASSERT(inifile.loadFromStream(mrs));
}
// A too-small write buffer (should fail)
{
Common::MemoryWriteStream mws(buf, 10);
TS_ASSERT(!inifile.saveToStream(mws));
}
// A good sized write buffer (should work)
int len;
{
Common::MemoryWriteStream mws(buf, 1024);
TS_ASSERT(inifile.saveToStream(mws));
len = mws.pos();
}
{
Common::MemoryReadStream mrs(buf, len - 1);
Common::INIFile checkinifile;
TS_ASSERT(checkinifile.loadFromStream(mrs));
TS_ASSERT(checkinifile.hasSection("s"));
const Common::INIFile::SectionList &sections = checkinifile.getSections();
const Common::INIFile::Section &section = sections.front();
TS_ASSERT_EQUALS(section.comment, "#comment\n");
TS_ASSERT_EQUALS(section.name, "s");
TS_ASSERT(checkinifile.hasKey("abc", "s"));
TS_ASSERT(checkinifile.hasKey("def", "s"));
Common::String val;
TS_ASSERT(inifile.getKey("abc", "s", val));
TS_ASSERT_EQUALS(val, "1");
TS_ASSERT(inifile.getKey("def", "s", val));
TS_ASSERT_EQUALS(val, "xyz");
}
}
};

18
test/common/intrinsics.h Normal file
View File

@@ -0,0 +1,18 @@
#include <cxxtest/TestSuite.h>
#include "common/intrinsics.h"
class IntrinsicsTestSuite : public CxxTest::TestSuite
{
public:
void test_intLog2() {
// Test special case for 0
TS_ASSERT_EQUALS(Common::intLog2(0), -1);
// intLog2 should round the result towards 0
TS_ASSERT_EQUALS(Common::intLog2(7), 2);
// Some simple test for 2^10
TS_ASSERT_EQUALS(Common::intLog2(1024), 10);
}
};

285
test/common/list.h Normal file
View File

@@ -0,0 +1,285 @@
#include <cxxtest/TestSuite.h>
#include "common/list.h"
class ListTestSuite : public CxxTest::TestSuite
{
public:
void test_empty_clear() {
Common::List<int> container;
TS_ASSERT(container.empty());
container.push_back(17);
container.push_back(33);
TS_ASSERT(!container.empty());
container.clear();
TS_ASSERT(container.empty());
}
public:
void test_size() {
Common::List<int> container;
TS_ASSERT_EQUALS(container.size(), (unsigned int)0);
container.push_back(17);
TS_ASSERT_EQUALS(container.size(), (unsigned int)1);
container.push_back(33);
TS_ASSERT_EQUALS(container.size(), (unsigned int)2);
container.clear();
TS_ASSERT_EQUALS(container.size(), (unsigned int)0);
}
void test_iterator_begin_end() {
Common::List<int> container;
// The container is initially empty ...
TS_ASSERT_EQUALS(container.begin(), container.end());
// ... then non-empty ...
container.push_back(33);
TS_ASSERT_DIFFERS(container.begin(), container.end());
// ... and again empty.
container.clear();
TS_ASSERT_EQUALS(container.begin(), container.end());
}
void test_iterator() {
Common::List<int> container;
Common::List<int>::iterator iter;
Common::List<int>::const_iterator cIter;
// Fill the container with some random data
container.push_back(17);
container.push_back(33);
container.push_back(-11);
// Iterate over the container and verify that we encounter the elements in
// the order we expect them to be.
iter = container.begin();
cIter = container.begin();
TS_ASSERT_EQUALS(iter, cIter);
TS_ASSERT_EQUALS(*iter, 17);
++iter;
++cIter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_DIFFERS(cIter, container.end());
TS_ASSERT_EQUALS(iter, cIter);
TS_ASSERT_EQUALS(*iter, 33);
++iter;
++cIter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_DIFFERS(cIter, container.end());
TS_ASSERT_EQUALS(iter, cIter);
// Also test the postinc
TS_ASSERT_EQUALS(*iter, -11);
iter++;
cIter++;
TS_ASSERT_EQUALS(iter, container.end());
TS_ASSERT_EQUALS(cIter, container.end());
TS_ASSERT_EQUALS(iter, cIter);
cIter = iter;
TS_ASSERT_EQUALS(iter, cIter);
}
void test_insert() {
Common::List<int> container;
Common::List<int>::iterator iter;
// Fill the container with some random data
container.push_back(17);
container.push_back(33);
container.push_back(-11);
// Iterate to after the second element
iter = container.begin();
++iter;
++iter;
// Insert a value before the final one
container.insert(iter, 42);
// Insert another value before the final one and check the return value
iter = container.insert(iter, 43);
TS_ASSERT_EQUALS(*iter, 43);
// Insert a value before the previously inserted one
container.insert(iter, 44);
// Verify contents are correct
iter = container.begin();
TS_ASSERT_EQUALS(*iter, 17);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 33);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 42);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 44);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 43);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, -11);
++iter;
TS_ASSERT_EQUALS(iter, container.end());
}
void test_erase() {
Common::List<int> container;
Common::List<int>::iterator first, last;
// Fill the container with some random data
container.push_back(17);
container.push_back(33);
container.push_back(-11);
container.push_back(42);
container.push_back(43);
// Iterate to after the second element
first = container.begin();
++first;
++first;
// Iterate to after the fourth element
last = first;
++last;
++last;
// Now erase that range
container.erase(first, last);
// Verify contents are correct
Common::List<int>::iterator iter = container.begin();
TS_ASSERT_EQUALS(*iter, 17);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 33);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 43);
++iter;
TS_ASSERT_EQUALS(iter, container.end());
}
void test_remove() {
Common::List<int> container;
Common::List<int>::iterator first, last;
// Fill the container with some random data
container.push_back(-11);
container.push_back(17);
container.push_back(33);
container.push_back(42);
container.push_back(-11);
container.push_back(42);
container.push_back(43);
// Remove some stuff
container.remove(42);
container.remove(-11);
// Now erase that range
container.erase(first, last);
// Verify contents are correct
Common::List<int>::iterator iter = container.begin();
TS_ASSERT_EQUALS(*iter, 17);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 33);
++iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 43);
++iter;
TS_ASSERT_EQUALS(iter, container.end());
}
void test_reverse() {
Common::List<int> container;
Common::List<int>::iterator iter;
// Fill the container with some random data
container.push_back(17);
container.push_back(33);
container.push_back(-11);
iter = container.reverse_begin();
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, -11);
--iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 33);
--iter;
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 17);
--iter;
TS_ASSERT_EQUALS(iter, container.end());
iter = container.reverse_begin();
iter = container.reverse_erase(iter);
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 33);
iter = container.reverse_erase(iter);
TS_ASSERT_DIFFERS(iter, container.end());
TS_ASSERT_EQUALS(*iter, 17);
iter = container.reverse_erase(iter);
TS_ASSERT_EQUALS(iter, container.end());
TS_ASSERT_EQUALS(container.begin(), container.end());
TS_ASSERT_EQUALS(container.reverse_begin(), container.end());
}
void test_front_back_push_pop() {
Common::List<int> container;
container.push_back( 42);
container.push_back(-23);
TS_ASSERT_EQUALS(container.front(), 42);
TS_ASSERT_EQUALS(container.back(), -23);
container.front() = -17;
container.back() = 163;
TS_ASSERT_EQUALS(container.front(), -17);
TS_ASSERT_EQUALS(container.back(), 163);
container.pop_front();
TS_ASSERT_EQUALS(container.front(), 163);
TS_ASSERT_EQUALS(container.back(), 163);
container.push_front(99);
TS_ASSERT_EQUALS(container.front(), 99);
TS_ASSERT_EQUALS(container.back(), 163);
container.pop_back();
TS_ASSERT_EQUALS(container.front(), 99);
TS_ASSERT_EQUALS(container.back(), 99);
}
};

50
test/common/md5.h Normal file
View File

@@ -0,0 +1,50 @@
#include <cxxtest/TestSuite.h>
#include "common/md5.h"
#include "common/stream.h"
/*
* those are the standard RFC 1321 test vectors
*/
static const char *md5_test_string[] = {
"",
"a",
"abc",
"message digest",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
("12345678901234567890123456789012345678901234567890123456789012"
"345678901234567890")
};
static const char *md5_test_digest[] = {
"d41d8cd98f00b204e9800998ecf8427e",
"0cc175b9c0f1b6a831c399e269772661",
"900150983cd24fb0d6963f7d28e17f72",
"f96b697d7cb7938d525a2f31aaf161d0",
"c3fcd3d76192e4007dfb496cca67e13b",
"d174ab98d277d9f5a5611c2c9f419d9f",
"57edf4a22be3c955ac49da2e2107b67a"
};
class MD5TestSuite : public CxxTest::TestSuite {
public:
void test_computeStreamMD5() {
int i, j;
char output[33];
unsigned char md5sum[16];
for (i = 0; i < 7; i++) {
Common::MemoryReadStream stream((const byte *)md5_test_string[i], strlen(md5_test_string[i]));
Common::computeStreamMD5(stream, md5sum);
for (j = 0; j < 16; j++) {
snprintf(output + j * 2, 3, "%02x", md5sum[j]);
}
Common::String tmp(output);
TS_ASSERT_EQUALS(tmp, md5_test_digest[i]);
}
}
};

63
test/common/memory.h Normal file
View File

@@ -0,0 +1,63 @@
#include <cxxtest/TestSuite.h>
#include "common/memory.h"
class MemoryTestSuite : public CxxTest::TestSuite {
public:
void test_memset16() {
uint16 expected[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
const uint16 step1[8] = { 0, 1, 1, 1, 1, 1, 1, 0 };
const uint16 step2[8] = { 0, 1, 2, 2, 2, 2, 1, 0 };
const uint16 step3[8] = { 0, 1, 2, 3, 3, 2, 1, 0 };
Common::memset16(expected + 1, 1, 6);
TS_ASSERT_EQUALS(memcmp(expected, step1, sizeof(expected)), 0);
Common::memset16(expected + 2, 2, 4);
TS_ASSERT_EQUALS(memcmp(expected, step2, sizeof(expected)), 0);
Common::memset16(expected + 3, 3, 2);
TS_ASSERT_EQUALS(memcmp(expected, step3, sizeof(expected)), 0);
}
void test_memset32() {
uint32 expected[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
const uint32 step1[8] = { 0, 1, 1, 1, 1, 1, 1, 0 };
const uint32 step2[8] = { 0, 1, 2, 2, 2, 2, 1, 0 };
const uint32 step3[8] = { 0, 1, 2, 3, 3, 2, 1, 0 };
Common::memset32(expected + 1, 1, 6);
TS_ASSERT_EQUALS(memcmp(expected, step1, sizeof(expected)), 0);
Common::memset32(expected + 2, 2, 4);
TS_ASSERT_EQUALS(memcmp(expected, step2, sizeof(expected)), 0);
Common::memset32(expected + 3, 3, 2);
TS_ASSERT_EQUALS(memcmp(expected, step3, sizeof(expected)), 0);
}
void test_memset64() {
uint64 expected[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
const uint64 step1[8] = { 0, 1, 1, 1, 1, 1, 1, 0 };
const uint64 step2[8] = { 0, 1, 2, 2, 2, 2, 1, 0 };
const uint64 step3[8] = { 0, 1, 2, 3, 3, 2, 1, 0 };
Common::memset64(expected + 1, 1, 6);
TS_ASSERT_EQUALS(memcmp(expected, step1, sizeof(expected)), 0);
Common::memset64(expected + 2, 2, 4);
TS_ASSERT_EQUALS(memcmp(expected, step2, sizeof(expected)), 0);
Common::memset64(expected + 3, 3, 2);
TS_ASSERT_EQUALS(memcmp(expected, step3, sizeof(expected)), 0);
}
};

View File

@@ -0,0 +1,107 @@
#include <cxxtest/TestSuite.h>
#include "common/memstream.h"
class MemoryReadStreamTestSuite : public CxxTest::TestSuite {
public:
void test_seek_set() {
byte contents[] = { 'a', 'b', '\n', '\n', 'c', '\n' };
Common::MemoryReadStream ms(contents, sizeof(contents));
ms.seek(0, SEEK_SET);
TS_ASSERT_EQUALS(ms.pos(), 0);
TS_ASSERT(!ms.eos());
ms.seek(1, SEEK_SET);
TS_ASSERT_EQUALS(ms.pos(), 1);
TS_ASSERT(!ms.eos());
ms.seek(5, SEEK_SET);
TS_ASSERT_EQUALS(ms.pos(), 5);
TS_ASSERT(!ms.eos());
}
void test_seek_cur() {
byte contents[] = { 'a', 'b', '\n', '\n', 'c' };
Common::MemoryReadStream ms(contents, sizeof(contents));
ms.seek(3, SEEK_CUR);
TS_ASSERT_EQUALS(ms.pos(), 3);
TS_ASSERT(!ms.eos());
ms.seek(-1, SEEK_CUR);
TS_ASSERT_EQUALS(ms.pos(), 2);
TS_ASSERT(!ms.eos());
ms.seek(3, SEEK_CUR);
TS_ASSERT_EQUALS(ms.pos(), 5);
TS_ASSERT(!ms.eos());
ms.seek(-1, SEEK_CUR);
TS_ASSERT_EQUALS(ms.pos(), 4);
TS_ASSERT(!ms.eos());
}
void test_seek_end() {
byte contents[] = { 'a', 'b', '\n', '\n', 'c' };
Common::MemoryReadStream ms(contents, sizeof(contents));
ms.seek(0, SEEK_END);
TS_ASSERT_EQUALS(ms.pos(), 5);
TS_ASSERT(!ms.eos());
ms.seek(-1, SEEK_END);
TS_ASSERT_EQUALS(ms.pos(), 4);
TS_ASSERT(!ms.eos());
ms.seek(-5, SEEK_END);
TS_ASSERT_EQUALS(ms.pos(), 0);
TS_ASSERT(!ms.eos());
}
void test_seek_read_le() {
byte contents[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
Common::MemoryReadStream ms(contents, sizeof(contents));
TS_ASSERT_EQUALS(ms.readUint16LE(), 0x0201UL);
TS_ASSERT_EQUALS(ms.pos(), 2);
TS_ASSERT_EQUALS(ms.readUint32LE(), 0x06050403UL);
TS_ASSERT_EQUALS(ms.pos(), 6);
TS_ASSERT_EQUALS(ms.readUint64LE(), 0x0E0D0C0B0A090807ULL);
TS_ASSERT_EQUALS(ms.pos(), 14);
TS_ASSERT_EQUALS(ms.readByte(), 0x0F);
TS_ASSERT_EQUALS(ms.pos(), 15);
TS_ASSERT(!ms.eos());
}
void test_seek_read_be() {
byte contents[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
Common::MemoryReadStream ms(contents, sizeof(contents));
TS_ASSERT_EQUALS(ms.readUint16BE(), 0x0102UL);
TS_ASSERT_EQUALS(ms.pos(), 2);
TS_ASSERT_EQUALS(ms.readUint32BE(), 0x03040506UL);
TS_ASSERT_EQUALS(ms.pos(), 6);
TS_ASSERT_EQUALS(ms.readUint64BE(), 0x0708090A0B0C0D0EULL);
TS_ASSERT_EQUALS(ms.pos(), 14);
TS_ASSERT_EQUALS(ms.readByte(), 0x0F);
TS_ASSERT_EQUALS(ms.pos(), 15);
TS_ASSERT(!ms.eos());
}
void test_eos() {
byte contents[] = { 1, 2, 3, 4, 5, 6, 7 };
Common::MemoryReadStream ms(contents, sizeof(contents));
// Read after the end of the stream
for (int32 i = 0; i <= ms.size(); ++i)
ms.readByte();
// The eos flag should be set here
TS_ASSERT(ms.eos());
// Seeking should reset the eos flag
ms.seek(0, SEEK_SET);
TS_ASSERT(!ms.eos());
}
};

View File

@@ -0,0 +1,121 @@
#include <cxxtest/TestSuite.h>
#include "common/memstream.h"
class MemoryReadStreamEndianTestSuite : public CxxTest::TestSuite {
public:
void test_seek_set() {
byte contents[] = { 'a', 'b', '\n', '\n', 'c', '\n' };
Common::MemoryReadStreamEndian ms(contents, sizeof(contents), false);
ms.seek(0, SEEK_SET);
TS_ASSERT_EQUALS(ms.pos(), 0);
TS_ASSERT(!ms.eos());
ms.seek(1, SEEK_SET);
TS_ASSERT_EQUALS(ms.pos(), 1);
TS_ASSERT(!ms.eos());
ms.seek(5, SEEK_SET);
TS_ASSERT_EQUALS(ms.pos(), 5);
TS_ASSERT(!ms.eos());
}
void test_seek_cur() {
byte contents[] = { 'a', 'b', '\n', '\n', 'c' };
Common::MemoryReadStreamEndian ms(contents, sizeof(contents), false);
ms.seek(3, SEEK_CUR);
TS_ASSERT_EQUALS(ms.pos(), 3);
TS_ASSERT(!ms.eos());
ms.seek(-1, SEEK_CUR);
TS_ASSERT_EQUALS(ms.pos(), 2);
TS_ASSERT(!ms.eos());
ms.seek(3, SEEK_CUR);
TS_ASSERT_EQUALS(ms.pos(), 5);
TS_ASSERT(!ms.eos());
ms.seek(-1, SEEK_CUR);
TS_ASSERT_EQUALS(ms.pos(), 4);
TS_ASSERT(!ms.eos());
}
void test_seek_end() {
byte contents[] = { 'a', 'b', '\n', '\n', 'c' };
Common::MemoryReadStreamEndian ms(contents, sizeof(contents), false);
ms.seek(0, SEEK_END);
TS_ASSERT_EQUALS(ms.pos(), 5);
TS_ASSERT(!ms.eos());
ms.seek(-1, SEEK_END);
TS_ASSERT_EQUALS(ms.pos(), 4);
TS_ASSERT(!ms.eos());
ms.seek(-5, SEEK_END);
TS_ASSERT_EQUALS(ms.pos(), 0);
TS_ASSERT(!ms.eos());
}
void test_seek_read_le() {
byte contents[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
Common::MemoryReadStreamEndian ms(contents, sizeof(contents), false);
TS_ASSERT_EQUALS(ms.readUint16LE(), 0x0201UL);
TS_ASSERT_EQUALS(ms.pos(), 2);
TS_ASSERT_EQUALS(ms.readUint32LE(), 0x06050403UL);
TS_ASSERT_EQUALS(ms.pos(), 6);
TS_ASSERT_EQUALS(ms.readUint64LE(), 0x0E0D0C0B0A090807ULL);
TS_ASSERT_EQUALS(ms.pos(), 14);
TS_ASSERT_EQUALS(ms.readByte(), 0x0F);
TS_ASSERT_EQUALS(ms.pos(), 15);
TS_ASSERT(!ms.eos());
}
void test_seek_read_be() {
byte contents[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
Common::MemoryReadStreamEndian ms(contents, sizeof(contents), false);
TS_ASSERT_EQUALS(ms.readUint16BE(), 0x0102UL);
TS_ASSERT_EQUALS(ms.pos(), 2);
TS_ASSERT_EQUALS(ms.readUint32BE(), 0x03040506UL);
TS_ASSERT_EQUALS(ms.pos(), 6);
TS_ASSERT_EQUALS(ms.readUint64BE(), 0x0708090A0B0C0D0EULL);
TS_ASSERT_EQUALS(ms.pos(), 14);
TS_ASSERT_EQUALS(ms.readByte(), 0x0F);
TS_ASSERT_EQUALS(ms.pos(), 15);
TS_ASSERT(!ms.eos());
}
void test_seek_read_le2() {
byte contents[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
Common::MemoryReadStreamEndian ms(contents, sizeof(contents), false);
TS_ASSERT_EQUALS(ms.readUint16(), 0x0201UL);
TS_ASSERT_EQUALS(ms.pos(), 2);
TS_ASSERT_EQUALS(ms.readUint32(), 0x06050403UL);
TS_ASSERT_EQUALS(ms.pos(), 6);
TS_ASSERT_EQUALS(ms.readUint64(), 0x0E0D0C0B0A090807ULL);
TS_ASSERT_EQUALS(ms.pos(), 14);
TS_ASSERT_EQUALS(ms.readByte(), 0x0F);
TS_ASSERT_EQUALS(ms.pos(), 15);
TS_ASSERT(!ms.eos());
}
void test_seek_read_be2() {
byte contents[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
Common::MemoryReadStreamEndian ms(contents, sizeof(contents), true);
TS_ASSERT_EQUALS(ms.readUint16(), 0x0102UL);
TS_ASSERT_EQUALS(ms.pos(), 2);
TS_ASSERT_EQUALS(ms.readUint32(), 0x03040506UL);
TS_ASSERT_EQUALS(ms.pos(), 6);
TS_ASSERT_EQUALS(ms.readUint64(), 0x0708090A0B0C0D0EULL);
TS_ASSERT_EQUALS(ms.pos(), 14);
TS_ASSERT_EQUALS(ms.readByte(), 0x0F);
TS_ASSERT_EQUALS(ms.pos(), 15);
TS_ASSERT(!ms.eos());
}
};

View File

@@ -0,0 +1,31 @@
#include <cxxtest/TestSuite.h>
#include "common/memstream.h"
class MemoryWriteStreamTestSuite : public CxxTest::TestSuite {
public:
void test_err() {
byte temp = 0;
Common::MemoryWriteStream stream(&temp, 0);
TS_ASSERT(!stream.err());
// Make sure the error indicator gets set
stream.write(&temp, 1);
TS_ASSERT(stream.err());
// Test whether the error indicator can be cleared
stream.clearErr();
TS_ASSERT(!stream.err());
}
void test_write() {
byte buffer[7] = {};
Common::MemoryWriteStream stream(buffer, sizeof(buffer));
const byte data[7] = { 7, 4, 3, 0, 10, 12, 1 };
stream.write(data, sizeof(data));
TS_ASSERT(memcmp(buffer, data, sizeof(data)) == 0);
TS_ASSERT(!stream.err());
}
};

34
test/common/pack.h Normal file
View File

@@ -0,0 +1,34 @@
#include <cxxtest/TestSuite.h>
#include "common/scummsys.h"
#include <stddef.h>
#include "common/pack-start.h" // START STRUCT PACKING
struct TestStruct {
uint32 x;
byte y;
uint16 z;
uint32 a;
byte b;
} PACKED_STRUCT;
#include "common/pack-end.h" // END STRUCT PACKING
#define OFFS(type,item) (((ptrdiff_t)(&((type *)42)->type::item))-42)
class PackTestSuite : public CxxTest::TestSuite
{
public:
void test_packing() {
TS_ASSERT_EQUALS(sizeof(TestStruct), size_t(4+1+2+4+1));
}
void test_offsets() {
TS_ASSERT_EQUALS(OFFS(TestStruct, x), (ptrdiff_t)0);
TS_ASSERT_EQUALS(OFFS(TestStruct, y), (ptrdiff_t)4);
TS_ASSERT_EQUALS(OFFS(TestStruct, z), (ptrdiff_t)5);
TS_ASSERT_EQUALS(OFFS(TestStruct, a), (ptrdiff_t)7);
TS_ASSERT_EQUALS(OFFS(TestStruct, b), (ptrdiff_t)11);
}
};

608
test/common/path.h Normal file
View File

@@ -0,0 +1,608 @@
#include <cxxtest/TestSuite.h>
#include "test/common/str-helper.h"
#include "common/path.h"
#include "common/hashmap.h"
static const char *TEST_PATH = "parent/dir/file.txt";
static const char *TEST_ESCAPED1_PATH = "|parent/dir/file.txt";
static const char *TEST_ESCAPED2_PATH = "par/ent\\dir\\file.txt";
static const char *TEST_ESCAPED3_PATH = "parent\\dir\\fi|le.txt";
static const char *TEST_BS_PATH = "parent\\dir\\file.txt";
class PathTestSuite : public CxxTest::TestSuite
{
public:
void test_Path() {
Common::Path p;
TS_ASSERT_EQUALS(p.toString(), "");
TS_ASSERT_EQUALS(p.empty(), true);
Common::Path p2(TEST_PATH);
TS_ASSERT_EQUALS(p2.toString(), TEST_PATH);
TS_ASSERT_EQUALS(p2.toString('|'), "parent|dir|file.txt");
TS_ASSERT_EQUALS(p2.toString('\\'), "parent\\dir\\file.txt");
Common::Path p3(TEST_ESCAPED1_PATH);
TS_ASSERT_EQUALS(p3.toString(), TEST_ESCAPED1_PATH);
TS_ASSERT_EQUALS(p3.toString('\\'), "|parent\\dir\\file.txt");
Common::Path p4(TEST_ESCAPED2_PATH, '\\');
TS_ASSERT_EQUALS(p4.toString('\\'), TEST_ESCAPED2_PATH);
Common::Path p5(TEST_ESCAPED3_PATH, '\\');
TS_ASSERT_EQUALS(p5.toString('\\'), TEST_ESCAPED3_PATH);
TS_ASSERT_EQUALS(p5.baseName(), "fi|le.txt");
Common::Path p6(TEST_BS_PATH, '\\');
TS_ASSERT_EQUALS(p6.toString('\\'), TEST_BS_PATH);
#ifndef RELEASE_BUILD
Common::Path::_shownSeparatorCollisionWarning = false;
TS_ASSERT_EQUALS(p3.toString('|'), "|parent|dir|file.txt");
TS_ASSERT_EQUALS(Common::Path::_shownSeparatorCollisionWarning, true);
Common::Path::_shownSeparatorCollisionWarning = false;
TS_ASSERT_EQUALS(p3.toString('i'), "|parentidirifile.txt");
TS_ASSERT_EQUALS(Common::Path::_shownSeparatorCollisionWarning, true);
Common::Path::_shownSeparatorCollisionWarning = false;
TS_ASSERT_EQUALS(p4.toString('/'), "par/ent/dir/file.txt");
TS_ASSERT_EQUALS(Common::Path::_shownSeparatorCollisionWarning, true);
Common::Path::_shownSeparatorCollisionWarning = false;
TS_ASSERT_EQUALS(p6.toString('i'), "parentidirifile.txt");
TS_ASSERT_EQUALS(Common::Path::_shownSeparatorCollisionWarning, true);
#endif
}
void test_clear() {
Common::Path p(TEST_PATH);
TS_ASSERT_EQUALS(p.empty(), false);
p.clear();
TS_ASSERT_EQUALS(p.empty(), true);
TS_ASSERT(p.equals(Common::Path()));
TS_ASSERT(p != Common::Path(TEST_PATH));
}
void test_getLastComponent() {
Common::Path p;
TS_ASSERT_EQUALS(p.getLastComponent().toString(), "");
TS_ASSERT_EQUALS(p.getLastComponent(), Common::Path());
Common::Path p2(TEST_PATH);
TS_ASSERT_EQUALS(p2.getLastComponent().toString(), "file.txt");
TS_ASSERT_EQUALS(p2.getLastComponent(), Common::Path("file.txt"));
Common::Path p3("parent/dir/|file.txt");
TS_ASSERT_EQUALS(p3.getLastComponent().toString(), "|file.txt");
TS_ASSERT_EQUALS(p3.getLastComponent(), Common::Path("|file.txt"));
}
void test_baseName() {
Common::Path p;
TS_ASSERT_EQUALS(p.baseName(), "");
Common::Path p2(TEST_PATH);
TS_ASSERT_EQUALS(p2.baseName(), "file.txt");
Common::Path p3("parent\\dir\\fi/le.txt", '\\');
TS_ASSERT_EQUALS(p3.baseName(), "fi/le.txt");
Common::Path p4("parent/dir/file.txt/");
TS_ASSERT_EQUALS(p4.baseName(), "file.txt");
Common::Path p5("File I/O", ':');
TS_ASSERT_EQUALS(p5.baseName(), "File I/O");
}
void test_getParent() {
Common::Path p;
TS_ASSERT_EQUALS(p.getParent().toString(), "");
Common::Path p2(TEST_PATH);
TS_ASSERT_EQUALS(p2.getParent().toString(), "parent/dir/");
// TODO: should this work?
TS_ASSERT_EQUALS(p2.getParent().getLastComponent().toString(), "dir/");
Common::Path p3(TEST_ESCAPED1_PATH);
TS_ASSERT_EQUALS(p3.getParent().toString(), "|parent/dir/");
// TODO: should this work?
TS_ASSERT_EQUALS(p3.getParent().getLastComponent().toString(), "dir/");
Common::Path p4(TEST_ESCAPED2_PATH, '\\');
TS_ASSERT_EQUALS(p4.getParent().toString('\\'), "par/ent\\dir\\");
// TODO: should this work?
TS_ASSERT_EQUALS(p4.getParent().getLastComponent().toString('\\'), "dir\\");
}
void test_join() {
Common::Path p("dir");
Common::Path p2 = p.join("file.txt");
TS_ASSERT_EQUALS(p2.toString(), "dir/file.txt");
p2 = p.join("");
TS_ASSERT_EQUALS(p2.toString(), "dir");
p2 = p.join(Common::Path());
TS_ASSERT_EQUALS(p2.toString(), "dir");
Common::Path p3;
Common::Path p4 = p3.join("file.txt");
TS_ASSERT_EQUALS(p4.toString(), "file.txt");
p4 = p3.join(Common::String("file.txt"));
TS_ASSERT_EQUALS(p4.toString(), "file.txt");
p4 = p3.join(Common::Path("file.txt"));
TS_ASSERT_EQUALS(p4.toString(), "file.txt");
Common::Path p5(TEST_PATH);
Common::Path p6 = p5.getParent().join("other.txt");
TS_ASSERT_EQUALS(p6.toString(), "parent/dir/other.txt");
p6 = p5.getParent().join("|child\\other.txt", '\\');
TS_ASSERT_EQUALS(p6.toString(), "parent/dir/|child/other.txt");
p6 = p5.getParent().join("/child\\other.txt", '\\');
TS_ASSERT_EQUALS(p6.toString('|'), "parent|dir|/child|other.txt");
p6 = p5.getParent().join(Common::Path("|other.txt"));
TS_ASSERT_EQUALS(p6.toString(), "parent/dir/|other.txt");
p6 = p5.getParent().join(Common::Path("oth/er.txt", '\\'));
TS_ASSERT_EQUALS(p6.toString('\\'), "parent\\dir\\oth/er.txt");
Common::Path p7(TEST_ESCAPED1_PATH);
Common::Path p8 = p7.getParent().join("other.txt");
TS_ASSERT_EQUALS(p8.toString(), "|parent/dir/other.txt");
p8 = p7.getParent().join(Common::Path("other.txt"));
TS_ASSERT_EQUALS(p8.toString(), "|parent/dir/other.txt");
p8 = p7.getParent().join(Common::Path("|other.txt"));
TS_ASSERT_EQUALS(p8.toString(), "|parent/dir/|other.txt");
}
// Ensure we can joinInPlace correctly with leading or trailing separators
void test_joinInPlace() {
Common::Path p("abc/def");
p.joinInPlace("file.txt");
TS_ASSERT_EQUALS(p.toString(), "abc/def/file.txt");
Common::Path p2("xyz/def");
p2.joinInPlace(Common::Path("file.txt"));
TS_ASSERT_EQUALS(p2.toString(), "xyz/def/file.txt");
Common::Path p3("ghi/def/");
p3.joinInPlace(Common::Path("file.txt"));
TS_ASSERT_EQUALS(p3.toString(), "ghi/def/file.txt");
Common::Path p4("123/def");
p4.joinInPlace(Common::Path("/file4.txt"));
TS_ASSERT_EQUALS(p4.toString(), "123/def/file4.txt");
Common::Path p5("abc/def");
p5.joinInPlace(Common::String("file.txt"));
TS_ASSERT_EQUALS(p5.toString(), "abc/def/file.txt");
}
void test_append() {
Common::Path p("abc/def");
p.appendInPlace("");
TS_ASSERT_EQUALS(p.toString(), "abc/def");
Common::Path p2;
p2.appendInPlace("file.txt");
TS_ASSERT_EQUALS(p2.toString(), "file.txt");
Common::Path p3("abc/def");
p3.appendInPlace(Common::Path());
TS_ASSERT_EQUALS(p3.toString(), "abc/def");
Common::Path p4;
p4.appendInPlace(Common::Path("file.txt"));
TS_ASSERT_EQUALS(p4.toString(), "file.txt");
TS_ASSERT_EQUALS(p4.append("a|b", '|').toString(), "file.txta/b");
TS_ASSERT_EQUALS(p4.append(Common::String("a|b"), '|').toString('/'), "file.txta/b");
TS_ASSERT_EQUALS(p4.append(p3).toString(), "file.txtabc/def");
}
void test_appendComponent() {
Common::Path p("abc/def");
Common::Path p2 = p.appendComponent("");
TS_ASSERT_EQUALS(p2.toString(), "abc/def");
Common::Path p3;
Common::Path p4 = p3.appendComponent("file.txt");
TS_ASSERT_EQUALS(p4.toString(), "file.txt");
p2 = p.appendComponent("file.txt");
TS_ASSERT_EQUALS(p2.toString(), "abc/def/file.txt");
p2 = p.appendComponent("fi/le.txt");
TS_ASSERT_EQUALS(p2.toString('\\'), "abc\\def\\fi/le.txt");
Common::Path p5("abc\\de/f", '\\');
Common::Path p6 = p5.appendComponent(Common::String("fi/le.txt"));
TS_ASSERT_EQUALS(p6.toString('\\'), "abc\\de/f\\fi/le.txt");
}
void test_separator() {
Common::Path p(TEST_PATH, '\\');
TS_ASSERT_EQUALS(p.getLastComponent().toString(), TEST_PATH);
TS_ASSERT_EQUALS(p.getParent().toString(), "");
Common::Path p2(TEST_PATH, 'e');
TS_ASSERT_EQUALS(p2.getLastComponent().toString(), ".txt");
TS_ASSERT_EQUALS(p2.getParent().toString('#'), "par#nt/dir/fil#");
TS_ASSERT_EQUALS(p2.getParent().getParent().toString('#'), "par#");
}
void test_splitComponents() {
Common::Path p(TEST_PATH);
Common::StringArray array = p.splitComponents();
TS_ASSERT_EQUALS(array.size(), 3u);
Common::StringArray::iterator iter = array.begin();
TS_ASSERT_EQUALS(*iter, "parent");
++iter;
TS_ASSERT_EQUALS(*iter, "dir");
++iter;
TS_ASSERT_EQUALS(*iter, "file.txt");
Common::Path p2;
Common::StringArray array2 = p2.splitComponents();
TS_ASSERT_EQUALS(array2.size(), 1u);
Common::StringArray::iterator iter2 = array2.begin();
TS_ASSERT_EQUALS(*iter2, "");
Common::Path p3(TEST_ESCAPED1_PATH);
Common::StringArray array3 = p3.splitComponents();
TS_ASSERT_EQUALS(array3.size(), 3u);
Common::StringArray::iterator iter3 = array3.begin();
TS_ASSERT_EQUALS(*iter3, "|parent");
++iter3;
TS_ASSERT_EQUALS(*iter3, "dir");
++iter3;
TS_ASSERT_EQUALS(*iter3, "file.txt");
}
void test_joinComponents() {
Common::StringArray array;
Common::Path p = Common::Path::joinComponents(array);
TS_ASSERT_EQUALS(p.toString(), "");
array.push_back("");
p = Common::Path::joinComponents(array);
TS_ASSERT_EQUALS(p.toString(), "");
Common::StringArray array2;
array2.push_back("par/ent");
array2.push_back("dir");
array2.push_back("file.txt");
p = Common::Path::joinComponents(array2);
TS_ASSERT_EQUALS(p.toString('\\'), TEST_ESCAPED2_PATH);
}
void test_removeTrailingSeparators() {
Common::Path p;
p.removeTrailingSeparators();
TS_ASSERT_EQUALS(p.toString(), "");
Common::Path p2(TEST_PATH);
p2.removeTrailingSeparators();
TS_ASSERT_EQUALS(p2.toString(), TEST_PATH);
Common::Path p3("parent/dir/file.txt///");
p3.removeTrailingSeparators();
TS_ASSERT_EQUALS(p3.toString(), "parent/dir/file.txt");
Common::Path p4("//");
p4.removeTrailingSeparators();
TS_ASSERT_EQUALS(p4.toString(), "/");
}
void test_isRelativeTo() {
Common::Path p, p1(TEST_PATH), p2(TEST_ESCAPED1_PATH);
// Everything is relative to empty
TS_ASSERT_EQUALS(p1.isRelativeTo(p), true);
TS_ASSERT_EQUALS(p2.isRelativeTo(p), true);
// Everything is relative to itself
TS_ASSERT_EQUALS(p1.isRelativeTo(p1), true);
TS_ASSERT_EQUALS(p2.isRelativeTo(p2), true);
// A path is not relative to empty one
TS_ASSERT_EQUALS(p.isRelativeTo(p1), false);
TS_ASSERT_EQUALS(p1.isRelativeTo(Common::Path("parent/dir")), true);
TS_ASSERT_EQUALS(p1.isRelativeTo(Common::Path("parent/dir/")), true);
TS_ASSERT_EQUALS(p1.isRelativeTo(Common::Path("parent/dir/fi")), false);
TS_ASSERT_EQUALS(p1.isRelativeTo(Common::Path("|parent/dir")), false);
Common::Path p3("parent\\dir\\fi/le.txt", '\\');
TS_ASSERT_EQUALS(p3.isRelativeTo(Common::Path("parent/dir")), true);
TS_ASSERT_EQUALS(p3.isRelativeTo(Common::Path("parent/dir/")), true);
TS_ASSERT_EQUALS(p3.isRelativeTo(Common::Path("parent/dir/fi")), false);
TS_ASSERT_EQUALS(p3.isRelativeTo(Common::Path("parent/dir/fa")), false);
Common::Path p4("par|ent\\dir\\fi/le.txt", '\\');
TS_ASSERT_EQUALS(p4.isRelativeTo(Common::Path("par|ent/dir")), true);
}
void test_relativeTo() {
Common::Path p, p1(TEST_PATH), p2(TEST_ESCAPED1_PATH);
// Everything is relative to empty
TS_ASSERT_EQUALS(p1.relativeTo(p).toString(), TEST_PATH);
TS_ASSERT_EQUALS(p2.relativeTo(p).toString(), TEST_ESCAPED1_PATH);
// Everything is relative to itself
TS_ASSERT_EQUALS(p1.relativeTo(p1), p);
TS_ASSERT_EQUALS(p2.relativeTo(p2), p);
// A path is not relative to empty one
TS_ASSERT_EQUALS(p.relativeTo(p1), p);
TS_ASSERT_EQUALS(p1.relativeTo(Common::Path("parent/dir")).toString(), "file.txt");
TS_ASSERT_EQUALS(p1.relativeTo(Common::Path("parent/dir/")).toString(), "file.txt");
TS_ASSERT_EQUALS(p1.relativeTo(Common::Path("parent/dir/fi")), p1);
TS_ASSERT_EQUALS(p1.relativeTo(Common::Path("|parent/dir")), p1);
Common::Path p3("parent\\dir\\fi/le.txt", '\\');
TS_ASSERT_EQUALS(p3.relativeTo(Common::Path("parent/dir")).toString('\\'), "fi/le.txt");
TS_ASSERT_EQUALS(p3.relativeTo(Common::Path("parent/dir/")).toString('\\'), "fi/le.txt");
TS_ASSERT_EQUALS(p3.relativeTo(Common::Path("parent/dir/fi")), p3);
TS_ASSERT_EQUALS(p3.relativeTo(Common::Path("parent/dir/fa")), p3);
Common::Path p4("par|ent\\dir\\fi/le.txt", '\\');
TS_ASSERT_EQUALS(p4.relativeTo(Common::Path("par|ent/dir")).toString('\\'), "fi/le.txt");
Common::Path p5("par|ent\\dir\\\\\\fi/le.txt", '\\');
TS_ASSERT_EQUALS(p5.relativeTo(Common::Path("par|ent/dir")).toString('\\'), "fi/le.txt");
}
void test_normalize() {
TS_ASSERT_EQUALS(Common::Path("/", '/').normalize().toString(), "/");
TS_ASSERT_EQUALS(Common::Path("///", '/').normalize().toString(), "/");
TS_ASSERT_EQUALS(Common::Path("/foo/bar", '/').normalize().toString(), "/foo/bar");
TS_ASSERT_EQUALS(Common::Path("/foo//bar/", '/').normalize().toString(), "/foo/bar");
TS_ASSERT_EQUALS(Common::Path("/foo/./bar", '/').normalize().toString(), "/foo/bar");
TS_ASSERT_EQUALS(Common::Path("/foo//./bar//", '/').normalize().toString(), "/foo/bar");
TS_ASSERT_EQUALS(Common::Path("/foo//.bar//", '/').normalize().toString(), "/foo/.bar");
TS_ASSERT_EQUALS(Common::Path("", '/').normalize().toString(), "");
TS_ASSERT_EQUALS(Common::Path("foo/bar", '/').normalize().toString(), "foo/bar");
TS_ASSERT_EQUALS(Common::Path("foo//bar/", '/').normalize().toString(), "foo/bar");
TS_ASSERT_EQUALS(Common::Path("foo/./bar", '/').normalize().toString(), "foo/bar");
TS_ASSERT_EQUALS(Common::Path("foo//./bar//", '/').normalize().toString(), "foo/bar");
TS_ASSERT_EQUALS(Common::Path("foo//.bar//", '/').normalize().toString(), "foo/.bar");
TS_ASSERT_EQUALS(Common::Path("..", '/').normalize().toString(), "..");
TS_ASSERT_EQUALS(Common::Path("../", '/').normalize().toString(), "..");
TS_ASSERT_EQUALS(Common::Path("/..", '/').normalize().toString(), "/..");
TS_ASSERT_EQUALS(Common::Path("../bar", '/').normalize().toString(), "../bar");
TS_ASSERT_EQUALS(Common::Path("foo//../", '/').normalize().toString(), "");
TS_ASSERT_EQUALS(Common::Path("foo/../bar", '/').normalize().toString(), "bar");
TS_ASSERT_EQUALS(Common::Path("foo//../bar//", '/').normalize().toString(), "bar");
TS_ASSERT_EQUALS(Common::Path("foo//..bar//", '/').normalize().toString(), "foo/..bar");
TS_ASSERT_EQUALS(Common::Path("foo/../../bar//", '/').normalize().toString(), "../bar");
TS_ASSERT_EQUALS(Common::Path("../foo/../bar", '/').normalize().toString(), "../bar");
TS_ASSERT_EQUALS(Common::Path("../../foo/bar/", '/').normalize().toString(), "../../foo/bar");
TS_ASSERT_EQUALS(Common::Path("foo/../|bar", '/').normalize().toString(), "|bar");
TS_ASSERT_EQUALS(Common::Path("foo/^..^bar", '^').normalize().toString('^'), "bar");
TS_ASSERT_EQUALS(Common::Path("foo^..^bar/", '^').normalize().toString('^'), "bar/");
}
void test_punycode() {
Common::Path p;
Common::Path p2 = p.punycodeDecode();
TS_ASSERT_EQUALS(p.toString(), "");
Common::Path p3("parent/dir/xn--Sound Manager 3.1 SoundLib-lba84k/Sound");
Common::Path p4 = p3.punycodeDecode();
TS_ASSERT_EQUALS(p4.toString(':'), "parent:dir:Sound Manager 3.1 / SoundLib:Sound");
Common::Path p5 = p4.punycodeEncode();
TS_ASSERT_EQUALS(p5.toString('/'), "parent/dir/xn--Sound Manager 3.1 SoundLib-lba84k/Sound");
Common::Path p6 = p3.punycodeEncode();
TS_ASSERT_EQUALS(p6.toString('/'), "parent/dir/xn--xn--Sound Manager 3.1 SoundLib-lba84k-/Sound");
Common::Path p7 = p6.punycodeDecode();
TS_ASSERT_EQUALS(p7.toString('/'), "parent/dir/xn--Sound Manager 3.1 SoundLib-lba84k/Sound");
typedef Common::HashMap<Common::Path, bool,
Common::Path::IgnoreCaseAndMac_Hash, Common::Path::IgnoreCaseAndMac_EqualTo> TestPathMap;
TestPathMap map;
map.setVal(p3, false);
TS_ASSERT_EQUALS(map.size(), 1u);
map.setVal(p4, false);
TS_ASSERT_EQUALS(map.size(), 1u);
map.setVal(p5, false);
TS_ASSERT_EQUALS(map.size(), 1u);
map.setVal(p, false);
TS_ASSERT_EQUALS(map.size(), 2u);
}
void test_lowerupper() {
Common::Path p2(TEST_PATH);
p2.toUppercase();
TS_ASSERT_EQUALS(p2.toString('/'), "PARENT/DIR/FILE.TXT");
p2 = TEST_PATH;
p2.toLowercase();
TS_ASSERT_EQUALS(p2.toString('/'), TEST_PATH);
Common::Path p3(TEST_ESCAPED1_PATH);
p3.toUppercase();
TS_ASSERT_EQUALS(p3.toString('/'), "|PARENT/DIR/FILE.TXT");
Common::String s3(TEST_ESCAPED1_PATH);
s3.toUppercase();
p3 = s3;
p3.toLowercase();
TS_ASSERT_EQUALS(p3.toString('/'), TEST_ESCAPED1_PATH);
}
void test_caseinsensitive() {
Common::Path p;
Common::Path p2("parent:dir:Sound Manager 3.1 / SoundLib:Sound", ':');
Common::Path p3("parent:dir:sound manager 3.1 / soundlib:sound", ':');
Common::Path p4("parent/dir/xn--Sound Manager 3.1 SoundLib-lba84k/Sound");
typedef Common::HashMap<Common::Path, bool,
Common::Path::IgnoreCase_Hash, Common::Path::IgnoreCase_EqualTo> TestPathMap;
TestPathMap map;
map.setVal(p2, false);
TS_ASSERT_EQUALS(map.size(), 1u);
map.setVal(p3, false);
TS_ASSERT_EQUALS(map.size(), 1u);
map.setVal(p4, false);
TS_ASSERT_EQUALS(map.size(), 2u);
map.setVal(p, false);
TS_ASSERT_EQUALS(map.size(), 3u);
}
void test_casesensitive() {
Common::Path p2("parent:dir:Sound Manager 3.1 / SoundLib:Sound", ':');
Common::Path p3("parent:dir:sound manager 3.1 / soundlib:sound", ':');
Common::Path p4("parent/dir/xn--Sound Manager 3.1 SoundLib-lba84k/Sound");
TS_ASSERT_DIFFERS(p2.hash(), p3.hash());
TS_ASSERT_DIFFERS(p2.hash(), p4.hash());
TS_ASSERT_DIFFERS(p3.hash(), p4.hash());
}
void test_matchString() {
TS_ASSERT(Common::Path("").matchPattern(""));
TS_ASSERT(Common::Path("a").matchPattern("*"));
TS_ASSERT(Common::Path("monkey.s01").matchPattern("*"));
TS_ASSERT(!Common::Path("").matchPattern("?"));
TS_ASSERT(Common::Path("a").matchPattern("?"));
TS_ASSERT(!Common::Path("monkey.s01").matchPattern("?"));
TS_ASSERT(Common::Path("monkey.s01").matchPattern("monkey.s??"));
TS_ASSERT(Common::Path("monkey.s99").matchPattern("monkey.s??"));
TS_ASSERT(!Common::Path("monkey.s101").matchPattern("monkey.s??"));
TS_ASSERT(Common::Path("monkey.s01").matchPattern("monkey.s?1"));
TS_ASSERT(!Common::Path("monkey.s99").matchPattern("monkey.s?1"));
TS_ASSERT(!Common::Path("monkey.s101").matchPattern("monkey.s?1"));
TS_ASSERT(Common::Path("monkey.s01").matchPattern("monkey.s*"));
TS_ASSERT(Common::Path("monkey.s99").matchPattern("monkey.s*"));
TS_ASSERT(Common::Path("monkey.s101").matchPattern("monkey.s*"));
TS_ASSERT(Common::Path("monkey.s01").matchPattern("monkey.s*1"));
TS_ASSERT(!Common::Path("monkey.s99").matchPattern("monkey.s*1"));
TS_ASSERT(Common::Path("monkey.s101").matchPattern("monkey.s*1"));
TS_ASSERT(Common::Path("monkey.s01").matchPattern("monkey.s##"));
TS_ASSERT(!Common::Path("monkey.s01").matchPattern("monkey.###"));
TS_ASSERT(Common::Path("monkey.s0#").matchPattern("monkey.s0\\#"));
TS_ASSERT(!Common::Path("monkey.s0#").matchPattern("monkey.s0#"));
TS_ASSERT(!Common::Path("monkey.s01").matchPattern("monkey.s0\\#"));
TS_ASSERT(Common::Path("test/monkey.s01").matchPattern("*/*"));
TS_ASSERT(!Common::Path("test/monkey.s01").matchPattern("|test/*"));
TS_ASSERT(Common::Path("|test/monkey.s01").matchPattern("*/*"));
TS_ASSERT(!Common::Path("test/monkey.s01").matchPattern("*"));
TS_ASSERT(!Common::Path("test/monkey.s01").matchPattern(Common::Path("test\\fi/le.txt", '\\')));
}
// These tests are here to exercise cases currently not used
// This allow to reach 100% code coverage (except unescape error)
void test_findLastSeparator() {
Common::Path p(TEST_PATH);
TS_ASSERT_EQUALS(p.findLastSeparator(), 10u);
Common::Path p2("file.txt");
TS_ASSERT_EQUALS(p2.findLastSeparator(), Common::String::npos);
}
void test_extract() {
Common::Path p(TEST_PATH);
Common::Path p2 = p.extract(p._str.c_str(), p._str.c_str());
TS_ASSERT_EQUALS(p2, Common::Path());
Common::Path p3("file.txt");
TS_ASSERT_EQUALS(p3.extract(p3._str.c_str()), p3);
}
void test_canUnescape() {
TS_ASSERT(Common::Path::canUnescape(true, true, ""));
}
void test_removeExtension() {
Common::Path p(TEST_PATH);
p.removeExtension();
TS_ASSERT_EQUALS(p.toString(), "parent/dir/file");
Common::Path p2("parent/dir/file.txt.gz");
p2.removeExtension();
TS_ASSERT_EQUALS(p2.toString(), "parent/dir/file.txt");
Common::Path p3("parent/dir/file.");
p3.removeExtension();
TS_ASSERT_EQUALS(p3.toString(), "parent/dir/file");
Common::Path p4("parent/dir/file.txt.txt");
p4.removeExtension(".txt");
TS_ASSERT_EQUALS(p4.toString(), "parent/dir/file.txt");
Common::Path p5("parent/dir/file.txt");
p5.removeExtension(".txt");
TS_ASSERT_EQUALS(p5.toString(), "parent/dir/file");
Common::Path p6("parent/dir.txt/file.gz");
p6.removeExtension(".txt");
TS_ASSERT_EQUALS(p6.toString(), "parent/dir.txt/file.gz");
Common::Path p7("parent/dir/xn--Sound Manager 3.1 SoundLib-lba84k/Sound.txt");
p7.removeExtension(".txt");
TS_ASSERT_EQUALS(p7.toString(), "parent/dir/xn--Sound Manager 3.1 SoundLib-lba84k/Sound");
Common::Path p8("parent/dir/Sound/xn--dialred.dir-qa21d");
p8.removeExtension(".dir");
TS_ASSERT_EQUALS(p8.toString(), "parent/dir/Sound/xn--dialred.dir-qa21d");
Common::Path p9("parent/dir/.ab");
p9.removeExtension();
TS_ASSERT_EQUALS(p9.toString(), "parent/dir/");
Common::Path p10("parent/dir/.ab");
p10.removeExtension(".abc");
TS_ASSERT_EQUALS(p10.toString(), "parent/dir/.ab");
Common::Path p11(".ab");
p11.removeExtension(".abc");
TS_ASSERT_EQUALS(p11.toString(), ".ab");
Common::Path p12("test.dir");
p12.removeExtension(".dir");
TS_ASSERT_EQUALS(p12.toString(), "test");
Common::Path p13("test.dir");
p13.removeExtension(".txt");
TS_ASSERT_EQUALS(p13.toString(), "test.dir");
Common::Path p14("test.dir.txt");
p14.removeExtension(".dir");
TS_ASSERT_EQUALS(p14.toString(), "test.dir.txt");
Common::Path p15(".dir");
p15.removeExtension(".dir");
TS_ASSERT_EQUALS(p15.toString(), "");
}
};

172
test/common/ptr.h Normal file
View File

@@ -0,0 +1,172 @@
#include <cxxtest/TestSuite.h>
#include "common/ptr.h"
class PtrTestSuite : public CxxTest::TestSuite {
public:
struct A {
int a;
};
struct B : public A {
int b;
};
// A simple class which keeps track of all its instances
class InstanceCountingClass {
public:
static int count;
InstanceCountingClass() { count++; }
InstanceCountingClass(const InstanceCountingClass&) { count++; }
~InstanceCountingClass() { count--; }
};
void test_deletion() {
TS_ASSERT_EQUALS(InstanceCountingClass::count, 0);
{
Common::SharedPtr<InstanceCountingClass> p1(new InstanceCountingClass());
TS_ASSERT_EQUALS(InstanceCountingClass::count, 1);
Common::ScopedPtr<InstanceCountingClass> p2(new InstanceCountingClass());
TS_ASSERT_EQUALS(InstanceCountingClass::count, 2);
}
TS_ASSERT_EQUALS(InstanceCountingClass::count, 0);
}
struct CustomDeleter {
static bool invoked;
void operator()(int *object) {
invoked = true;
delete object;
}
};
void test_scoped_deleter() {
CustomDeleter::invoked = false;
{
Common::ScopedPtr<int, CustomDeleter> a(new int(0));
TS_ASSERT(!CustomDeleter::invoked);
}
TS_ASSERT(CustomDeleter::invoked);
}
void test_disposable_deleter() {
CustomDeleter::invoked = false;
{
Common::DisposablePtr<int, CustomDeleter> a1(new int, DisposeAfterUse::YES);
TS_ASSERT(!CustomDeleter::invoked);
}
TS_ASSERT(CustomDeleter::invoked);
CustomDeleter::invoked = false;
int *a = new int;
{
Common::DisposablePtr<int, CustomDeleter> a2(a, DisposeAfterUse::NO);
}
TS_ASSERT(!CustomDeleter::invoked);
delete a;
}
void test_scoped_deref() {
A *raw = new A();
raw->a = 123;
Common::ScopedPtr<A> a(raw);
TS_ASSERT_EQUALS(&*a, &*raw);
TS_ASSERT_EQUALS(a->a, raw->a);
}
void test_disposable_deref() {
A *raw = new A();
raw->a = 123;
Common::DisposablePtr<A> a(raw, DisposeAfterUse::YES);
TS_ASSERT_EQUALS(&*a, &*raw);
TS_ASSERT_EQUALS(a->a, raw->a);
}
void test_assign() {
Common::SharedPtr<int> p1(new int(1));
TS_ASSERT(p1.unique());
TS_ASSERT_EQUALS(*p1, 1);
{
Common::SharedPtr<int> p2 = p1;
TS_ASSERT(!p1.unique());
TS_ASSERT_EQUALS(p1.refCount(), p2.refCount());
TS_ASSERT_EQUALS(p1.refCount(), 2);
TS_ASSERT_EQUALS(p1, p2);
TS_ASSERT_EQUALS(*p2, 1);
{
Common::SharedPtr<int> p3;
p3 = p2;
TS_ASSERT_EQUALS(p3, p2);
TS_ASSERT_EQUALS(p3, p1);
TS_ASSERT_EQUALS(p1.refCount(), 3);
TS_ASSERT_EQUALS(*p3, 1);
*p3 = 0;
TS_ASSERT_EQUALS(*p3, 0);
}
TS_ASSERT_EQUALS(*p2, 0);
TS_ASSERT_EQUALS(p1.refCount(), 2);
}
TS_ASSERT_EQUALS(*p1, 0);
TS_ASSERT(p1.unique());
}
template<class T>
struct Deleter {
bool *test;
void operator()(T *ptr) { *test = true; delete ptr; }
};
void test_deleter() {
Deleter<int> myDeleter;
bool test = false;
myDeleter.test = &test;
{
Common::SharedPtr<int> p(new int(1), myDeleter);
}
TS_ASSERT_EQUALS(test, true);
}
void test_compare() {
Common::SharedPtr<int> p1(new int(1));
Common::SharedPtr<int> p2;
TS_ASSERT(p1);
TS_ASSERT(!p2);
TS_ASSERT(p1 != 0);
TS_ASSERT(p2 == 0);
p1.reset();
TS_ASSERT(!p1);
}
void test_cast() {
Common::SharedPtr<B> b(new B);
Common::SharedPtr<A> a(b);
a = b;
}
void test_weak_ptr() {
Common::SharedPtr<B> b(new B);
Common::WeakPtr<A> a(b);
TS_ASSERT(a.lock() == b);
TS_ASSERT(!a.expired());
b.reset();
TS_ASSERT(a.expired());
TS_ASSERT(!a.lock());
}
};
int PtrTestSuite::InstanceCountingClass::count = 0;
bool PtrTestSuite::CustomDeleter::invoked = false;

42
test/common/punycode.h Normal file
View File

@@ -0,0 +1,42 @@
#include <cxxtest/TestSuite.h>
#include "common/punycode.h"
/**
* Test suite for the functions in common/util.h
*/
static const char *strings[] = {
"Icon\r", "xn--Icon-ja6e", "1",
"ascii", "ascii", "0",
"ends with dot .", "xn--ends with dot .-", "1",
"ends with space ", "xn--ends with space -", "1",
"バッドデイ(Power PC)", "xn--(Power PC)-jx4ilmwb1a7h", "1",
"Hello*", "xn--Hello-la10a", "1",
"File I/O", "xn--File IO-oa82b", "1",
"HDにコピーして下さい。G3", "xn--HDG3-rw3c5o2dpa9kzb2170dd4tzyda5j4k", "1",
"Buried in Time™ Demo", "xn--Buried in Time Demo-eo0l", "1",
"•Main Menu", "xn--Main Menu-zd0e", "1",
"Spaceship Warlock™", "xn--Spaceship Warlock-306j", "1",
"ワロビージャックの大冒険<デモ>", "xn--baa0pja0512dela6bueub9gshf1k1a1rt742c060a2x4u", "1",
"Jönssonligan går på djupet.exe", "xn--Jnssonligan gr p djupet.exe-glcd70c", "1",
"Jönssonligan.exe", "xn--Jnssonligan.exe-8sb", "1",
"G3フォルダ", "xn--G3-3g4axdtexf", "1",
"Big[test]", "Big[test]", "0",
"Where \\ Do <you> Want / To: G* ? ;Unless=nowhere,or|\"(everything)/\":*|\\?%<>,;=", "xn--Where Do you Want To G ;Unless=nowhere,or(everything),;=-5baedgdcbtamaaaaaaaaa99woa3wnnmb82aqb71ekb9g3c1f1cyb7bx6rfcv2pxa", "1",
"Buried in Timeェ Demo", "xn--Buried in Time Demo-yp97h", "1",
0
};
class PunycodeTestSuite : public CxxTest::TestSuite {
public:
void test_punycode() {
for (const char **a = strings; *a; a += 3) {
Common::U32String string_in(a[0]);
Common::String string_out(a[1]);
bool need = (a[2][0] == '1');
TS_ASSERT_EQUALS(punycode_decodefilename(string_out), string_in);
TS_ASSERT_EQUALS(punycode_encodefilename(string_in), string_out);
TS_ASSERT_EQUALS(punycode_needEncode(string_in), need);
}
}
};

82
test/common/queue.h Normal file
View File

@@ -0,0 +1,82 @@
#include <cxxtest/TestSuite.h>
#include "common/queue.h"
class QueueTestSuite : public CxxTest::TestSuite {
public:
void test_empty_clear() {
Common::Queue<int> queue;
TS_ASSERT(queue.empty());
queue.push(1);
queue.push(2);
TS_ASSERT(!queue.empty());
queue.clear();
TS_ASSERT(queue.empty());
}
void test_size() {
Common::Queue<int> queue;
TS_ASSERT_EQUALS(queue.size(), 0);
queue.push(5);
TS_ASSERT_EQUALS(queue.size(), 1);
queue.push(9);
queue.push(0);
TS_ASSERT_EQUALS(queue.size(), 3);
queue.pop();
TS_ASSERT_EQUALS(queue.size(), 2);
}
void test_front_back_push_pop() {
Common::Queue<int> container;
container.push( 42);
container.push(-23);
TS_ASSERT_EQUALS(container.front(), 42);
TS_ASSERT_EQUALS(container.back(), -23);
container.front() = -17;
container.back() = 163;
TS_ASSERT_EQUALS(container.front(), -17);
TS_ASSERT_EQUALS(container.back(), 163);
container.pop();
TS_ASSERT_EQUALS(container.front(), 163);
TS_ASSERT_EQUALS(container.back(), 163);
}
void test_assign() {
Common::Queue<int> q1, q2;
for (int i = 0; i < 5; ++i) {
q1.push(i);
q2.push(4-i);
}
Common::Queue<int> q3(q1);
for (int i = 0; i < 5; ++i) {
TS_ASSERT_EQUALS(q3.front(), i);
q3.pop();
}
TS_ASSERT(q3.empty());
q3 = q2;
for (int i = 4; i >= 0; --i) {
TS_ASSERT_EQUALS(q3.front(), i);
q3.pop();
}
TS_ASSERT(q3.empty());
TS_ASSERT(!q1.empty());
TS_ASSERT(!q2.empty());
}
};

144
test/common/rational.h Normal file
View File

@@ -0,0 +1,144 @@
#include <cxxtest/TestSuite.h>
#include "common/rational.h"
class RationalTestSuite : public CxxTest::TestSuite {
public:
void test_operators() {
Common::Rational r0(6, 3);
Common::Rational r1(1, 2);
Common::Rational r2(62, 2);
Common::Rational r3(34, 4);
Common::Rational r4 = (r0 + r1) * 3;
Common::Rational r5 = (r2 - r3) / 3;
Common::Rational r6 = r5 - 1;
TS_ASSERT(r4 == r5);
TS_ASSERT(!(r4 != r5));
TS_ASSERT(r4 != r6);
TS_ASSERT(!(r4 == r6));
TS_ASSERT(-r4 == -r5);
TS_ASSERT(r0 == 2);
TS_ASSERT(!(r0 != 2));
TS_ASSERT(!(r3 == 2));
TS_ASSERT(r3 != 2);
TS_ASSERT( r4 > r6);
TS_ASSERT( r4 >= r6);
TS_ASSERT(!(r4 < r6));
TS_ASSERT(!(r4 <= r6));
TS_ASSERT( r4 > 7);
TS_ASSERT( r4 >= 7);
TS_ASSERT(!(r4 < 7));
TS_ASSERT(!(r4 <= 7));
TS_ASSERT( 7 < r4);
TS_ASSERT( 7 <= r4);
TS_ASSERT(!(7 > r4));
TS_ASSERT(!(7 >= r4));
}
void test_assign() {
Common::Rational r0(6, 3);
Common::Rational r1(1, 2);
TS_ASSERT_EQUALS(r0, 2);
TS_ASSERT_EQUALS(r1, Common::Rational(1, 2));
r0 = r1;
TS_ASSERT_EQUALS(r0, r1);
TS_ASSERT_EQUALS(r0, Common::Rational(1, 2));
}
void test_negative() {
Common::Rational r0(6, 3);
Common::Rational r1(1, 2);
r0 = -r0;
r1 = -r1;
TS_ASSERT_EQUALS(r0, -2);
TS_ASSERT_EQUALS(r1, Common::Rational(-1, 2));
TS_ASSERT_EQUALS(r1, Common::Rational(1, -2));
TS_ASSERT_EQUALS(r1, Common::Rational(-25, 50));
TS_ASSERT_EQUALS(r1, Common::Rational(25, -50));
}
void test_add_sub() {
const Common::Rational r0(6, 3);
const Common::Rational r1(1, 2);
TS_ASSERT_EQUALS(r0 + r1, Common::Rational(5, 2));
TS_ASSERT_EQUALS(r1 + r0, Common::Rational(5, 2));
TS_ASSERT_EQUALS(r0 - r1, Common::Rational(3, 2));
TS_ASSERT_EQUALS(r1 - r0, Common::Rational(-3, 2));
TS_ASSERT_EQUALS(1 + r1, Common::Rational(3, 2));
TS_ASSERT_EQUALS(r1 + 1, Common::Rational(3, 2));
TS_ASSERT_EQUALS(1 - r1, Common::Rational(1, 2));
TS_ASSERT_EQUALS(r1 - 1, Common::Rational(-1, 2));
}
void test_add_sub2() {
// Make sure cancelation works correctly
const Common::Rational r0(4, 15); // = 8 / 30
const Common::Rational r1(1, 6); // = 5 / 30
TS_ASSERT_EQUALS(r0 + r1, Common::Rational(13, 30));
TS_ASSERT_EQUALS(r1 + r0, Common::Rational(13, 30));
TS_ASSERT_EQUALS(r0 - r1, Common::Rational(1, 10));
TS_ASSERT_EQUALS(r1 - r0, Common::Rational(-1, 10));
TS_ASSERT_EQUALS(1 + r1, Common::Rational(7, 6));
TS_ASSERT_EQUALS(r1 + 1, Common::Rational(7, 6));
TS_ASSERT_EQUALS(1 - r1, Common::Rational(5, 6));
TS_ASSERT_EQUALS(r1 - 1, Common::Rational(-5, 6));
}
void test_mul() {
const Common::Rational r0(6, 3);
const Common::Rational r1(1, 2);
const Common::Rational r2(15, 14);
const Common::Rational r3(7,3);
const Common::Rational r4(5,2);
TS_ASSERT_EQUALS(r0 * r1, 1);
TS_ASSERT_EQUALS(r2 * r3, r4);
TS_ASSERT_EQUALS((-r2) * r3, -r4);
TS_ASSERT_EQUALS(r2 * (-r3), -r4);
TS_ASSERT_EQUALS((-r2) * (-r3), r4);
TS_ASSERT_EQUALS(r1 * 2, 1);
TS_ASSERT_EQUALS(2 * r1, 1);
}
void test_div() {
Common::Rational r0(6, 3);
Common::Rational r1(1, 2);
TS_ASSERT_EQUALS(r0 / r1, 4);
TS_ASSERT_EQUALS(r1 / 2, Common::Rational(1, 4));
TS_ASSERT_EQUALS(2 / r1, Common::Rational(4, 1));
}
void test_isOne() {
Common::Rational r0(5, 5);
Common::Rational r1(1, 2);
Common::Rational r2(2, 1);
Common::Rational r3(1, 1);
TS_ASSERT(r0.isOne());
TS_ASSERT(!r1.isOne());
TS_ASSERT(!r2.isOne());
TS_ASSERT(r3.isOne());
}
};

62
test/common/rect.h Normal file
View File

@@ -0,0 +1,62 @@
#include <cxxtest/TestSuite.h>
#include "common/rect.h"
class RectTestSuite : public CxxTest::TestSuite
{
public:
void test_point_sqrDist() {
Common::Point p0;
Common::Point p11(1, 1);
Common::Point p21(2, 1);
Common::Point p23(2, 3);
Common::Point p32(3, 2);
TS_ASSERT_EQUALS(p0.sqrDist(p11), (uint) 2);
TS_ASSERT_EQUALS(p0.sqrDist(p21), (uint) 5);
TS_ASSERT_EQUALS(p0.sqrDist(p23), p0.sqrDist(p32));
TS_ASSERT_EQUALS(p11.sqrDist(p11), (uint) 0);
TS_ASSERT_EQUALS(p11.sqrDist(p23), (uint) 5);
}
void test_intersects() {
TS_ASSERT(Common::Rect(0, 0, 2, 2).intersects(Common::Rect(0, 0, 1, 1)));
TS_ASSERT(Common::Rect(0, 0, 2, 2).intersects(Common::Rect(1, 1, 2, 2)));
TS_ASSERT(!Common::Rect(0, 0, 1, 1).intersects(Common::Rect(1, 1, 2, 2)));
}
void test_contains() {
Common::Rect r0;
Common::Rect r1(0, 0, 1, 1);
Common::Rect r2(0, 0, 2, 2);
TS_ASSERT(!r0.contains(r1));
TS_ASSERT(!r0.contains(r2));
TS_ASSERT(!r1.contains(r2));
TS_ASSERT(r0.contains(r0));
TS_ASSERT(r1.contains(r0));
TS_ASSERT(r1.contains(r1));
TS_ASSERT(r2.contains(r0));
TS_ASSERT(r2.contains(r1));
TS_ASSERT(r2.contains(r2));
}
void test_extend() {
Common::Rect r0;
Common::Rect r1(0, 0, 1, 1);
Common::Rect r2(0, 0, 2, 2);
TS_ASSERT(!r0.contains(r1));
r0.extend(r1);
TS_ASSERT(r0.contains(r1));
TS_ASSERT_EQUALS(r0.top, 0);
TS_ASSERT_EQUALS(r0.left, 0);
TS_ASSERT_EQUALS(r0.bottom, 1);
TS_ASSERT_EQUALS(r0.right, 1);
r2.extend(r1);
TS_ASSERT_EQUALS(r2.top, 0);
TS_ASSERT_EQUALS(r2.left, 0);
TS_ASSERT_EQUALS(r2.bottom, 2);
TS_ASSERT_EQUALS(r2.right, 2);
}
};

83
test/common/rendermode.h Normal file
View File

@@ -0,0 +1,83 @@
#include <cxxtest/TestSuite.h>
#include "common/rendermode.h"
#include "common/gui_options.h"
#include "common/str.h"
class RenderModeTestSuite : public CxxTest::TestSuite {
public:
void test_parse_render_mode_good() {
/*
* Tests for parseRenderMode.
* It takes a code (case-insensitive) and spits a RenderMode back at you.
* These cases should work - the inputs are standard, there's just some
* fun with caps being had in here.
*/
TS_ASSERT_EQUALS(Common::parseRenderMode("fMTOwNs"), Common::kRenderFMTowns);
TS_ASSERT_EQUALS(Common::parseRenderMode("hercGrEen"), Common::kRenderHercG);
TS_ASSERT_EQUALS(Common::parseRenderMode("hercAmbeR"), Common::kRenderHercA);
TS_ASSERT_EQUALS(Common::parseRenderMode("CgA"), Common::kRenderCGA);
TS_ASSERT_EQUALS(Common::parseRenderMode("ega"), Common::kRenderEGA);
TS_ASSERT_EQUALS(Common::parseRenderMode("Vga"), Common::kRenderVGA);
TS_ASSERT_EQUALS(Common::parseRenderMode("AmigA"), Common::kRenderAmiga);
TS_ASSERT_EQUALS(Common::parseRenderMode("pc98-256c"), Common::kRenderPC98_256c);
TS_ASSERT_EQUALS(Common::parseRenderMode("PC98-16c"), Common::kRenderPC98_16c);
TS_ASSERT_EQUALS(Common::parseRenderMode("0"), Common::kRenderDefault);
}
void test_parse_render_mode_bad() {
/*
* These cases, according to the specification, should return the default.
* It is only mentioned that the function must be case insensitive.
* Whitespaces, in particular, should not be automatically trimmed.
*/
TS_ASSERT_EQUALS(Common::parseRenderMode("fmtowns "), Common::kRenderDefault);
TS_ASSERT_EQUALS(Common::parseRenderMode("FM-TOWNS "), Common::kRenderDefault);
TS_ASSERT_EQUALS(Common::parseRenderMode(" cga"), Common::kRenderDefault);
TS_ASSERT_EQUALS(Common::parseRenderMode("\tC g A"), Common::kRenderDefault);
TS_ASSERT_EQUALS(Common::parseRenderMode("\t"), Common::kRenderDefault);
// This is the only interesting bit: if the function was really, really
// broken it could be tempted to test for +-0x20.
TS_ASSERT_EQUALS(Common::parseRenderMode("pc Y8 -256c "), Common::kRenderDefault);
TS_ASSERT_EQUALS(Common::parseRenderMode(" PC\t98-16c "), Common::kRenderDefault);
TS_ASSERT_EQUALS(Common::parseRenderMode("0"), Common::kRenderDefault);
}
void test_get_render_mode_code_back_and_forth() {
/*
* What does getRenderModeCode return?
* Notably, the output should not be in mixed case.
*/
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("FMTOWNS")), "fmtowns", 7);
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("CGA")), "cga", 3);
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("vga")), "vga", 3);
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("Ega")), "ega", 3);
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("AmiGa")), "amiga", 5);
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("PC98-256C")), "pc98-256c", 9);
TS_ASSERT_SAME_DATA(Common::getRenderModeCode(Common::parseRenderMode("PC98-16C")), "pc98-16c", 8);
// Slightly more interesting:
// Make sure that we get a null pointer for 0 (and not the "0" string or stuff)
char *null_p = 0;
TS_ASSERT_EQUALS(Common::getRenderModeCode(Common::kRenderDefault), null_p);
}
void test_render_2_guio() {
/*
* Verify that a rendermode is taken and the corresponding
* GUIO_xxxxx is returned.
*/
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderHercG), GUIO_RENDERHERCGREEN);
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderHercA), GUIO_RENDERHERCAMBER);
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderCGA), GUIO_RENDERCGA);
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderEGA), GUIO_RENDEREGA);
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderVGA), GUIO_RENDERVGA);
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderAmiga), GUIO_RENDERAMIGA);
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderFMTowns), GUIO_RENDERFMTOWNS);
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderPC98_256c), GUIO_RENDERPC98_256C);
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderPC98_16c), GUIO_RENDERPC98_16C);
// renderMode2GUIO is supposed to return an empty string
// if given kRenderDefault as an argument
Common::String empty;
TS_ASSERT_EQUALS(Common::renderMode2GUIO(Common::kRenderDefault), empty);
}
};

View File

@@ -0,0 +1,73 @@
#include <cxxtest/TestSuite.h>
#include "common/memstream.h"
#include "common/substream.h"
class SeekableSubReadStreamTestSuite : public CxxTest::TestSuite {
public:
void test_traverse() {
byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Common::MemoryReadStream ms(contents, 10);
int start = 2, end = 8;
Common::SeekableSubReadStream ssrs(&ms, start, end);
int i;
byte b;
for (i = start; i < end; ++i) {
TS_ASSERT(!ssrs.eos());
TS_ASSERT_EQUALS(i - start, ssrs.pos());
ssrs.read(&b, 1);
TS_ASSERT_EQUALS(i, b);
}
TS_ASSERT(!ssrs.eos());
TS_ASSERT_EQUALS((uint)0, ssrs.read(&b, 1));
TS_ASSERT(ssrs.eos());
}
void test_seek() {
byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Common::MemoryReadStream ms(contents, 10);
Common::SeekableSubReadStream ssrs(&ms, 1, 9);
byte b;
TS_ASSERT_EQUALS(ssrs.pos(), 0);
ssrs.seek(1, SEEK_SET);
TS_ASSERT_EQUALS(ssrs.pos(), 1);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 2);
ssrs.seek(5, SEEK_CUR);
TS_ASSERT_EQUALS(ssrs.pos(), 7);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 8);
ssrs.seek(-3, SEEK_CUR);
TS_ASSERT_EQUALS(ssrs.pos(), 5);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 6);
ssrs.seek(0, SEEK_END);
TS_ASSERT_EQUALS(ssrs.pos(), 8);
TS_ASSERT(!ssrs.eos());
b = ssrs.readByte();
TS_ASSERT(ssrs.eos());
ssrs.seek(-3, SEEK_END);
TS_ASSERT(!ssrs.eos());
TS_ASSERT_EQUALS(ssrs.pos(), 5);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 6);
ssrs.seek(-8, SEEK_END);
TS_ASSERT_EQUALS(ssrs.pos(), 0);
b = ssrs.readByte();
TS_ASSERT_EQUALS(b, 1);
}
};

111
test/common/serializer.h Normal file
View File

@@ -0,0 +1,111 @@
#include <cxxtest/TestSuite.h>
#include "common/serializer.h"
#include "common/stream.h"
class SerializerTestSuite : public CxxTest::TestSuite {
Common::SeekableReadStream *_inStreamV1;
Common::SeekableReadStream *_inStreamV2;
public:
void setUp() {
// Our pseudo data format is as follows:
// * magic id - string "MAGI"
// * Version - uint32, LE
// * uint32, LE (available in v2 onward)
// * uint16, BE (available in v1 onward)
// * sint16, LE (available only in v1)
// * byte (always available)
static const byte contents_v1[] = {
'M', 'A', 'G', 'I', // magic id
0x01, 0x00, 0x00, 0x00, // Version
0x06, 0x07, // uint16, BE (available in v1 onward)
0xfe, 0xff, // sint16, LE (available only in v1)
0x0a // byte (always available)
};
static const byte contents_v2[] = {
'M', 'A', 'G', 'I', // magic id
0x02, 0x00, 0x00, 0x00, // Version
0x02, 0x03, 0x04, 0x05, // uint32, LE (available in v2 onward)
0x06, 0x07, // uint16, BE (available in v1 onward)
0x0a // byte (always available)
};
_inStreamV1 = new Common::MemoryReadStream(contents_v1, sizeof(contents_v1));
_inStreamV2 = new Common::MemoryReadStream(contents_v2, sizeof(contents_v2));
}
void tearDown() {
delete _inStreamV1;
delete _inStreamV2;
}
// A method which reads a v1 file
void readVersioned_v1(Common::SeekableReadStream *stream, Common::Serializer::Version version) {
Common::Serializer ser(stream, 0);
TS_ASSERT(ser.matchBytes("MAGI", 4));
TS_ASSERT(ser.syncVersion(1));
TS_ASSERT_EQUALS(ser.getVersion(), version);
uint32 tmp = 0;
ser.syncAsUint16BE(tmp, Common::Serializer::Version(1));
TS_ASSERT_EQUALS(tmp, (uint16)0x0607);
ser.syncAsSint16LE(tmp, Common::Serializer::Version(1));
TS_ASSERT_EQUALS((int16)tmp, -2);
ser.syncAsByte(tmp);
TS_ASSERT_EQUALS(tmp, (uint8)0x0a);
}
// A method which reads a v2 file
void readVersioned_v2(Common::SeekableReadStream *stream, Common::Serializer::Version version) {
Common::Serializer ser(stream, 0);
TS_ASSERT(ser.matchBytes("MAGI", 4));
TS_ASSERT(ser.syncVersion(2));
TS_ASSERT_EQUALS(ser.getVersion(), version);
uint32 tmp;
// Read a value only available starting with v2.
// Thus if we load an old save, it must be
// manually set. To simplify that, no sync method should
// modify the value passed to it if nothing was read!
tmp = 0x12345678;
ser.syncAsUint32LE(tmp, Common::Serializer::Version(2));
if (ser.getVersion() < 2) {
TS_ASSERT_EQUALS(tmp, (uint32)0x12345678);
} else {
TS_ASSERT_EQUALS(tmp, (uint32)0x05040302);
}
ser.syncAsUint16BE(tmp, Common::Serializer::Version(1));
TS_ASSERT_EQUALS(tmp, (uint32)0x0607);
// Skip over obsolete data
ser.skip(2, Common::Serializer::Version(1), Common::Serializer::Version(1));
ser.syncAsByte(tmp);
TS_ASSERT_EQUALS(tmp, (uint8)0x0a);
}
void test_read_v1_as_v1() {
readVersioned_v1(_inStreamV1, 1);
}
// There is no test_read_v2_as_v1() because a v1 parser cannot possibly
// read v2 data correctly. It should instead error out if it
// detects a version newer than its current version.
void test_read_v1_as_v2() {
readVersioned_v2(_inStreamV1, 1);
}
void test_read_v2_as_v2() {
readVersioned_v2(_inStreamV2, 2);
}
};

810
test/common/span.h Normal file
View File

@@ -0,0 +1,810 @@
#include <cxxtest/TestSuite.h>
class SpanTestSuite;
#include "common/span.h"
#include "common/str.h"
class SpanTestSuite : public CxxTest::TestSuite {
struct Foo {
int a;
};
template <typename ValueType, template <typename> class Derived>
class SiblingSpanImpl : public Common::SpanImpl<ValueType, Derived> {
typedef Common::SpanImpl<ValueType, Derived> super_type;
public:
COMMON_SPAN_TYPEDEFS;
SiblingSpanImpl() = default;
SiblingSpanImpl(pointer data_, size_type size_) : super_type(data_, size_) {}
};
template <typename ValueType>
class SiblingSpan : public SiblingSpanImpl<ValueType, SiblingSpan> {
typedef SiblingSpanImpl<ValueType, ::SpanTestSuite::SiblingSpan> super_type;
public:
COMMON_SPAN_TYPEDEFS;
SiblingSpan() = default;
SiblingSpan(pointer data_, size_type size_) : super_type(data_, size_) {}
};
template <typename ValueType, template <typename> class Derived>
class SubSpanImpl : public Common::NamedSpanImpl<ValueType, Derived> {
typedef Common::NamedSpanImpl<ValueType, Derived> super_type;
public:
COMMON_SPAN_TYPEDEFS;
SubSpanImpl() = default;
SubSpanImpl(pointer data_,
size_type size_,
const Common::String &name_ = Common::String(),
const size_type sourceByteOffset_ = 0) :
super_type(data_, size_, name_, sourceByteOffset_) {}
template <typename Other>
SubSpanImpl(const Other &other) : super_type(other) {}
};
template <typename ValueType>
class SubSpan : public SubSpanImpl<ValueType, SubSpan> {
typedef SubSpanImpl<ValueType, ::SpanTestSuite::SubSpan> super_type;
public:
COMMON_SPAN_TYPEDEFS;
SubSpan() = default;
SubSpan(pointer data_,
size_type size_,
const Common::String &name_ = Common::String(),
const size_type sourceByteOffset_ = 0) :
super_type(data_, size_, name_, sourceByteOffset_) {}
template <typename Other>
SubSpan(const Other &other) : super_type(other) {}
};
public:
void test_sibling_span() {
byte data[] = { 'h', 'e', 'l', 'l', 'o' };
SiblingSpan<byte> ss(data, sizeof(data));
Common::Span<byte> superInstance = ss;
TS_ASSERT_EQUALS(ss.data(), data);
TS_ASSERT_EQUALS(superInstance.data(), data);
}
void test_sub_span() {
byte data[] = { 'h', 'e', 'l', 'l', 'o' };
SubSpan<byte> ss(data, sizeof(data), "custom subspan");
Common::NamedSpan<byte> namedSuper = ss;
Common::Span<byte> unnamedSuper = ss;
TS_ASSERT(ss.name() == "custom subspan");
TS_ASSERT(namedSuper.name() == ss.name());
TS_ASSERT(unnamedSuper.name() == Common::String::format("%p", (void *)data));
}
void test_span_iterator_const() {
byte data[] = { 'h', 'e', 'l', 'l', 'o' };
const Common::Span<byte> span(data, sizeof(data));
Common::Span<byte>::const_iterator it = span.cbegin();
Common::Span<byte>::const_iterator sameIt(it);
TS_ASSERT_EQUALS(sameIt, it);
uint i;
for (i = 0; it != span.cend(); ++i, ++it) {
TS_ASSERT_EQUALS(*it, data[i]);
TS_ASSERT_LESS_THAN(i, sizeof(data));
}
TS_ASSERT_EQUALS(i, sizeof(data));
it = span.cend() - 1;
for (i = sizeof(data) - 1; it != span.cbegin(); --i, --it) {
TS_ASSERT_EQUALS(data[i], *it);
}
TS_ASSERT_EQUALS(i, 0U);
it = span.cbegin();
it += 4;
TS_ASSERT_EQUALS(data[4], *it);
it -= 4;
TS_ASSERT_EQUALS(data[0], *it);
TS_ASSERT_EQUALS(data[0], *it++);
TS_ASSERT_EQUALS(data[1], *it--);
TS_ASSERT_EQUALS(span.cend() - span.cbegin(), 5);
TS_ASSERT_EQUALS(*(span.cbegin() + 4), data[4]);
TS_ASSERT_EQUALS(*(span.cend() - 4), data[1]);
TS_ASSERT(span.cbegin() < span.cend());
TS_ASSERT(span.cbegin() <= span.cend());
TS_ASSERT(span.cbegin() <= span.cbegin());
TS_ASSERT(span.cend() > span.cbegin());
TS_ASSERT(span.cend() >= span.cbegin());
TS_ASSERT(span.cend() >= span.cend());
}
void test_span_iterator() {
byte data[] = { 'h', 'e', 'l', 'l', 'o' };
Common::Span<byte> span(data, sizeof(data));
// empty iterator should default construct OK
Common::Span<byte>::iterator defaultIt;
Common::Span<byte>::iterator it = span.begin();
Common::Span<byte>::iterator sameIt(it);
TS_ASSERT_EQUALS(sameIt, it);
uint i;
for (i = 0; it != span.end(); ++i, ++it) {
TS_ASSERT_EQUALS(*it, data[i]);
TS_ASSERT_LESS_THAN(i, sizeof(data));
}
TS_ASSERT_EQUALS(i, sizeof(data));
it = span.end() - 1;
for (i = sizeof(data) - 1; it != span.begin(); --i, --it) {
TS_ASSERT_EQUALS(data[i], *it);
}
TS_ASSERT_EQUALS(i, 0U);
it = span.begin();
it += 4;
TS_ASSERT_EQUALS(data[4], *it);
it -= 4;
TS_ASSERT_EQUALS(data[0], *it);
TS_ASSERT_EQUALS(data[0], *it++);
TS_ASSERT_EQUALS(data[1], *it--);
TS_ASSERT_EQUALS(span.end() - span.begin(), 5);
TS_ASSERT_EQUALS(*(span.begin() + 4), data[4]);
TS_ASSERT_EQUALS(*(span.end() - 4), data[1]);
TS_ASSERT(span.begin() < span.end());
TS_ASSERT(span.begin() <= span.end());
TS_ASSERT(span.begin() <= span.begin());
TS_ASSERT(span.end() > span.begin());
TS_ASSERT(span.end() >= span.begin());
TS_ASSERT(span.end() >= span.end());
it = span.begin();
for (i = 0; it != span.end(); ++i, ++it) {
*it = 'a' + i;
}
it = span.begin();
for (i = 0; it != span.end(); ++i, ++it) {
TS_ASSERT_EQUALS(*it, 'a' + i);
TS_ASSERT_EQUALS(data[i], 'a' + i);
}
}
void test_span_iterator_integers() {
const byte data[] = { 0xFF, 1, 2, 3, 2, 1, 0xFF };
Common::Span<const byte> span(data, sizeof(data));
Common::Span<const byte>::const_iterator it = span.cbegin();
TS_ASSERT_EQUALS(it.getInt8(), -1);
TS_ASSERT_EQUALS(it.getUint8(), 255);
TS_ASSERT_EQUALS(it.getInt16BE(), -255);
TS_ASSERT_EQUALS(it.getUint16BE(), 65281U);
TS_ASSERT_EQUALS((it + 5).getInt16LE(), -255);
TS_ASSERT_EQUALS((it + 5).getUint16LE(), 65281U);
TS_ASSERT_EQUALS(it.getUint24LE(), 131583U);
#if defined(SCUMM_LITTLE_ENDIAN)
TS_ASSERT_EQUALS((it + 3).getUint32(), 4278256131U);
#elif defined(SCUMM_BIG_ENDIAN)
TS_ASSERT_EQUALS(it.getUint32(), 4278256131U);
#else
#error No endianness detected
#endif
TS_ASSERT_EQUALS(it.getInt32BE(), -16711165);
TS_ASSERT_EQUALS(it.getUint32BE(), 4278256131U);
TS_ASSERT_EQUALS((it + 3).getInt32LE(), -16711165);
TS_ASSERT_EQUALS((it + 3).getUint32LE(), 4278256131U);
}
void test_span_iterator_ptr() {
Foo foo[2];
foo[0].a = 1;
foo[1].a = 2;
const Common::Span<Foo> span(foo, 2);
Common::Span<Foo>::const_iterator it = span.cbegin();
TS_ASSERT_EQUALS(it->a, 1);
++it;
TS_ASSERT_EQUALS(it->a, 2);
TS_ASSERT_EQUALS(it[0].a, 2);
TS_ASSERT_EQUALS(it[-1].a, 1);
--it;
TS_ASSERT_EQUALS(it[1].a, 2);
}
void test_span_owner() {
Common::SpanOwner<Common::Span<byte> > owner;
owner->allocate(3);
owner[0] = 'a';
owner[1] = 'b';
owner[2] = 'c';
for (int i = 0; i < 3; ++i) {
TS_ASSERT_EQUALS(owner->getUint8At(i), 'a' + i);
TS_ASSERT_EQUALS((*owner)[i], 'a' + i);
}
{
Common::SpanOwner<Common::NamedSpan<byte> > owner2;
TS_ASSERT(owner2->data() == nullptr);
owner2->allocateFromSpan(*owner);
TS_ASSERT(owner2->data() != nullptr);
TS_ASSERT_DIFFERS(owner->data(), owner2->data());
for (int i = 0; i < 3; ++i) {
TS_ASSERT_EQUALS(owner2->getUint8At(i), 'a' + i);
TS_ASSERT_EQUALS((*owner2)[i], 'a' + i);
}
TS_ASSERT_EQUALS((bool)owner2, true);
owner2.clear();
TS_ASSERT_EQUALS((bool)owner2, false);
}
{
Common::SpanOwner<Common::Span<byte> > owner2;
TS_ASSERT(owner2->data() == nullptr);
owner2 = owner;
TS_ASSERT(owner2->data() != nullptr);
TS_ASSERT_DIFFERS(owner->data(), owner2->data());
for (int i = 0; i < 3; ++i) {
TS_ASSERT_EQUALS(owner2->getUint8At(i), 'a' + i);
TS_ASSERT_EQUALS((*owner2)[i], 'a' + i);
}
TS_ASSERT_EQUALS((bool)owner2, true);
owner2.clear();
TS_ASSERT_EQUALS((bool)owner2, false);
}
{
Common::SpanOwner<Common::Span<byte> > owner2;
TS_ASSERT_EQUALS((bool)owner, true);
void *dataPtr = owner->data();
owner2.moveFrom(owner);
TS_ASSERT_EQUALS((bool)owner, false);
TS_ASSERT(owner->data() == nullptr);
TS_ASSERT_EQUALS(owner2->data(), dataPtr);
// tests destruction of held pointer by reassignment
owner2 = owner;
// tests nullipotence of assignment to self
dataPtr = owner2->data();
owner2 = owner2;
TS_ASSERT(owner2->data() == dataPtr);
}
{
char *data = new char[6];
Common::strlcpy(data, "hello", 6);
const Common::SpanOwner<Common::Span<const char> > constOwner(Common::Span<const char>(data, 6));
TS_ASSERT_EQUALS((*constOwner)[0], 'h');
TS_ASSERT_EQUALS(constOwner->getUint8At(1), 'e');
TS_ASSERT_EQUALS(constOwner[2], 'l');
}
{
TS_ASSERT_EQUALS((bool)owner, false);
Common::SpanOwner<Common::Span<byte> > owner2(owner);
TS_ASSERT_EQUALS((bool)owner2, false);
}
{
owner->allocate(1);
TS_ASSERT_EQUALS((bool)owner, true);
Common::SpanOwner<Common::Span<byte> > owner2(owner);
TS_ASSERT_EQUALS((bool)owner2, true);
TS_ASSERT_DIFFERS(owner->data(), owner2->data());
}
{
TS_ASSERT_EQUALS((bool)owner, true);
byte *dataPtr = owner->data();
TS_ASSERT_EQUALS(owner.release(), dataPtr);
TS_ASSERT_EQUALS((bool)owner, false);
delete[] dataPtr;
}
}
void test_span_owner_named_span() {
Common::SpanOwner<Common::NamedSpan<byte> > owner;
owner->allocate(3, "foo");
owner[0] = 'a';
owner[1] = 'b';
owner[2] = 'c';
for (int i = 0; i < 3; ++i) {
TS_ASSERT_EQUALS(owner->getUint8At(i), 'a' + i);
TS_ASSERT_EQUALS((*owner)[i], 'a' + i);
}
TS_ASSERT(owner->name() == "foo");
{
Common::SpanOwner<Common::NamedSpan<byte> > owner2;
TS_ASSERT(owner2->data() == nullptr);
owner2->allocateFromSpan(*owner);
TS_ASSERT(owner2->data() != nullptr);
TS_ASSERT_DIFFERS(owner->data(), owner2->data());
TS_ASSERT(owner2->name() == "foo");
for (int i = 0; i < 3; ++i) {
TS_ASSERT_EQUALS(owner2->getUint8At(i), 'a' + i);
TS_ASSERT_EQUALS((*owner2)[i], 'a' + i);
}
TS_ASSERT_EQUALS((bool)owner2, true);
owner2.clear();
TS_ASSERT_EQUALS((bool)owner2, false);
}
{
Common::SpanOwner<Common::NamedSpan<byte> > owner2;
TS_ASSERT_EQUALS((bool)owner, true);
void *dataPtr = owner->data();
owner2.moveFrom(owner);
TS_ASSERT_EQUALS((bool)owner, false);
TS_ASSERT(owner->data() == nullptr);
TS_ASSERT_EQUALS(owner2->data(), dataPtr);
// tests destruction of held pointer by reassignment
owner2 = owner;
}
{
char *data = new char[6];
Common::strlcpy(data, "hello", 6);
const Common::SpanOwner<Common::NamedSpan<const char> > constOwner(Common::NamedSpan<const char>(data, 6));
TS_ASSERT_EQUALS((*constOwner)[0], 'h');
TS_ASSERT_EQUALS(constOwner->getUint8At(1), 'e');
TS_ASSERT_EQUALS(constOwner[2], 'l');
}
{
TS_ASSERT_EQUALS((bool)owner, false);
Common::SpanOwner<Common::NamedSpan<byte> > owner2(owner);
TS_ASSERT_EQUALS((bool)owner2, false);
}
{
owner->allocate(1);
TS_ASSERT_EQUALS((bool)owner, true);
Common::SpanOwner<Common::NamedSpan<byte> > owner2(owner);
TS_ASSERT_EQUALS((bool)owner2, true);
TS_ASSERT_DIFFERS(owner->data(), owner2->data());
}
{
TS_ASSERT_EQUALS((bool)owner, true);
byte *dataPtr = owner->data();
TS_ASSERT_EQUALS(owner.release(), dataPtr);
TS_ASSERT_EQUALS((bool)owner, false);
delete[] dataPtr;
}
}
void test_span_allocate_from_stream() {
byte data[] = "hello";
Common::MemoryReadStream stream(data, sizeof(data));
Common::SpanOwner<Common::Span<byte> > owner;
owner->allocateFromStream(stream, 2);
TS_ASSERT(owner->data() != data);
TS_ASSERT_EQUALS(owner->size(), 2U);
TS_ASSERT_EQUALS(owner[0], 'h');
TS_ASSERT_EQUALS(owner[1], 'e');
owner.clear();
TS_ASSERT(owner->data() == nullptr);
stream.seek(0, SEEK_SET);
owner->allocateFromStream(stream);
TS_ASSERT(owner->data() != data);
TS_ASSERT_EQUALS(owner->size(), sizeof(data));
TS_ASSERT_EQUALS(owner[0], 'h');
TS_ASSERT_EQUALS(owner[1], 'e');
TS_ASSERT_EQUALS(owner[2], 'l');
TS_ASSERT_EQUALS(owner[3], 'l');
TS_ASSERT_EQUALS(owner[4], 'o');
Common::SpanOwner<Common::NamedSpan<const byte> > owner2;
stream.seek(0, SEEK_SET);
owner2->allocateFromStream(stream, Common::kSpanMaxSize, "streamname");
TS_ASSERT(owner2->data() != data);
TS_ASSERT_EQUALS(owner2->size(), sizeof(data));
TS_ASSERT_EQUALS(owner2[0], 'h');
TS_ASSERT_EQUALS(owner2[1], 'e');
TS_ASSERT_EQUALS(owner2[2], 'l');
TS_ASSERT_EQUALS(owner2[3], 'l');
TS_ASSERT_EQUALS(owner2[4], 'o');
TS_ASSERT_EQUALS(owner2->name(), "streamname");
}
void test_span_byte() {
{
byte data[] = { 'h', 'e', 'l', 'l', 'o' };
Common::Span<byte> span(data, sizeof(data));
TS_ASSERT_EQUALS(span.size(), sizeof(data));
TS_ASSERT_EQUALS(span.byteSize(), sizeof(data));
Common::Span<byte> other(span);
TS_ASSERT_EQUALS(span, other);
other.clear();
TS_ASSERT(span != other);
TS_ASSERT_EQUALS(span[0], 'h');
TS_ASSERT_EQUALS(span[1], 'e');
span[1] = 'o';
TS_ASSERT_EQUALS(span[1], 'o');
TS_ASSERT((bool)span);
span.clear();
TS_ASSERT(!(bool)span);
}
{
byte data[] = { 'h', 'e', 'l', 'l', 'o' };
const Common::Span<const byte> span(data, sizeof(data));
TS_ASSERT_EQUALS(span.size(), sizeof(data));
TS_ASSERT_EQUALS(span.byteSize(), sizeof(data));
const Common::Span<const byte> other(span);
TS_ASSERT_EQUALS(span, other);
TS_ASSERT_EQUALS(span[0], 'h');
TS_ASSERT_EQUALS(span[1], 'e');
}
}
void test_span_integers() {
const byte data[] = { 0xFF, 1, 2, 3, 2, 1, 0xFF };
Common::Span<const byte> span(data, sizeof(data));
TS_ASSERT_EQUALS(span[0], 255);
TS_ASSERT_EQUALS(span.getInt8At(0), -1);
TS_ASSERT_EQUALS(span.getUint8At(0), 255U);
TS_ASSERT_EQUALS(span.getInt16BEAt(0), -255);
TS_ASSERT_EQUALS(span.getUint16BEAt(0), 65281U);
TS_ASSERT_EQUALS(span.getInt16LEAt(5), -255);
TS_ASSERT_EQUALS(span.getUint16LEAt(5), 65281U);
TS_ASSERT_EQUALS(span.getUint24LEAt(0), 131583U);
TS_ASSERT_EQUALS(span.getInt32BEAt(0), -16711165);
TS_ASSERT_EQUALS(span.getUint32BEAt(0), 4278256131U);
TS_ASSERT_EQUALS(span.getInt32LEAt(3), -16711165);
TS_ASSERT_EQUALS(span.getUint32LEAt(3), 4278256131U);
#if defined(SCUMM_LITTLE_ENDIAN)
TS_ASSERT_EQUALS(span.getUint32At(3), 4278256131U);
#elif defined(SCUMM_BIG_ENDIAN)
TS_ASSERT_EQUALS(span.getUint32At(0), 4278256131U);
#else
#error No endianness detected
#endif
}
void test_span_string() {
char data[] = "hello";
Common::Span<char> span(data, sizeof(data));
TS_ASSERT_EQUALS(span[sizeof(data) - 1], '\0');
TS_ASSERT(span.getStringAt(0) == data);
TS_ASSERT(span.getStringAt(0, 2) == "he");
TS_ASSERT(span.getStringAt(2) == "llo");
TS_ASSERT(span.getStringAt(2, 3) == "llo");
span[3] = '\0';
TS_ASSERT(span.getStringAt(0) == "hel");
}
void test_span_unsafe_data() {
char data[] = "hello";
Common::Span<char> span(data, sizeof(data));
char *ptr = span.getUnsafeDataAt(0, 6);
TS_ASSERT_EQUALS(ptr, data);
ptr = span.getUnsafeDataAt(0);
TS_ASSERT_EQUALS(ptr, data);
const Common::Span<const char> span2(data, sizeof(data));
const char *ptr2 = span2.getUnsafeDataAt(0, 6);
TS_ASSERT_EQUALS(ptr2, data);
ptr2 = span2.getUnsafeDataAt(0);
TS_ASSERT_EQUALS(ptr2, data);
}
void test_span_subspan() {
{
byte data[] = { 1, 2, 3, 4, 5, 6 };
Common::Span<byte> span(data, sizeof(data));
TS_ASSERT_EQUALS(span.subspan(0).size(), sizeof(data) - 0);
TS_ASSERT_EQUALS(span.subspan(2).size(), sizeof(data) - 2);
TS_ASSERT_EQUALS(span.subspan(2, 2).size(), 2U);
TS_ASSERT_EQUALS(span.subspan<uint16>(0).size(), sizeof(data) / 2);
TS_ASSERT_EQUALS(span.subspan<uint16>(0).byteSize(), sizeof(data));
TS_ASSERT_EQUALS(span.subspan<uint16>(0, 2).size(), 1U);
TS_ASSERT_EQUALS(span.subspan<uint16>(0, 2).byteSize(), 2U);
#if defined(SCUMM_LITTLE_ENDIAN)
TS_ASSERT_EQUALS(span.subspan<uint16>(0)[1], 4 << 8 | 3);
#elif defined(SCUMM_BIG_ENDIAN)
TS_ASSERT_EQUALS(span.subspan<uint16>(0)[1], 3 << 8 | 4);
#else
#error No endianness detected
#endif
Common::Span<uint16> shortSpan = span.subspan<uint16>(0);
TS_ASSERT_EQUALS(shortSpan.byteSize(), span.byteSize());
TS_ASSERT(shortSpan.size() != span.size());
shortSpan[1] = 0xFFFF;
Common::Span<byte> byteSpan = shortSpan.subspan<byte>(1);
TS_ASSERT_EQUALS(byteSpan.size(), sizeof(data) - 1 * sizeof(uint16));
TS_ASSERT_EQUALS(byteSpan[0], 0xFF);
TS_ASSERT_EQUALS(byteSpan[1], 0xFF);
}
{
byte data[] = { 1, 2, 3, 4, 5, 6 };
const Common::Span<const byte> span(data, sizeof(data));
TS_ASSERT_EQUALS(span.subspan(0).size(), sizeof(data) - 0);
TS_ASSERT_EQUALS(span.subspan(2).size(), sizeof(data) - 2);
TS_ASSERT_EQUALS(span.subspan(2, 2).size(), 2U);
TS_ASSERT_EQUALS(span.subspan<uint16>(0).size(), sizeof(data) / 2);
TS_ASSERT_EQUALS(span.subspan<uint16>(0).byteSize(), sizeof(data));
TS_ASSERT_EQUALS(span.subspan<uint16>(0, 2).size(), 1U);
TS_ASSERT_EQUALS(span.subspan<uint16>(0, 2).byteSize(), 2U);
#if defined(SCUMM_LITTLE_ENDIAN)
TS_ASSERT_EQUALS(span.subspan<uint16>(0)[1], 4 << 8 | 3);
#elif defined(SCUMM_BIG_ENDIAN)
TS_ASSERT_EQUALS(span.subspan<uint16>(0)[1], 3 << 8 | 4);
#else
#error No endianness detected
#endif
const Common::Span<uint16> shortSpan = span.subspan<uint16>(0);
TS_ASSERT_EQUALS(shortSpan.byteSize(), span.byteSize());
TS_ASSERT(shortSpan.size() != span.size());
Common::Span<byte> byteSpan = shortSpan.subspan<byte>(1);
TS_ASSERT_EQUALS(byteSpan.size(), sizeof(data) - 1 * sizeof(uint16));
TS_ASSERT_EQUALS(byteSpan[0], 3);
TS_ASSERT_EQUALS(byteSpan[1], 4);
}
}
void test_span_to_stream() {
const byte data[] = { 0, 1, 2, 3 };
Common::Span<const byte> span(data, sizeof(data));
{
Common::MemoryReadStream stream(span.toStream(1, 2));
byte out;
TS_ASSERT_EQUALS(stream.read(&out, 1), 1U);
TS_ASSERT_EQUALS(out, 1);
TS_ASSERT_EQUALS(stream.read(&out, 1), 1U);
TS_ASSERT_EQUALS(out, 2);
TS_ASSERT_EQUALS(stream.read(&out, 1), 0U);
}
{
Common::MemoryReadStream stream = span.toStream();
byte out;
TS_ASSERT_EQUALS(stream.read(&out, 1), 1U);
TS_ASSERT_EQUALS(out, 0);
TS_ASSERT_EQUALS(stream.read(&out, 1), 1U);
TS_ASSERT_EQUALS(out, 1);
TS_ASSERT_EQUALS(stream.read(&out, 1), 1U);
TS_ASSERT_EQUALS(out, 2);
TS_ASSERT_EQUALS(stream.read(&out, 1), 1U);
TS_ASSERT_EQUALS(out, 3);
TS_ASSERT_EQUALS(stream.read(&out, 1), 0U);
}
}
void test_span_copying() {
const byte data[] = { 0, 1, 2, 3, 4, 5 };
Common::Span<const byte> span(data, sizeof(data));
byte targetData[sizeof(data)] = {};
Common::Span<byte> target(targetData, sizeof(targetData));
span.copyDataTo(target);
for (uint i = 0; i < sizeof(data); ++i) {
TS_ASSERT_EQUALS(target[i], i);
}
byte out[sizeof(data)];
span.unsafeCopyDataTo(out);
for (uint i = 0; i < sizeof(data); ++i) {
TS_ASSERT_EQUALS(out[i], i);
}
}
void test_span_validation() {
byte data[6];
Common::Span<byte> span(data, sizeof(data));
TS_ASSERT(!span.checkInvalidBounds(0, 0));
TS_ASSERT(!span.checkInvalidBounds(0, 6));
TS_ASSERT(!span.checkInvalidBounds(2, 4));
TS_ASSERT(!span.checkInvalidBounds(4, 2));
TS_ASSERT(!span.checkInvalidBounds(6, 0));
TS_ASSERT(!span.checkInvalidBounds(2, -2));
TS_ASSERT(span.checkInvalidBounds(-2, 2)); // negative index disallowed
TS_ASSERT(span.checkInvalidBounds(6, 1)); // combined positive overflow (+7)
TS_ASSERT(span.checkInvalidBounds(2, -4)); // negative overflow (-2)
TS_ASSERT(span.checkInvalidBounds(0, 10)); // delta positive overflow
const Common::Span<byte>::difference_type big = (Common::Span<byte>::difference_type)1 << (8 * sizeof(Common::Span<byte>::difference_type) - 1);
TS_ASSERT(span.checkInvalidBounds(big, 0));
TS_ASSERT(span.checkInvalidBounds(0, big));
TS_ASSERT(span.checkInvalidBounds(big, big));
}
void test_span_validation_message() {
byte data[1];
Common::Span<byte> span(data, sizeof(data));
Common::String source = span.name();
Common::String actual;
Common::String expected;
actual = span.getValidationMessage(12, 34, Common::kValidateRead);
expected = Common::String::format("Access violation reading %s: 12 + 34 > 1", source.c_str());
TS_ASSERT_EQUALS(actual, expected);
actual = span.getValidationMessage(23, 45, Common::kValidateWrite);
expected = Common::String::format("Access violation writing %s: 23 + 45 > 1", source.c_str());
TS_ASSERT_EQUALS(actual, expected);
actual = span.getValidationMessage(0, -56, Common::kValidateSeek);
expected = Common::String::format("Access violation seeking %s: 0 + -56 > 1", source.c_str());
TS_ASSERT_EQUALS(actual, expected);
}
void test_span_comparators() {
byte data[2] = { 0 };
Common::Span<const byte> span0(data, sizeof(data));
Common::Span<const byte> span1(data, sizeof(data));
Common::Span<const byte> span2(data, sizeof(data) - 1);
Common::Span<const byte> span3(data + 1, sizeof(data) - 1);
Common::Span<const byte> span4(data + 2, sizeof(data) - 2);
TS_ASSERT(span0 == span1);
TS_ASSERT(span0 != span2);
TS_ASSERT(span0 <= span1);
TS_ASSERT(span0 <= span3);
TS_ASSERT(span0 < span3);
TS_ASSERT(span3 < span4);
TS_ASSERT(span4 > span3);
TS_ASSERT(span3 > span0);
TS_ASSERT(span4 >= span4);
TS_ASSERT(span0 >= span1);
TS_ASSERT_EQUALS(span1 - span0, 0);
TS_ASSERT_EQUALS(span3 - span0, 1);
TS_ASSERT_EQUALS(span4 - span0, 2);
TS_ASSERT_EQUALS(span0 - span1, 0);
TS_ASSERT_EQUALS(span0 - span3, -1);
TS_ASSERT_EQUALS(span0 - span4, -2);
}
void test_named_span() {
byte data[6] = { 0, 1, 2, 3, 4, 5 };
Common::NamedSpan<byte> span(data, sizeof(data), "foo.data");
TS_ASSERT_EQUALS(span.name(), "foo.data");
Common::String actual;
Common::String expected;
actual = span.getValidationMessage(12, 34, Common::kValidateRead);
expected = "Access violation reading foo.data: 12 + 34 > 6 (abs: 12 + 34 > 6)";
TS_ASSERT_EQUALS(actual, expected);
{
Common::NamedSpan<byte> subspan = span.subspan(2);
expected = "Access violation reading foo.data: 23 + 45 > 4 (abs: 25 + 45 > 6)";
actual = subspan.getValidationMessage(23, 45, Common::kValidateRead);
TS_ASSERT_EQUALS(actual, expected);
}
{
Common::NamedSpan<byte> subspan = span.subspan(2, Common::kSpanMaxSize, "new.data");
expected = "Access violation reading new.data: 0 + -56 > 4 (abs: 2 + -56 > 6)";
actual = subspan.getValidationMessage(0, -56, Common::kValidateRead);
TS_ASSERT_EQUALS(actual, expected);
}
{
Common::NamedSpan<byte> subspan = span.subspan(2, Common::kSpanMaxSize, "new.data", 0);
expected = "Access violation reading new.data: 0 + -56 > 4 (abs: 0 + -56 > 4)";
actual = subspan.getValidationMessage(0, -56, Common::kValidateRead);
TS_ASSERT_EQUALS(actual, expected);
}
Common::NamedSpan<byte> span2;
span = span2 = span;
TS_ASSERT_EQUALS(span2, span);
TS_ASSERT(span2.name() == span.name());
TS_ASSERT(span2.sourceByteOffset() == span.sourceByteOffset());
Common::Span<byte> superclassInstance;
superclassInstance = span;
TS_ASSERT_EQUALS(span, superclassInstance);
Common::Span<byte> subclassInstance(superclassInstance);
TS_ASSERT_EQUALS(subclassInstance, superclassInstance);
const Common::NamedSpan<const byte> constSpan(span);
{
Common::NamedSpan<const byte> subspan = constSpan.subspan(2);
expected = "Access violation reading foo.data: 23 + 45 > 4 (abs: 25 + 45 > 6)";
actual = subspan.getValidationMessage(23, 45, Common::kValidateRead);
TS_ASSERT_EQUALS(actual, expected);
TS_ASSERT_EQUALS(subspan.sourceByteOffset(), 2U);
}
{
Common::NamedSpan<const byte> subspan = constSpan.subspan(2, Common::kSpanMaxSize, "new.data");
expected = "Access violation reading new.data: 0 + -56 > 4 (abs: 2 + -56 > 6)";
actual = subspan.getValidationMessage(0, -56, Common::kValidateRead);
TS_ASSERT_EQUALS(actual, expected);
}
{
Common::NamedSpan<const byte> subspan = constSpan.subspan(2, Common::kSpanMaxSize, "new.data", 0);
expected = "Access violation reading new.data: 0 + -56 > 4 (abs: 0 + -56 > 4)";
actual = subspan.getValidationMessage(0, -56, Common::kValidateRead);
TS_ASSERT_EQUALS(actual, expected);
}
{
Common::NamedSpan<const byte> subspan = constSpan.subspan(2, Common::kSpanMaxSize, "new.data", 0);
subspan.sourceByteOffset() = 2;
expected = "Access violation reading new.data: 0 + -56 > 4 (abs: 2 + -56 > 6)";
actual = subspan.getValidationMessage(0, -56, Common::kValidateRead);
TS_ASSERT_EQUALS(actual, expected);
}
{
Common::MemoryReadStream *stream = new Common::MemoryReadStream(data, sizeof(data));
Common::File file;
file.open(stream, "test.txt");
Common::SpanOwner<Common::NamedSpan<const byte> > fileOwner;
fileOwner->allocateFromStream(file);
TS_ASSERT_EQUALS(fileOwner->size(), (uint)file.size());
file.close();
TS_ASSERT(fileOwner->name() == "test.txt");
for (uint i = 0; i < fileOwner->size(); ++i) {
TS_ASSERT_EQUALS(fileOwner->getInt8At(i), data[i]);
}
}
}
};

83
test/common/stack.h Normal file
View File

@@ -0,0 +1,83 @@
#include <cxxtest/TestSuite.h>
#include "common/stack.h"
class StackTestSuite : public CxxTest::TestSuite {
public:
void test_empty_clear() {
Common::Stack<int> stack;
TS_ASSERT(stack.empty());
stack.push(1);
stack.push(2);
TS_ASSERT(!stack.empty());
stack.clear();
TS_ASSERT(stack.empty());
}
void test_size() {
typedef Common::Stack<int> Stack;
Stack stack;
TS_ASSERT_EQUALS(stack.size(), (Stack::size_type)0);
stack.push(5);
TS_ASSERT_EQUALS(stack.size(), (Stack::size_type)1);
stack.push(9);
stack.push(0);
TS_ASSERT_EQUALS(stack.size(), (Stack::size_type)3);
stack.pop();
TS_ASSERT_EQUALS(stack.size(), (Stack::size_type)2);
}
void test_top_pop() {
Common::Stack<int> stack;
stack.push( 42);
stack.push(-23);
TS_ASSERT_EQUALS(stack[0], 42);
TS_ASSERT_EQUALS(stack.top(), -23);
stack[0] = -23;
stack.top() = 42;
TS_ASSERT_EQUALS(stack[0], -23);
TS_ASSERT_EQUALS(stack.top(), 42);
stack.pop();
TS_ASSERT_EQUALS(stack[0], -23);
}
void test_assign() {
Common::Stack<int> q1, q2;
for (int i = 0; i <= 4; ++i) {
q1.push(4-i);
q2.push(i);
}
Common::Stack<int> q3(q1);
for (int i = 0; i < 5; ++i) {
TS_ASSERT_EQUALS(q3.top(), i);
q3.pop();
}
TS_ASSERT(q3.empty());
q3 = q2;
for (int i = 4; i >= 0; --i) {
TS_ASSERT_EQUALS(q3.top(), i);
q3.pop();
}
TS_ASSERT(q3.empty());
TS_ASSERT(!q1.empty());
TS_ASSERT(!q2.empty());
}
};

23
test/common/str-helper.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef TEST_COMMON_HELPER_H
#define TEST_COMMON_HELPER_H
#include "common/str.h"
namespace CxxTest
{
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const Common::String &>
{
ValueTraits &operator=( const ValueTraits & );
Common::String _str;
public:
ValueTraits( const Common::String &value ) : _str( value ) {}
ValueTraits( const ValueTraits &other ) : _str( other._str ) {}
const char *asString( void ) const { return _str.c_str(); }
};
CXXTEST_COPY_CONST_TRAITS( Common::String &);
CXXTEST_COPY_TRAITS( Common::String, const Common::String &);
}
#endif

774
test/common/str.h Normal file
View File

@@ -0,0 +1,774 @@
#include <cxxtest/TestSuite.h>
#include "common/str.h"
#include "common/ustr.h"
#include "test/common/str-helper.h"
class StringTestSuite : public CxxTest::TestSuite
{
public:
void test_constructors() {
Common::String str("test-string");
TS_ASSERT_EQUALS(str, "test-string");
str = Common::String(str.c_str()+5, 3);
TS_ASSERT_EQUALS(str, "str");
str = "test-string";
TS_ASSERT_EQUALS(str, "test-string");
str = Common::String(str.c_str()+5, str.c_str()+8);
TS_ASSERT_EQUALS(str, "str");
str = Common::String(5, 'a');
TS_ASSERT_EQUALS(str, "aaaaa");
}
void test_trim() {
Common::String str(" This is a s tring with spaces ");
Common::String str2 = str;
str.trim();
TS_ASSERT_EQUALS(str, "This is a s tring with spaces");
TS_ASSERT_EQUALS(str2, " This is a s tring with spaces ");
}
void test_chop() {
Common::String str("test-string");
Common::String str2 = str;
str.chop();
TS_ASSERT_EQUALS(str, "test-strin");
TS_ASSERT_EQUALS(str2, "test-string");
str = "test-string";
str.chop(2);
TS_ASSERT_EQUALS(str, "test-stri");
str = "test-string";
str.chop(10);
TS_ASSERT_EQUALS(str, "t");
str = "test-string";
str.chop(11);
TS_ASSERT(str.empty());
str = "test-string";
str.chop(200);
TS_ASSERT(str.empty());
}
void test_empty_clear() {
Common::String str("test");
TS_ASSERT(!str.empty());
str.clear();
TS_ASSERT(str.empty());
}
void test_lastChar() {
Common::String str;
TS_ASSERT_EQUALS(str.lastChar(), '\0');
str = "test";
TS_ASSERT_EQUALS(str.lastChar(), 't');
Common::String str2("bar");
TS_ASSERT_EQUALS(str2.lastChar(), 'r');
}
void test_firstChar() {
Common::String str;
TS_ASSERT_EQUALS(str.firstChar(), '\0');
str = "first_test";
TS_ASSERT_EQUALS(str.firstChar(), 'f');
Common::String str2("bar");
TS_ASSERT_EQUALS(str2.firstChar(), 'b');
}
void test_assign1() {
Common::String str("foobar");
str.assign("bar");
TS_ASSERT_EQUALS(str, "bar");
}
void test_assign2() {
Common::String str("foobar");
str.assign("abcdef", 3);
TS_ASSERT_EQUALS(str, "abc");
}
void test_assign3() {
Common::String str("foobar");
str.assign(3, '0');
TS_ASSERT_EQUALS(str, "000");
}
void test_concat1() {
Common::String str("foo");
Common::String str2("bar");
str += str2;
TS_ASSERT_EQUALS(str, "foobar");
TS_ASSERT_EQUALS(str2, "bar");
}
void test_concat2() {
Common::String str("foo");
str += "bar";
TS_ASSERT_EQUALS(str, "foobar");
}
void test_concat3() {
Common::String str("foo");
str += 'X';
TS_ASSERT_EQUALS(str, "fooX");
}
void test_concat4() {
Common::String str("foo");
str.append(2, '+');
TS_ASSERT_EQUALS(str, "foo++");
}
void test_refCount() {
// using internal storage
Common::String foo1("foo");
Common::String foo2(foo1);
Common::String foo3(foo2);
foo3 += 'X';
TS_ASSERT_EQUALS(foo1, "foo");
TS_ASSERT_EQUALS(foo2, "foo");
TS_ASSERT_EQUALS(foo3, "foo""X");
foo2 = 'x';
TS_ASSERT_EQUALS(foo1, "foo");
TS_ASSERT_EQUALS(foo2, "x");
TS_ASSERT_EQUALS(foo3, "foo""X");
}
void test_refCount2() {
// using external storage
Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
Common::String foo2(foo1);
Common::String foo3(foo2);
foo3 += 'X';
TS_ASSERT_EQUALS(foo1, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
TS_ASSERT_EQUALS(foo2, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
TS_ASSERT_EQUALS(foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""X");
foo2 = 'x';
TS_ASSERT_EQUALS(foo1, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
TS_ASSERT_EQUALS(foo2, "x");
TS_ASSERT_EQUALS(foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""X");
}
void test_refCount3() {
Common::String foo1("0123456789abcdefghijk");
Common::String foo2(foo1);
Common::String foo3(foo2);
foo3 += "0123456789abcdefghijk";
TS_ASSERT_EQUALS(foo1, foo2);
TS_ASSERT_EQUALS(foo2, "0123456789abcdefghijk");
TS_ASSERT_EQUALS(foo3, "0123456789abcdefghijk""0123456789abcdefghijk");
foo2 = 'x';
TS_ASSERT_EQUALS(foo1, "0123456789abcdefghijk");
TS_ASSERT_EQUALS(foo2, "x");
TS_ASSERT_EQUALS(foo3, "0123456789abcdefghijk""0123456789abcdefghijk");
}
void test_refCount4() {
Common::String foo1("fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
Common::String foo2(foo1);
Common::String foo3(foo2);
foo3 += "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd";
TS_ASSERT_EQUALS(foo1, foo2);
TS_ASSERT_EQUALS(foo2, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
TS_ASSERT_EQUALS(foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
foo2 = 'x';
TS_ASSERT_EQUALS(foo1, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
TS_ASSERT_EQUALS(foo2, "x");
TS_ASSERT_EQUALS(foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
}
void test_refCount5() {
// using external storage
Common::String foo1("HelloHelloHelloHelloAndHi");
Common::String foo2(foo1);
for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i)
*i = 'h';
TS_ASSERT_EQUALS(foo1, "HelloHelloHelloHelloAndHi");
TS_ASSERT_EQUALS(foo2, "hhhhhhhhhhhhhhhhhhhhhhhhh");
}
void test_refCount6() {
// using internal storage
Common::String foo1("Hello");
Common::String foo2(foo1);
for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i)
*i = 'h';
TS_ASSERT_EQUALS(foo1, "Hello");
TS_ASSERT_EQUALS(foo2, "hhhhh");
}
void test_self_asignment() {
Common::String foo1("12345678901234567890123456789012");
foo1 = foo1.c_str() + 2;
TS_ASSERT_EQUALS(foo1, "345678901234567890123456789012");
Common::String foo2("123456789012");
foo2 = foo2.c_str() + 2;
TS_ASSERT_EQUALS(foo2, "3456789012");
// "foo3" and "foo4" will be using allocated storage from construction on.
Common::String foo3("12345678901234567890123456789012");
foo3 += foo3.c_str();
TS_ASSERT_EQUALS(foo3, "12345678901234567890123456789012""12345678901234567890123456789012");
Common::String foo4("12345678901234567890123456789012");
foo4 += foo4;
TS_ASSERT_EQUALS(foo4, "12345678901234567890123456789012""12345678901234567890123456789012");
// Based on our current Common::String implementation "foo5" and "foo6" will first use the internal storage,
// and on "operator +=" they will change to allocated memory.
Common::String foo5("123456789012");
foo5 += foo5.c_str();
TS_ASSERT_EQUALS(foo5, "123456789012""123456789012");
Common::String foo6("123456789012");
foo6 += foo6;
TS_ASSERT_EQUALS(foo6, "123456789012""123456789012");
// "foo7" and "foo8" will purely operate on internal storage.
Common::String foo7("1234");
foo7 += foo7.c_str();
TS_ASSERT_EQUALS(foo7, "1234""1234");
Common::String foo8("1234");
foo8 += foo8;
TS_ASSERT_EQUALS(foo8, "1234""1234");
Common::String foo9("123456789012345678901234567889012");
foo9 = foo9.c_str();
TS_ASSERT_EQUALS(foo9, "123456789012345678901234567889012");
foo9 = foo9;
TS_ASSERT_EQUALS(foo9, "123456789012345678901234567889012");
Common::String foo10("1234");
foo10 = foo10.c_str();
TS_ASSERT_EQUALS(foo10, "1234");
foo10 = foo10;
TS_ASSERT_EQUALS(foo10, "1234");
}
void test_hasPrefix() {
Common::String str("this/is/a/test, haha");
TS_ASSERT_EQUALS(str.hasPrefix(""), true);
TS_ASSERT_EQUALS(str.hasPrefix("this"), true);
TS_ASSERT_EQUALS(str.hasPrefix("thit"), false);
TS_ASSERT_EQUALS(str.hasPrefix("foo"), false);
}
void test_hasSuffix() {
Common::String str("this/is/a/test, haha");
TS_ASSERT_EQUALS(str.hasSuffix(""), true);
TS_ASSERT_EQUALS(str.hasSuffix("haha"), true);
TS_ASSERT_EQUALS(str.hasSuffix("hahb"), false);
TS_ASSERT_EQUALS(str.hasSuffix("hahah"), false);
}
void test_contains() {
Common::String str("this/is/a/test, haha");
TS_ASSERT_EQUALS(str.contains(""), true);
TS_ASSERT_EQUALS(str.contains("haha"), true);
TS_ASSERT_EQUALS(str.contains("hahb"), false);
TS_ASSERT_EQUALS(str.contains("test"), true);
TS_ASSERT_EQUALS(str.contains('/'), true);
TS_ASSERT_EQUALS(str.contains('x'), false);
}
void test_toLowercase() {
Common::String str("Test it, NOW! 42");
Common::String str2 = str;
str.toLowercase();
TS_ASSERT_EQUALS(str, "test it, now! 42");
TS_ASSERT_EQUALS(str2, "Test it, NOW! 42");
}
void test_toUppercase() {
Common::String str("Test it, NOW! 42");
Common::String str2 = str;
str.toUppercase();
TS_ASSERT_EQUALS(str, "TEST IT, NOW! 42");
TS_ASSERT_EQUALS(str2, "Test it, NOW! 42");
}
void test_deleteChar() {
Common::String str("01234567890123456789012345678901");
str.deleteChar(10);
TS_ASSERT_EQUALS(str, "0123456789123456789012345678901");
str.deleteChar(10);
TS_ASSERT_EQUALS(str, "012345678923456789012345678901");
}
void test_erase() {
Common::String str("01234567890123456789012345678901");
str.erase(18);
TS_ASSERT_EQUALS(str, "012345678901234567");
str.erase(7, 5);
TS_ASSERT_EQUALS(str, "0123456234567");
}
void test_sharing() {
Common::String str("01234567890123456789012345678901");
Common::String str2(str);
TS_ASSERT_EQUALS(str2, "01234567890123456789012345678901");
str.deleteLastChar();
TS_ASSERT_EQUALS(str, "0123456789012345678901234567890");
TS_ASSERT_EQUALS(str2, "01234567890123456789012345678901");
}
void test_lastPathComponent() {
TS_ASSERT_EQUALS(Common::lastPathComponent("/", '/'), "");
TS_ASSERT_EQUALS(Common::lastPathComponent("/foo/bar", '/'), "bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("/foo//bar/", '/'), "bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("/foo/./bar", '/'), "bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("/foo//./bar//", '/'), "bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("/foo//.bar//", '/'), ".bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("", '/'), "");
TS_ASSERT_EQUALS(Common::lastPathComponent("foo/bar", '/'), "bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("foo//bar/", '/'), "bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("foo/./bar", '/'), "bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("foo//./bar//", '/'), "bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("foo//.bar//", '/'), ".bar");
TS_ASSERT_EQUALS(Common::lastPathComponent("foo", '/'), "foo");
}
void test_normalizePath() {
TS_ASSERT_EQUALS(Common::normalizePath("/", '/'), "/");
TS_ASSERT_EQUALS(Common::normalizePath("/foo/bar", '/'), "/foo/bar");
TS_ASSERT_EQUALS(Common::normalizePath("/foo//bar/", '/'), "/foo/bar");
TS_ASSERT_EQUALS(Common::normalizePath("/foo/./bar", '/'), "/foo/bar");
TS_ASSERT_EQUALS(Common::normalizePath("/foo//./bar//", '/'), "/foo/bar");
TS_ASSERT_EQUALS(Common::normalizePath("/foo//.bar//", '/'), "/foo/.bar");
TS_ASSERT_EQUALS(Common::normalizePath("", '/'), "");
TS_ASSERT_EQUALS(Common::normalizePath("foo/bar", '/'), "foo/bar");
TS_ASSERT_EQUALS(Common::normalizePath("foo//bar/", '/'), "foo/bar");
TS_ASSERT_EQUALS(Common::normalizePath("foo/./bar", '/'), "foo/bar");
TS_ASSERT_EQUALS(Common::normalizePath("foo//./bar//", '/'), "foo/bar");
TS_ASSERT_EQUALS(Common::normalizePath("foo//.bar//", '/'), "foo/.bar");
TS_ASSERT_EQUALS(Common::normalizePath("..", '/'), "..");
TS_ASSERT_EQUALS(Common::normalizePath("../", '/'), "..");
TS_ASSERT_EQUALS(Common::normalizePath("/..", '/'), "/..");
TS_ASSERT_EQUALS(Common::normalizePath("../bar", '/'), "../bar");
TS_ASSERT_EQUALS(Common::normalizePath("foo//../", '/'), "");
TS_ASSERT_EQUALS(Common::normalizePath("foo/../bar", '/'), "bar");
TS_ASSERT_EQUALS(Common::normalizePath("foo//../bar//", '/'), "bar");
TS_ASSERT_EQUALS(Common::normalizePath("foo//..bar//", '/'), "foo/..bar");
TS_ASSERT_EQUALS(Common::normalizePath("foo/../../bar//", '/'), "../bar");
TS_ASSERT_EQUALS(Common::normalizePath("../foo/../bar", '/'), "../bar");
TS_ASSERT_EQUALS(Common::normalizePath("../../foo/bar/", '/'), "../../foo/bar");
}
void test_matchString() {
TS_ASSERT(Common::matchString("", "*"));
TS_ASSERT(Common::matchString("a", "*"));
TS_ASSERT(Common::matchString("monkey.s01", "*"));
TS_ASSERT(!Common::matchString("", "?"));
TS_ASSERT(Common::matchString("a", "?"));
TS_ASSERT(!Common::matchString("monkey.s01", "?"));
TS_ASSERT(Common::matchString("monkey.s01", "monkey.s??"));
TS_ASSERT(Common::matchString("monkey.s99", "monkey.s??"));
TS_ASSERT(!Common::matchString("monkey.s101", "monkey.s??"));
TS_ASSERT(Common::matchString("monkey.s01", "monkey.s?1"));
TS_ASSERT(!Common::matchString("monkey.s99", "monkey.s?1"));
TS_ASSERT(!Common::matchString("monkey.s101", "monkey.s?1"));
TS_ASSERT(Common::matchString("monkey.s01", "monkey.s*"));
TS_ASSERT(Common::matchString("monkey.s99", "monkey.s*"));
TS_ASSERT(Common::matchString("monkey.s101", "monkey.s*"));
TS_ASSERT(Common::matchString("monkey.s01", "monkey.s*1"));
TS_ASSERT(!Common::matchString("monkey.s99", "monkey.s*1"));
TS_ASSERT(Common::matchString("monkey.s101", "monkey.s*1"));
TS_ASSERT(Common::matchString("monkey.s01", "monkey.s##"));
TS_ASSERT(!Common::matchString("monkey.s01", "monkey.###"));
TS_ASSERT(Common::matchString("monkey.s0#", "monkey.s0\\#"));
TS_ASSERT(!Common::matchString("monkey.s0#", "monkey.s0#"));
TS_ASSERT(!Common::matchString("monkey.s01", "monkey.s0\\#"));
TS_ASSERT(!Common::String("").matchString("*_"));
TS_ASSERT(Common::String("a").matchString("a***"));
}
void test_string_printf() {
TS_ASSERT_EQUALS( Common::String::format(" "), " " );
TS_ASSERT_EQUALS( Common::String::format("%s", "test"), "test" );
TS_ASSERT_EQUALS( Common::String::format("%s.s%.02d", "monkey", 1), "monkey.s01" );
TS_ASSERT_EQUALS( Common::String::format("Some %s to make this string longer than the default built-in %s %d", "text", "capacity", 123456), "Some text to make this string longer than the default built-in capacity 123456" );
Common::String s = Common::String::format("%s%X", "test", 1234);
TS_ASSERT_EQUALS(s, "test4D2");
TS_ASSERT_EQUALS(s.size(), 7U);
}
void test_ustring_printf() {
//Ideally should be the same as above (make String template?)
TS_ASSERT_EQUALS( Common::U32String::format(" ").encode(), " " );
TS_ASSERT_EQUALS( Common::U32String::format("%s", "test").encode(), "test" );
TS_ASSERT_EQUALS( Common::U32String::format("%s%c%s", "Press ", 'X', " to win").encode(), "Press X to win" );
TS_ASSERT_EQUALS( Common::U32String::format("Some %s to make this string longer than the default built-in %s %d", "text", "capacity", 123456).encode(), "Some text to make this string longer than the default built-in capacity 123456" );
TS_ASSERT_EQUALS( Common::U32String::format("%u", 0).encode(), "0" );
TS_ASSERT_EQUALS( Common::U32String::format("%u", 1234).encode(), "1234" );
TS_ASSERT_EQUALS( Common::U32String::format("%d", 0).encode(), "0" );
TS_ASSERT_EQUALS( Common::U32String::format("%d", 1234).encode(), "1234" );
TS_ASSERT_EQUALS( Common::U32String::format("%d", -1234).encode(), "-1234" );
TS_ASSERT_EQUALS( Common::U32String::format("%u %%", 100).encode(), "100 %" );
}
void test_strlcpy() {
static const char * const testString = "1234567890";
char test1[4];
TS_ASSERT_EQUALS(Common::strlcpy(test1, testString, 4), strlen(testString));
TS_ASSERT_EQUALS(strcmp(test1, "123"), 0);
char test2[12];
test2[11] = 'X';
TS_ASSERT_EQUALS(Common::strlcpy(test2, testString, 11), strlen(testString));
TS_ASSERT_EQUALS(strcmp(test2, testString), 0);
TS_ASSERT_EQUALS(test2[11], 'X');
char test3[1] = { 'X' };
TS_ASSERT_EQUALS(Common::strlcpy(test3, testString, 0), strlen(testString));
TS_ASSERT_EQUALS(test3[0], 'X');
char test4[12];
TS_ASSERT_EQUALS(Common::strlcpy(test4, testString, 12), strlen(testString));
TS_ASSERT_EQUALS(strcmp(test4, testString), 0);
}
void test_strlcat() {
static const char * const initialString = "123";
static const char * const appendString = "4567890";
static const char * const resultString = "1234567890";
char test1[4];
TS_ASSERT_EQUALS(Common::strlcpy(test1, initialString, 4), strlen(initialString));
TS_ASSERT_EQUALS(strcmp(test1, initialString), 0);
TS_ASSERT_EQUALS(Common::strlcat(test1, appendString, 4), strlen(resultString));
TS_ASSERT_EQUALS(strcmp(test1, initialString), 0);
char test2[12];
test2[11] = 'X';
TS_ASSERT_EQUALS(Common::strlcpy(test2, initialString, 11), strlen(initialString));
TS_ASSERT_EQUALS(strcmp(test2, initialString), 0);
TS_ASSERT_EQUALS(Common::strlcat(test2, appendString, 11), strlen(resultString));
TS_ASSERT_EQUALS(strcmp(test2, resultString), 0);
TS_ASSERT_EQUALS(test2[11], 'X');
char test3[1];
test3[0] = 'X';
TS_ASSERT_EQUALS(Common::strlcat(test3, appendString, 0), strlen(appendString));
TS_ASSERT_EQUALS(test3[0], 'X');
char test4[11];
TS_ASSERT_EQUALS(Common::strlcpy(test4, initialString, 11), strlen(initialString));
TS_ASSERT_EQUALS(strcmp(test4, initialString), 0);
TS_ASSERT_EQUALS(Common::strlcat(test4, appendString, 11), strlen(resultString));
TS_ASSERT_EQUALS(strcmp(test4, resultString), 0);
}
void test_strnlen() {
static const char * const testString = "123";
TS_ASSERT_EQUALS(Common::strnlen(testString, 0), 0u);
TS_ASSERT_EQUALS(Common::strnlen(testString, 1), 1u);
TS_ASSERT_EQUALS(Common::strnlen(testString, 2), 2u);
TS_ASSERT_EQUALS(Common::strnlen(testString, 3), 3u);
TS_ASSERT_EQUALS(Common::strnlen(testString, 4), 3u);
const char testArray[4] = { '1', '2', '3', '4' };
TS_ASSERT_EQUALS(Common::strnlen(testArray, 0), 0u);
TS_ASSERT_EQUALS(Common::strnlen(testArray, 1), 1u);
TS_ASSERT_EQUALS(Common::strnlen(testArray, 2), 2u);
TS_ASSERT_EQUALS(Common::strnlen(testArray, 3), 3u);
TS_ASSERT_EQUALS(Common::strnlen(testArray, 4), 4u);
const char testArray2[4] = { '1', '\0', '3', '4' };
TS_ASSERT_EQUALS(Common::strnlen(testArray2, 0), 0u);
TS_ASSERT_EQUALS(Common::strnlen(testArray2, 1), 1u);
TS_ASSERT_EQUALS(Common::strnlen(testArray2, 2), 1u);
TS_ASSERT_EQUALS(Common::strnlen(testArray2, 3), 1u);
TS_ASSERT_EQUALS(Common::strnlen(testArray2, 4), 1u);
}
void test_scumm_stricmp() {
TS_ASSERT_EQUALS(scumm_stricmp("abCd", "abCd"), 0);
TS_ASSERT_EQUALS(scumm_stricmp("abCd", "ABCd"), 0);
TS_ASSERT_LESS_THAN(scumm_stricmp("abCd", "ABCe"), 0);
TS_ASSERT_LESS_THAN(scumm_stricmp("abCd", "ABCde"), 0);
}
void test_scumm_strnicmp() {
TS_ASSERT_EQUALS(scumm_strnicmp("abCd", "abCd", 3), 0);
TS_ASSERT_EQUALS(scumm_strnicmp("abCd", "ABCd", 4), 0);
TS_ASSERT_EQUALS(scumm_strnicmp("abCd", "ABCd", 5), 0);
TS_ASSERT_EQUALS(scumm_strnicmp("abCd", "ABCe", 3), 0);
TS_ASSERT_LESS_THAN(scumm_strnicmp("abCd", "ABCe", 4), 0);
TS_ASSERT_EQUALS(scumm_strnicmp("abCd", "ABCde", 4), 0);
TS_ASSERT_LESS_THAN(scumm_strnicmp("abCd", "ABCde", 5), 0);
}
void test_wordWrap() {
Common::String testString("123456");
testString.wordWrap(10);
TS_ASSERT(testString == "123456");
testString.wordWrap(2);
TS_ASSERT(testString == "12\n34\n56");
testString = "1234 5678";
testString.wordWrap(4);
TS_ASSERT(testString == "1234\n5678");
testString = "12 3 45";
testString.wordWrap(4);
TS_ASSERT(testString == "12 3\n45");
testString = "\n1\n23 45\n\n";
testString.wordWrap(3);
TS_ASSERT(testString == "\n1\n23\n45\n\n");
testString = "123 ";
testString.wordWrap(4);
TS_ASSERT(testString == "123 ");
testString.wordWrap(3);
TS_ASSERT(testString == "123\n");
}
void test_replace() {
// Tests created with the results of the STL std::string class
// --------------------------
// Tests without displacement
// --------------------------
Common::String testString = Common::String("This is the original string.");
// Positions and sizes as parameters, string as replacement
testString.replace(12, 8, Common::String("newnewne"));
TS_ASSERT_EQUALS(testString, Common::String("This is the newnewne string."));
// The same but with char*
testString.replace(0, 4, "That");
TS_ASSERT_EQUALS(testString, Common::String("That is the newnewne string."));
// Using iterators (also a terribly useless program as a test).
testString.replace(testString.begin(), testString.end(), "That is the supernew string.");
TS_ASSERT_EQUALS(testString, Common::String("That is the supernew string."));
// With sub strings of character arrays.
testString.replace(21, 6, "That phrase is new.", 5, 6);
TS_ASSERT_EQUALS(testString, Common::String("That is the supernew phrase."));
// Now with substrings.
testString.replace(12, 2, Common::String("That hy is new."), 5, 2);
TS_ASSERT_EQUALS(testString, Common::String("That is the hypernew phrase."));
// --------------------------
// Tests with displacement
// --------------------------
testString = Common::String("Hello World");
// Positions and sizes as parameters, string as replacement
testString.replace(6, 5, Common::String("friends"));
TS_ASSERT_EQUALS(testString, Common::String("Hello friends"));
// The same but with char*
testString.replace(0, 5, "Good");
TS_ASSERT_EQUALS(testString, Common::String("Good friends"));
// Using iterators (also a terribly useless program as a test)
testString.replace(testString.begin() + 4, testString.begin() + 5, " coffee ");
TS_ASSERT_EQUALS(testString, Common::String("Good coffee friends"));
// With sub strings of character arrays
testString.replace(4, 0, "Lorem ipsum expresso dolor sit amet", 11, 9);
TS_ASSERT_EQUALS(testString, Common::String("Good expresso coffee friends"));
// Now with substrings
testString.replace(5, 9, Common::String("Displaced ristretto string"), 10, 10);
TS_ASSERT_EQUALS(testString, Common::String("Good ristretto coffee friends"));
// -----------------------
// Deep copy compliance
// -----------------------
// Makes a deep copy without changing the length of the original
Common::String s1 = "TestTestTestTestTestTestTestTestTestTestTest";
Common::String s2(s1);
TS_ASSERT_EQUALS(s1, "TestTestTestTestTestTestTestTestTestTestTest");
TS_ASSERT_EQUALS(s2, "TestTestTestTestTestTestTestTestTestTestTest");
s1.replace(0, 4, "TEST");
TS_ASSERT_EQUALS(s1, "TESTTestTestTestTestTestTestTestTestTestTest");
TS_ASSERT_EQUALS(s2, "TestTestTestTestTestTestTestTestTestTestTest");
// Makes a deep copy when we shorten the string
Common::String s3 = "TestTestTestTestTestTestTestTestTestTestTest";
Common::String s4(s3);
s3.replace(0, 32, "");
TS_ASSERT_EQUALS(s3, "TestTestTest");
TS_ASSERT_EQUALS(s4, "TestTestTestTestTestTestTestTestTestTestTest");
}
void test_ustring_replace() {
// These tests are inspired from the above string tests
// --------------------------
// Tests without displacement
// --------------------------
Common::U32String testString = Common::U32String("This is the original string.");
// Positions and sizes as parameters, U32String as replacement
testString.replace(12, 8, Common::U32String("newnewne"));
TS_ASSERT_EQUALS(testString, Common::U32String("This is the newnewne string."));
// Using iterators (also a terribly useless program as a test).
testString.replace(testString.begin(), testString.end(), Common::U32String("That is the supernew string."));
TS_ASSERT_EQUALS(testString, Common::U32String("That is the supernew string."));
// With substrings.
testString.replace(12, 2, Common::U32String("That hy is new."), 5, 2);
TS_ASSERT_EQUALS(testString, Common::U32String("That is the hypernew string."));
// --------------------------
// Tests with displacement
// --------------------------
testString = Common::U32String("Hello World");
// Positions and sizes as parameters, string as replacement
testString.replace(6, 5, Common::U32String("friends"));
TS_ASSERT_EQUALS(testString, Common::U32String("Hello friends"));
// Using iterators (also a terribly useless program as a test)
testString.replace(testString.begin() + 5, testString.begin() + 6, Common::U32String(" good "));
TS_ASSERT_EQUALS(testString, Common::U32String("Hello good friends"));
// With substrings
testString.replace(6, 0, Common::U32String("Displaced my string"), 10, 3);
TS_ASSERT_EQUALS(testString, Common::U32String("Hello my good friends"));
// -----------------------
// Deep copy compliance
// -----------------------
// Makes a deep copy without changing the length of the original
Common::U32String s1 = Common::U32String("TestTestTestTestTestTestTestTestTestTestTest");
Common::U32String s2(s1);
TS_ASSERT_EQUALS(s1, "TestTestTestTestTestTestTestTestTestTestTest");
TS_ASSERT_EQUALS(s2, "TestTestTestTestTestTestTestTestTestTestTest");
s1.replace(0, 4, Common::U32String("TEST"));
TS_ASSERT_EQUALS(s1, "TESTTestTestTestTestTestTestTestTestTestTest");
TS_ASSERT_EQUALS(s2, "TestTestTestTestTestTestTestTestTestTestTest");
// Makes a deep copy when we shorten the string
Common::U32String s3 = Common::U32String("TestTestTestTestTestTestTestTestTestTestTest");
Common::U32String s4(s3);
s3.replace(0, 32, Common::U32String());
TS_ASSERT_EQUALS(s3, "TestTestTest");
TS_ASSERT_EQUALS(s4, "TestTestTestTestTestTestTestTestTestTestTest");
}
void test_find() {
Common::String a("0123012"), b;
TS_ASSERT_EQUALS(a.find('1'), 1u);
TS_ASSERT_EQUALS(a.find('3'), 3u);
TS_ASSERT_EQUALS(a.find('1', 3), 5u);
TS_ASSERT_EQUALS(b.find('*'), Common::String::npos);
TS_ASSERT_EQUALS(b.find('*', 1), Common::String::npos);
TS_ASSERT_EQUALS(a.rfind('1'), 5u);
TS_ASSERT_EQUALS(a.rfind('3'), 3u);
TS_ASSERT_EQUALS(a.rfind('1', 3), 1u);
TS_ASSERT_EQUALS(b.rfind('*'), Common::String::npos);
TS_ASSERT_EQUALS(b.rfind('*', 1), Common::String::npos);
}
void test_setChar() {
Common::String testString("123456");
testString.setChar('2', 0);
TS_ASSERT(testString == "223456");
testString.setChar('0', 5);
TS_ASSERT(testString == "223450");
}
void test_insertChar() {
Common::String testString("123456");
testString.insertChar('2', 0);
TS_ASSERT(testString == "2123456");
testString.insertChar('0', 5);
TS_ASSERT(testString == "21234056");
testString.insertChar('7', 8);
TS_ASSERT(testString == "212340567");
}
void test_insertString() {
Common::String testString("123456");
testString.insertString("12", 0);
TS_ASSERT(testString == "12123456");
testString.insertString("01", 6);
TS_ASSERT(testString == "1212340156");
testString.insertString("78", 10);
TS_ASSERT(testString == "121234015678");
}
void test_comparison() {
Common::String a("0123"), ax("01234"), b("0124"), e;
TS_ASSERT_EQUALS(a, a);
TS_ASSERT_EQUALS(ax, ax);
TS_ASSERT_EQUALS(b, b);
TS_ASSERT_EQUALS(e, e);
TS_ASSERT_DIFFERS(a, ax);
TS_ASSERT_DIFFERS(a, b);
TS_ASSERT_DIFFERS(a, e);
TS_ASSERT_DIFFERS(ax, b);
TS_ASSERT_DIFFERS(ax, e);
TS_ASSERT_DIFFERS(b, ax);
TS_ASSERT_DIFFERS(b, e);
TS_ASSERT_LESS_THAN(e, a);
TS_ASSERT_LESS_THAN(e, ax);
TS_ASSERT_LESS_THAN(e, b);
TS_ASSERT_LESS_THAN(a, ax);
TS_ASSERT_LESS_THAN(a, b);
TS_ASSERT_LESS_THAN(ax, b);
}
void test_ustr_comparison() {
Common::U32String a("abc"), b("abd"), c, d("");
TS_ASSERT_EQUALS(a, a);
TS_ASSERT_EQUALS(b, b);
TS_ASSERT_DIFFERS(a, b);
TS_ASSERT_LESS_THAN(a, b);
TS_ASSERT_LESS_THAN_EQUALS(a, b);
TS_ASSERT_LESS_THAN_EQUALS(a, a);
TS_ASSERT_LESS_THAN_EQUALS(b, b);
//U32String does not define compare, so test both sides
TS_ASSERT(a >= a);
TS_ASSERT(b > a);
TS_ASSERT(b >= b);
TS_ASSERT(b >= a);
TS_ASSERT(c == d);
TS_ASSERT(a > c);
TS_ASSERT(c < a);
}
};

46
test/common/stream.h Normal file
View File

@@ -0,0 +1,46 @@
#include <cxxtest/TestSuite.h>
#include "common/memstream.h"
class ReadLineStreamTestSuite : public CxxTest::TestSuite {
public:
void test_readline() {
byte contents[] = { 'a', 'b', '\n', '\n', 'c', '\n' };
Common::MemoryReadStream ms(contents, sizeof(contents));
char buffer[100];
TS_ASSERT_DIFFERS((char *)0, ms.readLine(buffer, sizeof(buffer)));
TS_ASSERT_EQUALS(0, strcmp(buffer, "ab\n"));
TS_ASSERT_DIFFERS((char *)0, ms.readLine(buffer, sizeof(buffer)));
TS_ASSERT_EQUALS(0, strcmp(buffer, "\n"));
TS_ASSERT_DIFFERS((char *)0, ms.readLine(buffer, sizeof(buffer)));
TS_ASSERT_EQUALS(0, strcmp(buffer, "c\n"));
TS_ASSERT(!ms.eos());
TS_ASSERT_EQUALS((char *)0, ms.readLine(buffer, sizeof(buffer)));
TS_ASSERT(ms.eos());
}
void test_readline2() {
byte contents[] = { 'a', 'b', '\n', '\n', 'c' };
Common::MemoryReadStream ms(contents, sizeof(contents));
char buffer[100];
TS_ASSERT_DIFFERS((char *)0, ms.readLine(buffer, sizeof(buffer)));
TS_ASSERT_EQUALS(0, strcmp(buffer, "ab\n"));
TS_ASSERT_DIFFERS((char *)0, ms.readLine(buffer, sizeof(buffer)));
TS_ASSERT_EQUALS(0, strcmp(buffer, "\n"));
TS_ASSERT_DIFFERS((char *)0, ms.readLine(buffer, sizeof(buffer)));
TS_ASSERT_EQUALS(0, strcmp(buffer, "c"));
TS_ASSERT(ms.eos());
}
};

View File

@@ -0,0 +1,47 @@
#include <cxxtest/TestSuite.h>
#include "common/memstream.h"
#include "common/substream.h"
class SubReadStreamTestSuite : public CxxTest::TestSuite {
public:
void test_traverse() {
byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Common::MemoryReadStream ms(contents, 10);
int end = 5;
Common::SubReadStream srs(&ms, end);
int i;
byte b;
for (i = 0; i < end; ++i) {
TS_ASSERT(!srs.eos());
b = srs.readByte();
TS_ASSERT_EQUALS(i, b);
}
TS_ASSERT(!srs.eos());
b = srs.readByte();
TS_ASSERT(srs.eos());
}
void test_safe_eos() {
byte contents[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Common::MemoryReadStream ms(contents, sizeof(contents));
Common::SafeSeekableSubReadStream ssrs1(&ms, 0, sizeof(contents));
Common::SafeSeekableSubReadStream ssrs2(&ms, 0, sizeof(contents));
// Read after the end of the stream of the first sub stream
for (int32 i = 0; i <= ssrs1.size(); ++i)
ssrs1.readByte();
// eos should be set for the first sub stream
TS_ASSERT(ssrs1.eos());
// eos should not be set for the second sub stream
TS_ASSERT(!ssrs2.eos());
}
};

57
test/common/tokenizer.h Normal file
View File

@@ -0,0 +1,57 @@
#include <cxxtest/TestSuite.h>
#include "common/util.h"
#include "common/tokenizer.h"
class TokenizerTestSuite : public CxxTest::TestSuite {
public:
void test_nextToken() {
// test normal behavior
Common::StringTokenizer strTokenizer("Now, this is a test!", " ,!");
Common::String tokenArray[] = {"Now", "this", "is", "a", "test"};
for (int i = 0; i < ARRAYSIZE(tokenArray); ++i) {
// make sure nextToken works correctly
TS_ASSERT_EQUALS(tokenArray[i], strTokenizer.nextToken());
}
TS_ASSERT(strTokenizer.empty());
// Test edge cases:
// empty string
Common::StringTokenizer s1("");
TS_ASSERT_EQUALS("", s1.nextToken());
TS_ASSERT(s1.empty());
// empty delimiter
Common::StringTokenizer s2("test String", "");
TS_ASSERT_EQUALS("test String", s2.nextToken());
// string is the delimiter
Common::StringTokenizer s3("abc", "abc");
TS_ASSERT_EQUALS("", s3.nextToken());
TS_ASSERT(s3.empty());
// consecutive delimiters in the string
Common::StringTokenizer s4("strstr,after all!!", "str, !");
TS_ASSERT_EQUALS("af", s4.nextToken());
}
void test_resetAndEmpty() {
Common::StringTokenizer strTokenizer("Just, another test!", " ,!");
// test reset()
Common::String token1 = strTokenizer.nextToken(); //Just
TS_ASSERT_EQUALS(token1, "Just");
strTokenizer.reset();
Common::String token2 = strTokenizer.nextToken(); //Just
TS_ASSERT_EQUALS(token2, "Just");
// test empty()
TS_ASSERT(!strTokenizer.empty());
strTokenizer.nextToken(); //another
strTokenizer.nextToken(); //test
TS_ASSERT(strTokenizer.empty());
}
};

253
test/common/util.h Normal file
View File

@@ -0,0 +1,253 @@
#include <cxxtest/TestSuite.h>
#include "common/util.h"
/**
* Test suite for the functions in common/util.h
*/
class UtilTestSuite : public CxxTest::TestSuite {
public:
void test_parsebool_yesno() {
// First test for the parseBool function.
// These are the mixed case yes/no cases that must work
bool valasbool;
bool success;
Common::String string_1("Yes");
success = Common::parseBool(string_1, valasbool);
TS_ASSERT_EQUALS(success, 1);
TS_ASSERT_EQUALS(valasbool, 1);
Common::String string_2("nO");
success = Common::parseBool(string_2, valasbool);
TS_ASSERT_EQUALS(success, 1);
TS_ASSERT_EQUALS(valasbool, 0);
}
void test_parsebool_truefalse() {
// First test for the parseBool function.
// These are the mixed case true/false cases that must work
bool valasbool;
bool success;
Common::String string_3("tRuE");
success = Common::parseBool(string_3, valasbool);
TS_ASSERT_EQUALS(success, 1);
TS_ASSERT_EQUALS(valasbool, 1);
Common::String string_4("fAlSe");
success = Common::parseBool(string_4, valasbool);
TS_ASSERT_EQUALS(success, 1);
TS_ASSERT_EQUALS(valasbool, 0);
}
void test_parsebool_onezero() {
// Third test for the parseBool function.
// These are the 1/0 cases that must work.
// Note that while 'a-z'+0x20 must work just fine,
// '0-1'+0x20 should NOT; this is addressed in
// parsebool_bad
bool valasbool;
bool success;
Common::String string_5("1");
success = Common::parseBool(string_5, valasbool);
TS_ASSERT_EQUALS(success, 1);
TS_ASSERT_EQUALS(valasbool, 1);
Common::String string_6("0");
success = Common::parseBool(string_6, valasbool);
TS_ASSERT_EQUALS(success, 1);
TS_ASSERT_EQUALS(valasbool, 0);
}
void test_parsebool_bad() {
bool valasbool;
bool success;
// Bad cases that should not return success #1:
// Random string
Common::String string_1("u_f1ght_l1k3_a_c0w");
success = Common::parseBool(string_1, valasbool);
TS_ASSERT_EQUALS(success, 0);
// Bad cases that should not return success #2, #3:
// The function should NOT accept trailing whitespaces:
Common::String string_2(" yes");
success = Common::parseBool(string_2, valasbool);
TS_ASSERT_EQUALS(success, 0);
Common::String string_3("yes ");
success = Common::parseBool(string_3, valasbool);
TS_ASSERT_EQUALS(success, 0);
// While 'a-z'+0x20 must work just fine,
// '0-1'+0x20 should NOT. '2' is not good either.
Common::String string_4("\x50");
success = Common::parseBool(string_4, valasbool);
TS_ASSERT_EQUALS(success, 0);
Common::String string_5("\x51");
success = Common::parseBool(string_5, valasbool);
TS_ASSERT_EQUALS(success, 0);
Common::String string_6("2");
success = Common::parseBool(string_6, valasbool);
TS_ASSERT_EQUALS(success, 0);
}
void test_is_al_num() {
// Test the isAlnum function
// Should return true if and only if the input is an alphanumeric char
TS_ASSERT_EQUALS(Common::isAlnum('a'), 1);
TS_ASSERT_EQUALS(Common::isAlnum('A'), 1);
TS_ASSERT_EQUALS(Common::isAlnum('z'), 1);
TS_ASSERT_EQUALS(Common::isAlnum('Z'), 1);
TS_ASSERT_EQUALS(Common::isAlnum('1'), 1);
TS_ASSERT_EQUALS(Common::isAlnum('0'), 1);
TS_ASSERT_EQUALS(Common::isAlnum('\xA7'), 0);
TS_ASSERT_EQUALS(Common::isAlnum('$'), 0);
TS_ASSERT_EQUALS(Common::isAlnum(' '), 0);
TS_ASSERT_EQUALS(Common::isAlnum('\n'), 0);
TS_ASSERT_EQUALS(Common::isAlnum('\b'), 0);
TS_ASSERT_EQUALS(Common::isAlnum(0), 0);
TS_ASSERT_EQUALS(Common::isAlnum(255), 0);
}
void test_is_alpha() {
// Test the isAlpha function
// Should return true if and only if the input is an alphanumeric char
TS_ASSERT_EQUALS(Common::isAlpha('a'), 1);
TS_ASSERT_EQUALS(Common::isAlpha('A'), 1);
TS_ASSERT_EQUALS(Common::isAlpha('z'), 1);
TS_ASSERT_EQUALS(Common::isAlpha('Z'), 1);
TS_ASSERT_EQUALS(Common::isAlpha('1'), 0);
TS_ASSERT_EQUALS(Common::isAlpha('0'), 0);
TS_ASSERT_EQUALS(Common::isAlpha('\xA7'), 0);
TS_ASSERT_EQUALS(Common::isAlpha('$'), 0);
TS_ASSERT_EQUALS(Common::isAlpha(' '), 0);
TS_ASSERT_EQUALS(Common::isAlpha('\n'), 0);
TS_ASSERT_EQUALS(Common::isAlpha('\b'), 0);
TS_ASSERT_EQUALS(Common::isAlpha(0), 0);
TS_ASSERT_EQUALS(Common::isAlpha(255), 0);
}
void test_is_digit() {
// Test the isDigit function
// Should return true if and only if the input is a single digit
TS_ASSERT_EQUALS(Common::isDigit('a'), 0);
TS_ASSERT_EQUALS(Common::isDigit('A'), 0);
TS_ASSERT_EQUALS(Common::isDigit('z'), 0);
TS_ASSERT_EQUALS(Common::isDigit('Z'), 0);
TS_ASSERT_EQUALS(Common::isDigit('1'), 1);
TS_ASSERT_EQUALS(Common::isDigit('0'), 1);
TS_ASSERT_EQUALS(Common::isDigit('\xA7'), 0);
TS_ASSERT_EQUALS(Common::isDigit('$'), 0);
TS_ASSERT_EQUALS(Common::isDigit(' '), 0);
TS_ASSERT_EQUALS(Common::isDigit('\n'), 0);
TS_ASSERT_EQUALS(Common::isDigit('\b'), 0);
TS_ASSERT_EQUALS(Common::isDigit(0), 0);
TS_ASSERT_EQUALS(Common::isDigit(255), 0);
}
void test_is_lower() {
// Test the isLower function
// Should return true if and only if the input is a lowercase char
TS_ASSERT_EQUALS(Common::isLower('a'), 1);
TS_ASSERT_EQUALS(Common::isLower('A'), 0);
TS_ASSERT_EQUALS(Common::isLower('z'), 1);
TS_ASSERT_EQUALS(Common::isLower('Z'), 0);
TS_ASSERT_EQUALS(Common::isLower('1'), 0);
TS_ASSERT_EQUALS(Common::isLower('0'), 0);
TS_ASSERT_EQUALS(Common::isLower('\xA7'), 0);
TS_ASSERT_EQUALS(Common::isLower('$'), 0);
TS_ASSERT_EQUALS(Common::isLower(' '), 0);
TS_ASSERT_EQUALS(Common::isLower('\n'), 0);
TS_ASSERT_EQUALS(Common::isLower('\b'), 0);
TS_ASSERT_EQUALS(Common::isLower(0), 0);
TS_ASSERT_EQUALS(Common::isLower(255), 0);
}
void test_is_upper() {
// Test the isUpper function
// Should return true if and only if the input is an uppercase char
TS_ASSERT_EQUALS(Common::isUpper('a'), 0);
TS_ASSERT_EQUALS(Common::isUpper('A'), 1);
TS_ASSERT_EQUALS(Common::isUpper('z'), 0);
TS_ASSERT_EQUALS(Common::isUpper('Z'), 1);
TS_ASSERT_EQUALS(Common::isUpper('1'), 0);
TS_ASSERT_EQUALS(Common::isUpper('0'), 0);
TS_ASSERT_EQUALS(Common::isUpper('\xA7'), 0);
TS_ASSERT_EQUALS(Common::isUpper('$'), 0);
TS_ASSERT_EQUALS(Common::isUpper(' '), 0);
TS_ASSERT_EQUALS(Common::isUpper('\n'), 0);
TS_ASSERT_EQUALS(Common::isUpper('\b'), 0);
TS_ASSERT_EQUALS(Common::isUpper(0), 0);
TS_ASSERT_EQUALS(Common::isUpper(255), 0);
}
void test_is_space() {
// isSpace should return true iff the character is some kind of whitespace
// or tab character
for (int c = 0; c < 255; c++) {
if (c == ' ' || c == '\t' ||
c == '\r' || c == '\n' ||
c == '\v' || c == '\f') {
TS_ASSERT_EQUALS(Common::isSpace(c), 1);
} else {
TS_ASSERT_EQUALS(Common::isSpace(c), 0);
}
}
}
void test_is_print() {
// isPrint should return true iff the input is a printable ascii char.
// That is to say, 0x20 to 0x7E.
for (int c = 0; c < 255; c++) {
if (c >= 0x20 && c <= 0x7E) {
TS_ASSERT_EQUALS(Common::isPrint(c), 1);
} else {
TS_ASSERT_EQUALS(Common::isPrint(c), 0);
}
}
}
void test_is_punct() {
// isPunct should return true if the input is a punctation ascii char.
for (int c = 0; c < 255; c++) {
if (c >= 33 && c <= 47) {
TS_ASSERT_EQUALS(Common::isPunct(c), 1);
} else if (c >= 58 && c <= 64) {
TS_ASSERT_EQUALS(Common::isPunct(c), 1);
} else if (c >= 91 && c <= 96) {
TS_ASSERT_EQUALS(Common::isPunct(c), 1);
} else if (c >= 123 && c <= 126) {
TS_ASSERT_EQUALS(Common::isPunct(c), 1);
} else {
TS_ASSERT_EQUALS(Common::isPunct(c), 0);
}
}
}
};

502
test/cxxtest/COPYING Normal file
View File

@@ -0,0 +1,502 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

63
test/cxxtest/README Normal file
View File

@@ -0,0 +1,63 @@
Introduction
------------
CxxTest is a JUnit/CppUnit/xUnit-like framework for C++.
Its advantages over existing alternatives are that it:
- Doesn't require RTTI
- Doesn't require member template functions
- Doesn't require exception handling
- Doesn't require any external libraries (including memory management,
file/console I/O, graphics libraries)
This makes it extremely portable and usable.
CxxTest is available under the GNU Lesser General Public Licence (LGPL).
See http://www.gnu.org/copyleft/lesser.html for the license.
Simple user's guide
-------------------
1. Create a test suite header file:
MyTest.h:
#include <cxxtest/TestSuite.h>
class MyTestSuite : public CxxTest::TestSuite
{
public:
void testAddition( void )
{
TS_ASSERT( 1 + 1 > 1 );
TS_ASSERT_EQUALS( 1 + 1, 2 );
}
};
2. Generate the tests file:
# cxxtestgen.pl -o tests.cpp MyTestSuite.h
3. Create a main function that runs the tests
main.cpp:
#include <cxxtest/ErrorPrinter.h>
int main( void )
{
CxxText::ErrorPrinter::runAllTests();
return 0;
}
4. Compile and run!
# g++ -o main main.cpp tests.cpp
# ./main
Running 1 test(s).OK!
Advanced User's Guide
---------------------
See docs/guide.html.

33
test/cxxtest/TODO Normal file
View File

@@ -0,0 +1,33 @@
This is an -*- Outline -*- of ideas for future versions of CxxTest.
It is not meant to be "human readable".
* CxxTest To Do list
** Mock framework
Write some mocks
*** Distribution
Separate packages (w/ binaries)? How would that be used?
For Windows: .lib for "Real" and "Mock" parts.
For Linux: Maybe. Different compilers etc.
So probably only source release with Makefiles and .ds[pw]? Or just Win32 binary.
**** Installation?
extract cxxtest-x.y.z.tar.gz
(extract cxxtest-mock-x.y.z.tar.gz) ?
make -C cxxtest/Real
make -C cxxtest/Mock
or maybe make -C cxxtest -f Makefile.mock
but then Makefile.mock.bcc32, Makefile.mock.msvc, Makefile.mock.gcc, and heaven knows what else.
Could put the Makefile.mock.* in cxxtest/Real and cxxtest/Mock or in cxxtest/T
Maybe this should be a different package altogether?
Seems logical, since they evolve separately. But then you'd want to download both.
** Thoughts
-fomit-frame-pointer
** TS_HEX

152
test/cxxtest/Versions Normal file
View File

@@ -0,0 +1,152 @@
CxxTest Releases
================
Version 3.10.1 (2004-12-01):
----------------------------
- Improved support for VC7
- Fixed clash with some versions of STL
Version 3.10.0 (2004-11-20):
----------------------------
- Added mock framework for global functions
- Added TS_ASSERT_THROWS_ASSERT and TS_ASSERT_THROWS_EQUALS
- Added CXXTEST_ENUM_TRAITS
- Improved support for STL classes (vector, map etc.)
- Added support for Digital Mars compiler
- Reduced root/part compilation time and binary size
- Support C++-style commenting of tests
Version 3.9.1 (2004-01-19):
---------------------------
- Fixed small bug with runner exit code
- Embedded test suites are now deprecated
Version 3.9.0 (2004-01-17):
---------------------------
- Added TS_TRACE
- Added --no-static-init
- CxxTest::setAbortTestOnFail() works even without --abort-on-fail
Version 3.8.5 (2004-01-08):
---------------------------
- Added --no-eh
- Added CxxTest::setAbortTestOnFail() and CXXTEST_DEFAULT_ABORT
- Added CxxTest::setMaxDumpSize()
- Added StdioFilePrinter
Version 3.8.4 (2003-12-31):
---------------------------
- Split distribution into cxxtest and cxxtest-selftest
- Added `sample/msvc/FixFiles.bat'
Version 3.8.3 (2003-12-24):
---------------------------
- Added TS_ASSERT_PREDICATE
- Template files can now specify where to insert the preamble
- Added a sample Visual Studio workspace in `sample/msvc'
- Can compile in MSVC with warning level 4
- Changed output format slightly
Version 3.8.1 (2003-12-21):
---------------------------
- Fixed small bug when using multiple --part files.
- Fixed X11 GUI crash when there's no X server.
- Added GlobalFixture::setUpWorld()/tearDownWorld()
- Added leaveOnly(), activateAllTests() and `sample/only.tpl'
- Should now run without warnings on Sun compiler.
Version 3.8.0 (2003-12-13):
---------------------------
- Fixed bug where `Root.cpp' needed exception handling
- Added TS_ASSERT_RELATION
- TSM_ macros now also tell you what went wrong
- Renamed Win32Gui::free() to avoid clashes
- Now compatible with more versions of Borland compiler
- Improved the documentation
Version 3.7.1 (2003-09-29):
---------------------------
- Added --version
- Compiles with even more exotic g++ warnings
- Win32 Gui compiles with UNICODE
- Should compile on some more platforms (Sun Forte, HP aCC)
Version 3.7.0 (2003-09-20):
---------------------------
- Added TS_ASSERT_LESS_THAN_EQUALS
- Minor cleanups
Version 3.6.1 (2003-09-15):
---------------------------
- Improved QT GUI
- Improved portability some more
Version 3.6.0 (2003-09-04):
---------------------------
- Added --longlong
- Some portability improvements
Version 3.5.1 (2003-09-03):
---------------------------
- Major internal rewrite of macros
- Added TS_ASSERT_SAME_DATA
- Added --include option
- Added --part and --root to enable splitting the test runner
- Added global fixtures
- Enhanced Win32 GUI with timers, -keep and -title
- Now compiles with strict warnings
Version 3.1.1 (2003-08-27):
---------------------------
- Fixed small bug in TS_ASSERT_THROWS_*()
Version 3.1.0 (2003-08-23):
---------------------------
- Default ValueTraits now dumps value as hex bytes
- Fixed double invocation bug (e.g. TS_FAIL(functionWithSideEffects()))
- TS_ASSERT_THROWS*() are now "abort on fail"-friendly
- Win32 GUI now supports Windows 98 and doesn't need comctl32.lib
Version 3.0.1 (2003-08-07):
---------------------------
- Added simple GUI for X11, Win32 and Qt
- Added TS_WARN() macro
- Removed --exit-code
- Improved samples
- Improved support for older (pre-std::) compilers
- Made a PDF version of the User's Guide
Version 2.8.4 (2003-07-21):
---------------------------
- Now supports g++-3.3
- Added --have-eh
- Fixed bug in numberToString()
Version 2.8.3 (2003-06-30):
---------------------------
- Fixed bugs in cxxtestgen.pl
- Fixed warning for some compilers in ErrorPrinter/StdioPrinter
- Thanks Martin Jost for pointing out these problems!
Version 2.8.2 (2003-06-10):
---------------------------
- Fixed bug when using CXXTEST_ABORT_TEST_ON_FAIL without standard library
- Added CXXTEST_USER_TRAITS
- Added --abort-on-fail
Version 2.8.1 (2003-01-16):
---------------------------
- Fixed charToString() for negative chars
Version 2.8.0 (2003-01-13):
---------------------------
- Added CXXTEST_ABORT_TEST_ON_FAIL for xUnit-like behaviour
- Added `sample/winddk'
- Improved ValueTraits
- Improved output formatter
- Started version history
Version 2.7.0 (2002-09-29):
---------------------------
- Added embedded test suites
- Major internal improvements

39
test/cxxtest/cxxtest.spec Normal file
View File

@@ -0,0 +1,39 @@
Name: cxxtest
Summary: CxxTest Testing Framework for C++
Version: 3.10.1
Release: 1
Copyright: LGPL
Group: Development/C++
Source: cxxtest-%{version}.tar.gz
BuildRoot: /tmp/cxxtest-build
BuildArch: noarch
Prefix: /usr
%description
CxxTest is a JUnit/CppUnit/xUnit-like framework for C++.
Its advantages over existing alternatives are that it:
- Doesn't require RTTI
- Doesn't require member template functions
- Doesn't require exception handling
- Doesn't require any external libraries (including memory management,
file/console I/O, graphics libraries)
%prep
%setup -n cxxtest
%build
%install
install -m 755 -d $RPM_BUILD_ROOT/usr/bin $RPM_BUILD_ROOT/usr/include/cxxtest
install -m 755 cxxtestgen.p[ly] $RPM_BUILD_ROOT/usr/bin/
install -m 644 cxxtest/* $RPM_BUILD_ROOT/usr/include/cxxtest/
%clean
rm -rf $RPM_BUILD_ROOT
%files
%attr(-, root, root) %doc README
%attr(-, root, root) %doc sample
%attr(-, root, root) /usr/include/cxxtest
%attr(-, root, root) /usr/bin/cxxtestgen.pl
%attr(-, root, root) /usr/bin/cxxtestgen.py

View File

@@ -0,0 +1,58 @@
#ifndef __cxxtest__Descriptions_cpp__
#define __cxxtest__Descriptions_cpp__
#include <cxxtest/Descriptions.h>
namespace CxxTest
{
TestDescription::~TestDescription() {}
SuiteDescription::~SuiteDescription() {}
WorldDescription::~WorldDescription() {}
//
// Convert total tests to string
//
#ifndef _CXXTEST_FACTOR
char *WorldDescription::strTotalTests( char *s ) const
{
numberToString( numTotalTests(), s );
return s;
}
#else // _CXXTEST_FACTOR
char *WorldDescription::strTotalTests( char *s ) const
{
char *p = numberToString( numTotalTests(), s );
if ( numTotalTests() <= 1 )
return s;
unsigned n = numTotalTests();
unsigned numFactors = 0;
for ( unsigned factor = 2; (factor * factor) <= n; factor += (factor == 2) ? 1 : 2 ) {
unsigned power;
for ( power = 0; (n % factor) == 0; n /= factor )
++ power;
if ( !power )
continue;
p = numberToString( factor, copyString( p, (numFactors == 0) ? " = " : " * " ) );
if ( power > 1 )
p = numberToString( power, copyString( p, "^" ) );
++ numFactors;
}
if ( n > 1 ) {
if ( !numFactors )
copyString( p, tracker().failedTests() ? " :(" : tracker().warnings() ? " :|" : " :)" );
else
numberToString( n, copyString( p, " * " ) );
}
return s;
}
#endif // _CXXTEST_FACTOR
}
#endif // __cxxtest__Descriptions_cpp__

View File

@@ -0,0 +1,73 @@
#ifndef __cxxtest__Descriptions_h__
#define __cxxtest__Descriptions_h__
//
// TestDescription, SuiteDescription and WorldDescription
// hold information about tests so they can be run and reported.
//
#include <cxxtest/LinkedList.h>
namespace CxxTest
{
class TestSuite;
class TestDescription : public Link
{
public:
virtual ~TestDescription();
virtual const char *file() const = 0;
virtual unsigned line() const = 0;
virtual const char *testName() const = 0;
virtual const char *suiteName() const = 0;
virtual void run() = 0;
virtual const TestDescription *next() const = 0;
virtual TestDescription *next() = 0;
};
class SuiteDescription : public Link
{
public:
virtual ~SuiteDescription();
virtual const char *file() const = 0;
virtual unsigned line() const = 0;
virtual const char *suiteName() const = 0;
virtual TestSuite *suite() const = 0;
virtual unsigned numTests() const = 0;
virtual const TestDescription &testDescription( unsigned /*i*/ ) const = 0;
virtual TestDescription *firstTest() = 0;
virtual const TestDescription *firstTest() const = 0;
virtual SuiteDescription *next() = 0;
virtual const SuiteDescription *next() const = 0;
virtual void activateAllTests() = 0;
virtual bool leaveOnly( const char * /*testName*/ ) = 0;
};
class WorldDescription : public Link
{
public:
virtual ~WorldDescription();
virtual unsigned numSuites( void ) const = 0;
virtual unsigned numTotalTests( void ) const = 0;
virtual const SuiteDescription &suiteDescription( unsigned /*i*/ ) const = 0;
enum { MAX_STRLEN_TOTAL_TESTS = 32 };
char *strTotalTests( char * /*buffer*/ ) const;
virtual SuiteDescription *firstSuite() = 0;
virtual const SuiteDescription *firstSuite() const = 0;
virtual void activateAllTests() = 0;
virtual bool leaveOnly( const char * /*suiteName*/, const char * /*testName*/ = 0 ) = 0;
};
}
#endif // __cxxtest__Descriptions_h__

View File

@@ -0,0 +1,48 @@
#include <cxxtest/DummyDescriptions.h>
namespace CxxTest
{
DummyTestDescription::DummyTestDescription() {}
const char *DummyTestDescription::file() const { return "<no file>"; }
unsigned DummyTestDescription::line() const { return 0; }
const char *DummyTestDescription::testName() const { return "<no test>"; }
const char *DummyTestDescription::suiteName() const { return "<no suite>"; }
bool DummyTestDescription::setUp() { return true;}
void DummyTestDescription::run() {}
bool DummyTestDescription::tearDown() { return true;}
TestDescription *DummyTestDescription::next() { return 0; }
const TestDescription *DummyTestDescription::next() const { return 0; }
DummySuiteDescription::DummySuiteDescription() : _test() {}
const char *DummySuiteDescription::file() const { return "<no file>"; }
unsigned DummySuiteDescription::line() const { return 0; }
const char *DummySuiteDescription::suiteName() const { return "<no suite>"; }
TestSuite *DummySuiteDescription::suite() const { return 0; }
unsigned DummySuiteDescription::numTests() const { return 0; }
const TestDescription &DummySuiteDescription::testDescription( unsigned ) const { return _test; }
SuiteDescription *DummySuiteDescription::next() { return 0; }
TestDescription *DummySuiteDescription::firstTest() { return 0; }
const SuiteDescription *DummySuiteDescription::next() const { return 0; }
const TestDescription *DummySuiteDescription::firstTest() const { return 0; }
void DummySuiteDescription::activateAllTests() {}
bool DummySuiteDescription::leaveOnly( const char * /*testName*/ ) { return false; }
bool DummySuiteDescription::setUp() { return true;}
bool DummySuiteDescription::tearDown() { return true;}
DummyWorldDescription::DummyWorldDescription() : _suite() {}
unsigned DummyWorldDescription::numSuites( void ) const { return 0; }
unsigned DummyWorldDescription::numTotalTests( void ) const { return 0; }
const SuiteDescription &DummyWorldDescription::suiteDescription( unsigned ) const { return _suite; }
SuiteDescription *DummyWorldDescription::firstSuite() { return 0; }
const SuiteDescription *DummyWorldDescription::firstSuite() const { return 0; }
void DummyWorldDescription::activateAllTests() {}
bool DummyWorldDescription::leaveOnly( const char * /*suiteName*/, const char * /*testName*/ ) { return false; }
bool DummyWorldDescription::setUp() { return true;}
bool DummyWorldDescription::tearDown() { return true;}
}

View File

@@ -0,0 +1,75 @@
#ifndef __cxxtest__DummyDescriptions_h__
#define __cxxtest__DummyDescriptions_h__
//
// DummyTestDescription, DummySuiteDescription and DummyWorldDescription
//
#include <cxxtest/Descriptions.h>
namespace CxxTest
{
class DummyTestDescription : public TestDescription
{
public:
DummyTestDescription();
const char *file() const;
unsigned line() const;
const char *testName() const;
const char *suiteName() const;
bool setUp();
void run();
bool tearDown();
TestDescription *next();
const TestDescription *next() const;
};
class DummySuiteDescription : public SuiteDescription
{
public:
DummySuiteDescription();
const char *file() const;
unsigned line() const;
const char *suiteName() const;
TestSuite *suite() const;
unsigned numTests() const;
const TestDescription &testDescription( unsigned ) const;
SuiteDescription *next();
TestDescription *firstTest();
const SuiteDescription *next() const;
const TestDescription *firstTest() const;
void activateAllTests();
bool leaveOnly( const char * /*testName*/ );
bool setUp();
bool tearDown();
private:
DummyTestDescription _test;
};
class DummyWorldDescription : public WorldDescription
{
public:
DummyWorldDescription();
unsigned numSuites( void ) const;
unsigned numTotalTests( void ) const;
const SuiteDescription &suiteDescription( unsigned ) const;
SuiteDescription *firstSuite();
const SuiteDescription *firstSuite() const;
void activateAllTests();
bool leaveOnly( const char * /*suiteName*/, const char * /*testName*/ = 0 );
bool setUp();
bool tearDown();
private:
DummySuiteDescription _suite;
};
}
#endif // __cxxtest__DummyDescriptions_h__

View File

@@ -0,0 +1,281 @@
#ifndef __cxxtest__ErrorFormatter_h__
#define __cxxtest__ErrorFormatter_h__
//
// The ErrorFormatter is a TestListener that
// prints reports of the errors to an output
// stream. Since we cannot rely ou the standard
// iostreams, this header defines a base class
// analogout to std::ostream.
//
#include <cxxtest/TestRunner.h>
#include <cxxtest/TestListener.h>
#include <cxxtest/TestTracker.h>
#include <cxxtest/ValueTraits.h>
namespace CxxTest
{
class OutputStream
{
public:
virtual ~OutputStream() {}
virtual void flush() {}
virtual OutputStream &operator<<( unsigned /*number*/ ) { return *this; }
virtual OutputStream &operator<<( const char * /*string*/ ) { return *this; }
typedef void (*Manipulator)( OutputStream & );
virtual OutputStream &operator<<( Manipulator m ) { m( *this ); return *this; }
static void endl( OutputStream &o ) { (o << "\n").flush(); }
};
class ErrorFormatter : public TestListener
{
public:
ErrorFormatter( OutputStream *o, const char *preLine = ":", const char *postLine = "" ) :
_dotting( true ),
_reported( false ),
_o(o),
_preLine(preLine),
_postLine(postLine)
{
}
int run()
{
TestRunner::runAllTests( *this );
return tracker().failedTests();
}
void enterWorld( const WorldDescription & /*desc*/ )
{
(*_o) << "Running " << totalTests;
_o->flush();
_dotting = true;
_reported = false;
}
static void totalTests( OutputStream &o )
{
char s[WorldDescription::MAX_STRLEN_TOTAL_TESTS];
const WorldDescription &wd = tracker().world();
o << wd.strTotalTests( s ) << (wd.numTotalTests() == 1 ? " test" : " tests");
}
void enterSuite( const SuiteDescription & )
{
_reported = false;
}
void enterTest( const TestDescription & )
{
_reported = false;
}
void leaveTest( const TestDescription & )
{
if ( !tracker().testFailed() ) {
((*_o) << ".").flush();
_dotting = true;
}
}
void leaveWorld( const WorldDescription &desc )
{
if ( !tracker().failedTests() ) {
(*_o) << "OK!" << endl;
return;
}
newLine();
(*_o) << "Failed " << tracker().failedTests() << " of " << totalTests << endl;
unsigned numPassed = desc.numTotalTests() - tracker().failedTests();
(*_o) << "Success rate: " << (numPassed * 100 / desc.numTotalTests()) << "%" << endl;
}
void trace( const char *file, unsigned line, const char *expression )
{
stop( file, line ) << "Trace: " <<
expression << endl;
}
void warning( const char *file, unsigned line, const char *expression )
{
stop( file, line ) << "Warning: " <<
expression << endl;
}
void failedTest( const char *file, unsigned line, const char *expression )
{
stop( file, line ) << "Error: Test failed: " <<
expression << endl;
}
void failedAssert( const char *file, unsigned line, const char *expression )
{
stop( file, line ) << "Error: Assertion failed: " <<
expression << endl;
}
void failedAssertEquals( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
stop( file, line ) << "Error: Expected (" <<
xStr << " == " << yStr << "), found (" <<
x << " != " << y << ")" << endl;
}
void failedAssertSameData( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *sizeStr, const void *x,
const void *y, unsigned size )
{
stop( file, line ) << "Error: Expected " << sizeStr << " (" << size << ") bytes to be equal at (" <<
xStr << ") and (" << yStr << "), found:" << endl;
dump( x, size );
(*_o) << " differs from" << endl;
dump( y, size );
}
void failedAssertDelta( const char *file, unsigned line,
const char *xStr, const char *yStr, const char *dStr,
const char *x, const char *y, const char *d )
{
stop( file, line ) << "Error: Expected (" <<
xStr << " == " << yStr << ") up to " << dStr << " (" << d << "), found (" <<
x << " != " << y << ")" << endl;
}
void failedAssertDiffers( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *value )
{
stop( file, line ) << "Error: Expected (" <<
xStr << " != " << yStr << "), found (" <<
value << ")" << endl;
}
void failedAssertLessThan( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
stop( file, line ) << "Error: Expected (" <<
xStr << " < " << yStr << "), found (" <<
x << " >= " << y << ")" << endl;
}
void failedAssertLessThanEquals( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
stop( file, line ) << "Error: Expected (" <<
xStr << " <= " << yStr << "), found (" <<
x << " > " << y << ")" << endl;
}
void failedAssertRelation( const char *file, unsigned line,
const char *relation, const char *xStr, const char *yStr,
const char *x, const char *y )
{
stop( file, line ) << "Error: Expected " << relation << "( " <<
xStr << ", " << yStr << " ), found !" << relation << "( " << x << ", " << y << " )" << endl;
}
void failedAssertPredicate( const char *file, unsigned line,
const char *predicate, const char *xStr, const char *x )
{
stop( file, line ) << "Error: Expected " << predicate << "( " <<
xStr << " ), found !" << predicate << "( " << x << " )" << endl;
}
void failedAssertThrows( const char *file, unsigned line,
const char *expression, const char *type,
bool otherThrown )
{
stop( file, line ) << "Error: Expected (" << expression << ") to throw (" <<
type << ") but it " << (otherThrown ? "threw something else" : "didn't throw") <<
endl;
}
void failedAssertThrowsNot( const char *file, unsigned line, const char *expression )
{
stop( file, line ) << "Error: Expected (" << expression << ") not to throw, but it did" <<
endl;
}
protected:
OutputStream *outputStream() const
{
return _o;
}
private:
ErrorFormatter( const ErrorFormatter & );
ErrorFormatter &operator=( const ErrorFormatter & );
OutputStream &stop( const char *file, unsigned line )
{
newLine();
reportTest();
return (*_o) << file << _preLine << line << _postLine << ": ";
}
void newLine( void )
{
if ( _dotting ) {
(*_o) << endl;
_dotting = false;
}
}
void reportTest( void )
{
if( _reported )
return;
(*_o) << "In " << tracker().suite().suiteName() << "::" << tracker().test().testName() << ":" << endl;
_reported = true;
}
void dump( const void *buffer, unsigned size )
{
if ( !buffer )
dumpNull();
else
dumpBuffer( buffer, size );
}
void dumpNull()
{
(*_o) << " (null)" << endl;
}
void dumpBuffer( const void *buffer, unsigned size )
{
unsigned dumpSize = size;
if ( maxDumpSize() && dumpSize > maxDumpSize() )
dumpSize = maxDumpSize();
const unsigned char *p = (const unsigned char *)buffer;
(*_o) << " { ";
for ( unsigned i = 0; i < dumpSize; ++ i )
(*_o) << byteToHex( *p++ ) << " ";
if ( dumpSize < size )
(*_o) << "... ";
(*_o) << "}" << endl;
}
static void endl( OutputStream &o )
{
OutputStream::endl( o );
}
bool _dotting;
bool _reported;
OutputStream *_o;
const char *_preLine;
const char *_postLine;
};
}
#endif // __cxxtest__ErrorFormatter_h__

View File

@@ -0,0 +1,55 @@
#ifndef __cxxtest__ErrorPrinter_h__
#define __cxxtest__ErrorPrinter_h__
//
// The ErrorPrinter is a simple TestListener that
// just prints "OK" if everything goes well, otherwise
// reports the error in the format of compiler messages.
// The ErrorPrinter uses std::cout
//
#include <cxxtest/Flags.h>
#ifndef _CXXTEST_HAVE_STD
# define _CXXTEST_HAVE_STD
#endif // _CXXTEST_HAVE_STD
#include <cxxtest/ErrorFormatter.h>
#include <cxxtest/StdValueTraits.h>
#ifdef _CXXTEST_OLD_STD
# include <iostream.h>
#else // !_CXXTEST_OLD_STD
# include <iostream>
#endif // _CXXTEST_OLD_STD
namespace CxxTest
{
class ErrorPrinter : public ErrorFormatter
{
public:
ErrorPrinter( CXXTEST_STD(ostream) &o = CXXTEST_STD(cout), const char *preLine = ":", const char *postLine = "" ) :
ErrorFormatter( new Adapter(o), preLine, postLine ) {}
virtual ~ErrorPrinter() { delete outputStream(); }
private:
class Adapter : public OutputStream
{
CXXTEST_STD(ostream) &_o;
public:
Adapter( CXXTEST_STD(ostream) &o ) : _o(o) {}
void flush() { _o.flush(); }
OutputStream &operator<<( const char *s ) { _o << s; return *this; }
OutputStream &operator<<( Manipulator m ) { return OutputStream::operator<<( m ); }
OutputStream &operator<<( unsigned i )
{
char s[1 + 3 * sizeof(unsigned)];
numberToString( i, s );
_o << s;
return *this;
}
};
};
}
#endif // __cxxtest__ErrorPrinter_h__

View File

@@ -0,0 +1,121 @@
#ifndef __cxxtest__Flags_h__
#define __cxxtest__Flags_h__
//
// These are the flags that control CxxTest
//
#if !defined(CXXTEST_FLAGS)
# define CXXTEST_FLAGS
#endif // !CXXTEST_FLAGS
#if defined(CXXTEST_HAVE_EH) && !defined(_CXXTEST_HAVE_EH)
# define _CXXTEST_HAVE_EH
#endif // CXXTEST_HAVE_EH
#if defined(CXXTEST_HAVE_STD) && !defined(_CXXTEST_HAVE_STD)
# define _CXXTEST_HAVE_STD
#endif // CXXTEST_HAVE_STD
#if defined(CXXTEST_OLD_TEMPLATE_SYNTAX) && !defined(_CXXTEST_OLD_TEMPLATE_SYNTAX)
# define _CXXTEST_OLD_TEMPLATE_SYNTAX
#endif // CXXTEST_OLD_TEMPLATE_SYNTAX
#if defined(CXXTEST_OLD_STD) && !defined(_CXXTEST_OLD_STD)
# define _CXXTEST_OLD_STD
#endif // CXXTEST_OLD_STD
#if defined(CXXTEST_ABORT_TEST_ON_FAIL) && !defined(_CXXTEST_ABORT_TEST_ON_FAIL)
# define _CXXTEST_ABORT_TEST_ON_FAIL
#endif // CXXTEST_ABORT_TEST_ON_FAIL
#if defined(CXXTEST_NO_COPY_CONST) && !defined(_CXXTEST_NO_COPY_CONST)
# define _CXXTEST_NO_COPY_CONST
#endif // CXXTEST_NO_COPY_CONST
#if defined(CXXTEST_FACTOR) && !defined(_CXXTEST_FACTOR)
# define _CXXTEST_FACTOR
#endif // CXXTEST_FACTOR
#if defined(CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION) && !defined(_CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION)
# define _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
#endif // CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
#if defined(CXXTEST_LONGLONG)
# if defined(_CXXTEST_LONGLONG)
# undef _CXXTEST_LONGLONG
# endif
# define _CXXTEST_LONGLONG CXXTEST_LONGLONG
#endif // CXXTEST_LONGLONG
#ifndef CXXTEST_MAX_DUMP_SIZE
# define CXXTEST_MAX_DUMP_SIZE 0
#endif // CXXTEST_MAX_DUMP_SIZE
#if defined(_CXXTEST_ABORT_TEST_ON_FAIL) && !defined(CXXTEST_DEFAULT_ABORT)
# define CXXTEST_DEFAULT_ABORT true
#endif // _CXXTEST_ABORT_TEST_ON_FAIL && !CXXTEST_DEFAULT_ABORT
#if !defined(CXXTEST_DEFAULT_ABORT)
# define CXXTEST_DEFAULT_ABORT false
#endif // !CXXTEST_DEFAULT_ABORT
#if defined(_CXXTEST_ABORT_TEST_ON_FAIL) && !defined(_CXXTEST_HAVE_EH)
# warning "CXXTEST_ABORT_TEST_ON_FAIL is meaningless without CXXTEST_HAVE_EH"
# undef _CXXTEST_ABORT_TEST_ON_FAIL
#endif // _CXXTEST_ABORT_TEST_ON_FAIL && !_CXXTEST_HAVE_EH
//
// Some minimal per-compiler configuration to allow us to compile
//
#ifdef __BORLANDC__
# if __BORLANDC__ <= 0x520 // Borland C++ 5.2 or earlier
# ifndef _CXXTEST_OLD_STD
# define _CXXTEST_OLD_STD
# endif
# ifndef _CXXTEST_OLD_TEMPLATE_SYNTAX
# define _CXXTEST_OLD_TEMPLATE_SYNTAX
# endif
# endif
# if __BORLANDC__ >= 0x540 // C++ Builder 4.0 or later
# ifndef _CXXTEST_NO_COPY_CONST
# define _CXXTEST_NO_COPY_CONST
# endif
# ifndef _CXXTEST_LONGLONG
# define _CXXTEST_LONGLONG __int64
# endif
# endif
#endif // __BORLANDC__
#ifdef _MSC_VER // Visual C++
# ifndef _CXXTEST_LONGLONG
# define _CXXTEST_LONGLONG __int64
# endif
# if (_MSC_VER >= 0x51E)
# ifndef _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
# define _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
# endif
# endif
# pragma warning( disable : 4127 )
# pragma warning( disable : 4290 )
# pragma warning( disable : 4511 )
# pragma warning( disable : 4512 )
# pragma warning( disable : 4514 )
#endif // _MSC_VER
#ifdef __GNUC__
# if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 9)
# ifndef _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
# define _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
# endif
# endif
#endif // __GNUC__
#ifdef __DMC__ // Digital Mars
# ifndef _CXXTEST_OLD_STD
# define _CXXTEST_OLD_STD
# endif
#endif
#endif // __cxxtest__Flags_h__

View File

@@ -0,0 +1,22 @@
#ifndef __cxxtest__GlobalFixture_cpp__
#define __cxxtest__GlobalFixture_cpp__
#include <cxxtest/GlobalFixture.h>
namespace CxxTest
{
bool GlobalFixture::setUpWorld() { return true; }
bool GlobalFixture::tearDownWorld() { return true; }
bool GlobalFixture::setUp() { return true; }
bool GlobalFixture::tearDown() { return true; }
GlobalFixture::GlobalFixture() { attach( _list ); }
GlobalFixture::~GlobalFixture() { detach( _list ); }
GlobalFixture *GlobalFixture::firstGlobalFixture() { return (GlobalFixture *)_list.head(); }
GlobalFixture *GlobalFixture::lastGlobalFixture() { return (GlobalFixture *)_list.tail(); }
GlobalFixture *GlobalFixture::nextGlobalFixture() { return (GlobalFixture *)next(); }
GlobalFixture *GlobalFixture::prevGlobalFixture() { return (GlobalFixture *)prev(); }
}
#endif // __cxxtest__GlobalFixture_cpp__

View File

@@ -0,0 +1,29 @@
#ifndef __cxxtest__GlobalFixture_h__
#define __cxxtest__GlobalFixture_h__
#include <cxxtest/LinkedList.h>
namespace CxxTest
{
class GlobalFixture : public Link
{
public:
virtual bool setUpWorld();
virtual bool tearDownWorld();
virtual bool setUp();
virtual bool tearDown();
GlobalFixture();
~GlobalFixture();
static GlobalFixture *firstGlobalFixture();
static GlobalFixture *lastGlobalFixture();
GlobalFixture *nextGlobalFixture();
GlobalFixture *prevGlobalFixture();
private:
static List _list;
};
}
#endif // __cxxtest__GlobalFixture_h__

178
test/cxxtest/cxxtest/Gui.h Normal file
View File

@@ -0,0 +1,178 @@
#ifndef __CXXTEST__GUI_H
#define __CXXTEST__GUI_H
//
// GuiListener is a simple base class for the differes GUIs
// GuiTuiRunner<GuiT, TuiT> combines a GUI with a text-mode error formatter
//
#include <cxxtest/TeeListener.h>
namespace CxxTest
{
class GuiListener : public TestListener
{
public:
GuiListener() : _state( GREEN_BAR ) {}
virtual ~GuiListener() {}
virtual void runGui( int &argc, char **argv, TestListener &listener )
{
enterGui( argc, argv );
TestRunner::runAllTests( listener );
leaveGui();
}
virtual void enterGui( int & /*argc*/, char ** /*argv*/ ) {}
virtual void leaveGui() {}
//
// The easy way is to implement these functions:
//
virtual void guiEnterWorld( unsigned /*numTotalTests*/ ) {}
virtual void guiEnterSuite( const char * /*suiteName*/ ) {}
virtual void guiEnterTest( const char * /*suiteName*/, const char * /*testName*/ ) {}
virtual void yellowBar() {}
virtual void redBar() {}
//
// The hard way is this:
//
void enterWorld( const WorldDescription &d ) { guiEnterWorld( d.numTotalTests() ); }
void enterSuite( const SuiteDescription &d ) { guiEnterSuite( d.suiteName() ); }
void enterTest( const TestDescription &d ) { guiEnterTest( d.suiteName(), d.testName() ); }
void leaveTest( const TestDescription & ) {}
void leaveSuite( const SuiteDescription & ) {}
void leaveWorld( const WorldDescription & ) {}
void warning( const char * /*file*/, unsigned /*line*/, const char * /*expression*/ )
{
yellowBarSafe();
}
void failedTest( const char * /*file*/, unsigned /*line*/, const char * /*expression*/ )
{
redBarSafe();
}
void failedAssert( const char * /*file*/, unsigned /*line*/, const char * /*expression*/ )
{
redBarSafe();
}
void failedAssertEquals( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*x*/, const char * /*y*/ )
{
redBarSafe();
}
void failedAssertSameData( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*sizeStr*/, const void * /*x*/,
const void * /*y*/, unsigned /*size*/ )
{
redBarSafe();
}
void failedAssertDelta( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/, const char * /*dStr*/,
const char * /*x*/, const char * /*y*/, const char * /*d*/ )
{
redBarSafe();
}
void failedAssertDiffers( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*value*/ )
{
redBarSafe();
}
void failedAssertLessThan( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*x*/, const char * /*y*/ )
{
redBarSafe();
}
void failedAssertLessThanEquals( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*x*/, const char * /*y*/ )
{
redBarSafe();
}
void failedAssertPredicate( const char * /*file*/, unsigned /*line*/,
const char * /*predicate*/, const char * /*xStr*/, const char * /*x*/ )
{
redBarSafe();
}
void failedAssertRelation( const char * /*file*/, unsigned /*line*/,
const char * /*relation*/, const char * /*xStr*/, const char * /*yStr*/,
const char * /*x*/, const char * /*y*/ )
{
redBarSafe();
}
void failedAssertThrows( const char * /*file*/, unsigned /*line*/,
const char * /*expression*/, const char * /*type*/,
bool /*otherThrown*/ )
{
redBarSafe();
}
void failedAssertThrowsNot( const char * /*file*/, unsigned /*line*/,
const char * /*expression*/ )
{
redBarSafe();
}
protected:
void yellowBarSafe()
{
if ( _state < YELLOW_BAR ) {
yellowBar();
_state = YELLOW_BAR;
}
}
void redBarSafe()
{
if ( _state < RED_BAR ) {
redBar();
_state = RED_BAR;
}
}
private:
enum { GREEN_BAR, YELLOW_BAR, RED_BAR } _state;
};
template<class GuiT, class TuiT>
class GuiTuiRunner : public TeeListener
{
int &_argc;
char **_argv;
GuiT _gui;
TuiT _tui;
public:
GuiTuiRunner( int &argc, char **argv ) :
_argc( argc ),
_argv( argv )
{
setFirst( _gui );
setSecond( _tui );
}
int run()
{
_gui.runGui( _argc, _argv, *this );
return tracker().failedTests();
}
};
}
#endif //__CXXTEST__GUI_H

View File

@@ -0,0 +1,172 @@
#ifndef __cxxtest__LinkedList_cpp__
#define __cxxtest__LinkedList_cpp__
#include <cxxtest/LinkedList.h>
namespace CxxTest
{
List GlobalFixture::_list = { 0, 0 };
List RealSuiteDescription::_suites = { 0, 0 };
void List::initialize()
{
_head = _tail = 0;
}
Link *List::head()
{
Link *l = _head;
while ( l && !l->active() )
l = l->next();
return l;
}
const Link *List::head() const
{
Link *l = _head;
while ( l && !l->active() )
l = l->next();
return l;
}
Link *List::tail()
{
Link *l = _tail;
while ( l && !l->active() )
l = l->prev();
return l;
}
const Link *List::tail() const
{
Link *l = _tail;
while ( l && !l->active() )
l = l->prev();
return l;
}
bool List::empty() const
{
return (_head == 0);
}
unsigned List::size() const
{
unsigned count = 0;
for ( const Link *l = head(); l != 0; l = l->next() )
++ count;
return count;
}
Link *List::nth( unsigned n )
{
Link *l = head();
while ( n -- )
l = l->next();
return l;
}
void List::activateAll()
{
for ( Link *l = _head; l != 0; l = l->justNext() )
l->setActive( true );
}
void List::leaveOnly( const Link &link )
{
for ( Link *l = head(); l != 0; l = l->next() )
if ( l != &link )
l->setActive( false );
}
Link::Link() :
_next( 0 ),
_prev( 0 ),
_active( true )
{
}
Link::~Link()
{
}
bool Link::active() const
{
return _active;
}
void Link::setActive( bool value )
{
_active = value;
}
Link * Link::justNext()
{
return _next;
}
Link * Link::justPrev()
{
return _prev;
}
Link * Link::next()
{
Link *l = _next;
while ( l && !l->_active )
l = l->_next;
return l;
}
Link * Link::prev()
{
Link *l = _prev;
while ( l && !l->_active )
l = l->_prev;
return l;
}
const Link * Link::next() const
{
Link *l = _next;
while ( l && !l->_active )
l = l->_next;
return l;
}
const Link * Link::prev() const
{
Link *l = _prev;
while ( l && !l->_active )
l = l->_prev;
return l;
}
void Link::attach( List &l )
{
if ( l._tail )
l._tail->_next = this;
_prev = l._tail;
_next = 0;
if ( l._head == 0 )
l._head = this;
l._tail = this;
}
void Link::detach( List &l )
{
if ( _prev )
_prev->_next = _next;
else
l._head = _next;
if ( _next )
_next->_prev = _prev;
else
l._tail = _prev;
}
}
#endif // __cxxtest__LinkedList_cpp__

View File

@@ -0,0 +1,64 @@
#ifndef __cxxtest__LinkedList_h__
#define __cxxtest__LinkedList_h__
#include <cxxtest/Flags.h>
namespace CxxTest
{
struct List;
class Link;
struct List
{
Link *_head;
Link *_tail;
void initialize();
Link *head();
const Link *head() const;
Link *tail();
const Link *tail() const;
bool empty() const;
unsigned size() const;
Link *nth( unsigned n );
void activateAll();
void leaveOnly( const Link &link );
};
class Link
{
public:
Link();
virtual ~Link();
bool active() const;
void setActive( bool value = true );
Link *justNext();
Link *justPrev();
Link *next();
Link *prev();
const Link *next() const;
const Link *prev() const;
virtual bool setUp() = 0;
virtual bool tearDown() = 0;
void attach( List &l );
void detach( List &l );
private:
Link *_next;
Link *_prev;
bool _active;
Link( const Link & );
Link &operator=( const Link & );
};
}
#endif // __cxxtest__LinkedList_h__

350
test/cxxtest/cxxtest/Mock.h Normal file
View File

@@ -0,0 +1,350 @@
#ifndef __cxxtest__Mock_h__
#define __cxxtest__Mock_h__
//
// The default namespace is T::
//
#ifndef CXXTEST_MOCK_NAMESPACE
# define CXXTEST_MOCK_NAMESPACE T
#endif // CXXTEST_MOCK_NAMESPACE
//
// MockTraits: What to return when no mock object has been created
//
#define __CXXTEST_MOCK__TRAITS \
namespace CXXTEST_MOCK_NAMESPACE \
{ \
template<class T> \
class MockTraits \
{ \
public: \
static T defaultValue() { return 0; } \
}; \
};
//
// extern "C" when needed
//
#ifdef __cplusplus
# define CXXTEST_EXTERN_C extern "C"
#else
# define CXXTEST_EXTERN_C
#endif // __cplusplus
//
// Prototypes: For "normal" headers
//
#define __CXXTEST_MOCK__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
namespace CXXTEST_MOCK_NAMESPACE { TYPE NAME ARGS; }
#define __CXXTEST_MOCK_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__PROTOTYPE( MOCK, void, NAME, ARGS, REAL, CALL )
#define __CXXTEST_SUPPLY__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
TYPE REAL ARGS;
#define __CXXTEST_SUPPLY_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY__PROTOTYPE( MOCK, void, NAME, ARGS, REAL, CALL )
//
// Class declarations: For test files
//
#define __CXXTEST_MOCK__CLASS_DECLARATION( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
namespace CXXTEST_MOCK_NAMESPACE { \
class Base_##MOCK : public CxxTest::Link \
{ \
public: \
Base_##MOCK(); \
~Base_##MOCK(); \
bool setUp(); \
bool tearDown(); \
\
static Base_##MOCK &current(); \
\
virtual TYPE NAME ARGS = 0; \
\
private: \
static CxxTest::List _list; \
}; \
\
class Real_##MOCK : public Base_##MOCK \
{ \
public: \
TYPE NAME ARGS; \
}; \
\
class _Unimplemented_##MOCK : public Base_##MOCK \
{ \
public: \
TYPE NAME ARGS; \
}; \
}
#define __CXXTEST_MOCK_VOID__CLASS_DECLARATION( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__CLASS_DECLARATION( MOCK, void, NAME, ARGS, REAL, CALL )
#define __CXXTEST_SUPPLY__CLASS_DECLARATION( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
namespace CXXTEST_MOCK_NAMESPACE { \
class Base_##MOCK : public CxxTest::Link \
{ \
public: \
Base_##MOCK(); \
~Base_##MOCK(); \
bool setUp(); \
bool tearDown(); \
\
static Base_##MOCK &current(); \
\
virtual TYPE NAME ARGS = 0; \
\
private: \
static CxxTest::List _list; \
}; \
\
class _Unimplemented_##MOCK : public Base_##MOCK \
{ \
public: \
TYPE NAME ARGS; \
}; \
}
#define __CXXTEST_SUPPLY_VOID__CLASS_DECLARATION( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY__CLASS_DECLARATION( MOCK, void, NAME, ARGS, REAL, CALL )
//
// Class implementation: For test source files
//
#define __CXXTEST_MOCK__COMMON_CLASS_IMPLEMENTATION( MOCK, NAME ) \
namespace CXXTEST_MOCK_NAMESPACE { \
\
CxxTest::List Base_##MOCK::_list = { 0, 0 }; \
\
Base_##MOCK::Base_##MOCK() { attach( _list ); } \
Base_##MOCK::~Base_##MOCK() { detach( _list ); } \
bool Base_##MOCK::setUp() { return true; } \
bool Base_##MOCK::tearDown() { return true; } \
\
Base_##MOCK &Base_##MOCK::current() \
{ \
if ( _list.empty() ) \
static _Unimplemented_##MOCK unimplemented; \
return *(Base_##MOCK *)_list.tail(); \
} \
}
#define __CXXTEST_MOCK__CLASS_IMPLEMENTATION( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__COMMON_CLASS_IMPLEMENTATION( MOCK, NAME ) \
namespace CXXTEST_MOCK_NAMESPACE { \
TYPE Real_##MOCK::NAME ARGS \
{ \
return REAL CALL; \
} \
\
TYPE _Unimplemented_##MOCK::NAME ARGS \
{ \
while ( false ) \
return NAME CALL; \
__CXXTEST_MOCK_UNIMPLEMENTED( NAME, ARGS ); \
return MockTraits<TYPE>::defaultValue(); \
} \
\
TYPE NAME ARGS \
{ \
return Base_##MOCK::current().NAME CALL; \
} \
}
#define __CXXTEST_MOCK_VOID__CLASS_IMPLEMENTATION( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__COMMON_CLASS_IMPLEMENTATION( MOCK, NAME ) \
namespace CXXTEST_MOCK_NAMESPACE { \
void Real_##MOCK::NAME ARGS \
{ \
REAL CALL; \
} \
\
void _Unimplemented_##MOCK::NAME ARGS \
{ \
while ( false ) \
NAME CALL; \
__CXXTEST_MOCK_UNIMPLEMENTED( NAME, ARGS ); \
} \
\
void NAME ARGS \
{ \
Base_##MOCK::current().NAME CALL; \
} \
}
#define __CXXTEST_SUPPLY__CLASS_IMPLEMENTATION( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__COMMON_CLASS_IMPLEMENTATION( MOCK, NAME ) \
namespace CXXTEST_MOCK_NAMESPACE { \
TYPE _Unimplemented_##MOCK::NAME ARGS \
{ \
while ( false ) \
return NAME CALL; \
__CXXTEST_MOCK_UNIMPLEMENTED( NAME, ARGS ); \
return MockTraits<TYPE>::defaultValue(); \
} \
} \
\
TYPE REAL ARGS \
{ \
return CXXTEST_MOCK_NAMESPACE::Base_##MOCK::current().NAME CALL; \
}
#define __CXXTEST_SUPPLY_VOID__CLASS_IMPLEMENTATION( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__COMMON_CLASS_IMPLEMENTATION( MOCK, NAME ) \
namespace CXXTEST_MOCK_NAMESPACE { \
void _Unimplemented_##MOCK::NAME ARGS \
{ \
while ( false ) \
NAME CALL; \
__CXXTEST_MOCK_UNIMPLEMENTED( NAME, ARGS ); \
} \
} \
\
void REAL ARGS \
{ \
CXXTEST_MOCK_NAMESPACE::Base_##MOCK::current().NAME CALL; \
} \
//
// Error for calling mock function w/o object
//
#define __CXXTEST_MOCK_UNIMPLEMENTED( NAME, ARGS ) \
TS_FAIL( CXXTEST_MOCK_NAMESPACE_STR #NAME #ARGS " called with no " \
CXXTEST_MOCK_NAMESPACE_STR "Base_" #NAME " object" ); \
#define CXXTEST_MOCK_NAMESPACE_STR __CXXTEST_STR(CXXTEST_MOCK_NAMESPACE) "::"
#define __CXXTEST_STR(X) __CXXTEST_XSTR(X)
#define __CXXTEST_XSTR(X) #X
#if defined(CXXTEST_MOCK_TEST_SOURCE_FILE)
//
// Test source file: Prototypes, class declarations and implementation
//
#include <cxxtest/TestSuite.h>
__CXXTEST_MOCK__TRAITS;
#define CXXTEST_MOCK( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__CLASS_DECLARATION( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__CLASS_IMPLEMENTATION( MOCK, TYPE, NAME, ARGS, REAL, CALL )
#define CXXTEST_MOCK_VOID( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK_VOID__CLASS_DECLARATION( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK_VOID__CLASS_IMPLEMENTATION( MOCK, NAME, ARGS, REAL, CALL )
#define CXXTEST_SUPPLY( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY__CLASS_DECLARATION( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY__CLASS_IMPLEMENTATION( MOCK, TYPE, NAME, ARGS, REAL, CALL )
#define CXXTEST_SUPPLY_VOID( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY_VOID__CLASS_DECLARATION( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY_VOID__CLASS_IMPLEMENTATION( MOCK, NAME, ARGS, REAL, CALL )
#elif defined(CXXTEST_FLAGS) || defined(CXXTEST_RUNNING)
//
// Test file other than source: Prototypes and class declarations
//
#include <cxxtest/TestSuite.h>
__CXXTEST_MOCK__TRAITS;
#define CXXTEST_MOCK( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__CLASS_DECLARATION( MOCK, TYPE, NAME, ARGS, REAL, CALL )
#define CXXTEST_MOCK_VOID( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK_VOID__CLASS_DECLARATION( MOCK, NAME, ARGS, REAL, CALL )
#define CXXTEST_SUPPLY( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY__CLASS_DECLARATION( MOCK, TYPE, NAME, ARGS, REAL, CALL )
#define CXXTEST_SUPPLY_VOID( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY_VOID__CLASS_DECLARATION( MOCK, NAME, ARGS, REAL, CALL )
#elif defined(CXXTEST_MOCK_REAL_SOURCE_FILE)
//
// Real source file: "Real" implementations
//
#define CXXTEST_MOCK( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
namespace CXXTEST_MOCK_NAMESPACE { TYPE NAME ARGS { return REAL CALL; } }
#define CXXTEST_MOCK_VOID( MOCK, NAME, ARGS, REAL, CALL ) \
namespace CXXTEST_MOCK_NAMESPACE { void NAME ARGS { REAL CALL; } }
#else
//
// Ordinary header file: Just prototypes
//
#define CXXTEST_MOCK( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL )
#define CXXTEST_MOCK_VOID( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_MOCK_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL )
#define CXXTEST_SUPPLY( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL )
#define CXXTEST_SUPPLY_VOID( MOCK, NAME, ARGS, REAL, CALL ) \
__CXXTEST_SUPPLY_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL )
#endif // Ordinary header file
//
// How to supply extern "C" functions
//
#define CXXTEST_SUPPLY_C( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
CXXTEST_EXTERN_C __CXXTEST_SUPPLY__PROTOTYPE( MOCK, TYPE, NAME, ARGS, REAL, CALL ) \
CXXTEST_SUPPLY( MOCK, TYPE, NAME, ARGS, REAL, CALL )
#define CXXTEST_SUPPLY_VOID_C( MOCK, NAME, ARGS, REAL, CALL ) \
CXXTEST_EXTERN_C __CXXTEST_SUPPLY_VOID__PROTOTYPE( MOCK, NAME, ARGS, REAL, CALL ) \
CXXTEST_SUPPLY_VOID( MOCK, NAME, ARGS, REAL, CALL )
//
// Usually we mean the global namespace
//
#define CXXTEST_MOCK_GLOBAL( TYPE, NAME, ARGS, CALL ) \
CXXTEST_MOCK( NAME, TYPE, NAME, ARGS, ::NAME, CALL )
#define CXXTEST_MOCK_VOID_GLOBAL( NAME, ARGS, CALL ) \
CXXTEST_MOCK_VOID( NAME, NAME, ARGS, ::NAME, CALL )
#define CXXTEST_SUPPLY_GLOBAL( TYPE, NAME, ARGS, CALL ) \
CXXTEST_SUPPLY( NAME, TYPE, NAME, ARGS, NAME, CALL )
#define CXXTEST_SUPPLY_VOID_GLOBAL( NAME, ARGS, CALL ) \
CXXTEST_SUPPLY_VOID( NAME, NAME, ARGS, NAME, CALL )
#define CXXTEST_SUPPLY_GLOBAL_C( TYPE, NAME, ARGS, CALL ) \
CXXTEST_SUPPLY_C( NAME, TYPE, NAME, ARGS, NAME, CALL )
#define CXXTEST_SUPPLY_VOID_GLOBAL_C( NAME, ARGS, CALL ) \
CXXTEST_SUPPLY_VOID_C( NAME, NAME, ARGS, NAME, CALL )
//
// What to return when no mock object has been created.
// The default value of 0 usually works, but some cases may need this.
//
#define CXXTEST_MOCK_DEFAULT_VALUE( TYPE, VALUE ) \
namespace CXXTEST_MOCK_NAMESPACE \
{ \
template<> \
class MockTraits<TYPE> \
{ \
public: \
static TYPE defaultValue() { return VALUE; } \
}; \
}
#endif // __cxxtest__Mock_h__

View File

@@ -0,0 +1,21 @@
#ifndef __cxxtest__ParenPrinter_h__
#define __cxxtest__ParenPrinter_h__
//
// The ParenPrinter is identical to the ErrorPrinter, except it
// prints the line number in a format expected by some compilers
// (notably, MSVC).
//
#include <cxxtest/ErrorPrinter.h>
namespace CxxTest
{
class ParenPrinter : public ErrorPrinter
{
public:
ParenPrinter( CXXTEST_STD(ostream) &o = CXXTEST_STD(cout) ) : ErrorPrinter( o, "(", ")" ) {}
};
}
#endif // __cxxtest__ParenPrinter_h__

View File

@@ -0,0 +1,271 @@
#ifndef __cxxtest__QtGui_h__
#define __cxxtest__QtGui_h__
//
// The QtGui displays a simple progress bar using the Qt Toolkit. It
// has been tested with versions 2.x and 3.x.
//
// Apart from normal Qt command-line arguments, it accepts the following options:
// -minimized Start minimized, pop up on error
// -keep Don't close the window at the end
// -title TITLE Set the window caption
//
// If both are -minimized and -keep specified, GUI will only keep the
// window if it's in focus.
//
#include <cxxtest/Gui.h>
#include <qapplication.h>
#include <qglobal.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qmessagebox.h>
#include <qpixmap.h>
#include <qprogressbar.h>
#include <qstatusbar.h>
namespace CxxTest
{
class QtGui : public GuiListener
{
public:
void enterGui( int &argc, char **argv )
{
parseCommandLine( argc, argv );
createApplication( argc, argv );
}
void enterWorld( const WorldDescription &wd )
{
createWindow( wd );
processEvents();
}
void guiEnterSuite( const char *suiteName )
{
showSuiteName( suiteName );
}
void guiEnterTest( const char *suiteName, const char *testName )
{
setCaption( suiteName, testName );
advanceProgressBar();
showTestName( testName );
showTestsDone( _progressBar->progress() );
processEvents();
}
void yellowBar()
{
setColor( 255, 255, 0 );
setIcon( QMessageBox::Warning );
getTotalTests();
processEvents();
}
void redBar()
{
if ( _startMinimized && _mainWindow->isMinimized() )
showNormal();
setColor( 255, 0, 0 );
setIcon( QMessageBox::Critical );
getTotalTests();
processEvents();
}
void leaveGui()
{
if ( keep() ) {
showSummary();
_application->exec();
}
else
_mainWindow->close( true );
}
private:
QString _title;
bool _startMinimized, _keep;
unsigned _numTotalTests;
QString _strTotalTests;
QApplication *_application;
QWidget *_mainWindow;
QVBoxLayout *_layout;
QProgressBar *_progressBar;
QStatusBar *_statusBar;
QLabel *_suiteName, *_testName, *_testsDone;
void parseCommandLine( int argc, char **argv )
{
_startMinimized = _keep = false;
_title = argv[0];
for ( int i = 1; i < argc; ++ i ) {
QString arg( argv[i] );
if ( arg == "-minimized" )
_startMinimized = true;
else if ( arg == "-keep" )
_keep = true;
else if ( arg == "-title" && (i + 1 < argc) )
_title = argv[++i];
}
}
void createApplication( int &argc, char **argv )
{
_application = new QApplication( argc, argv );
}
void createWindow( const WorldDescription &wd )
{
getTotalTests( wd );
createMainWindow();
createProgressBar();
createStatusBar();
setMainWidget();
if ( _startMinimized )
showMinimized();
else
showNormal();
}
void getTotalTests()
{
getTotalTests( tracker().world() );
}
void getTotalTests( const WorldDescription &wd )
{
_numTotalTests = wd.numTotalTests();
char s[WorldDescription::MAX_STRLEN_TOTAL_TESTS];
_strTotalTests = wd.strTotalTests( s );
}
void createMainWindow()
{
_mainWindow = new QWidget();
_layout = new QVBoxLayout( _mainWindow );
}
void createProgressBar()
{
_layout->addWidget( _progressBar = new QProgressBar( _numTotalTests, _mainWindow ) );
_progressBar->setProgress( 0 );
setColor( 0, 255, 0 );
setIcon( QMessageBox::Information );
}
void createStatusBar()
{
_layout->addWidget( _statusBar = new QStatusBar( _mainWindow ) );
_statusBar->addWidget( _suiteName = new QLabel( _statusBar ), 2 );
_statusBar->addWidget( _testName = new QLabel( _statusBar ), 4 );
_statusBar->addWidget( _testsDone = new QLabel( _statusBar ), 1 );
}
void setMainWidget()
{
_application->setMainWidget( _mainWindow );
}
void showMinimized()
{
_mainWindow->showMinimized();
}
void showNormal()
{
_mainWindow->showNormal();
centerWindow();
}
void setCaption( const QString &suiteName, const QString &testName )
{
_mainWindow->setCaption( _title + " - " + suiteName + "::" + testName + "()" );
}
void showSuiteName( const QString &suiteName )
{
_suiteName->setText( "class " + suiteName );
}
void advanceProgressBar()
{
_progressBar->setProgress( _progressBar->progress() + 1 );
}
void showTestName( const QString &testName )
{
_testName->setText( testName + "()" );
}
void showTestsDone( unsigned testsDone )
{
_testsDone->setText( asString( testsDone ) + " of " + _strTotalTests );
}
static QString asString( unsigned n )
{
return QString::number( n );
}
void setColor( int r, int g, int b )
{
QPalette palette = _progressBar->palette();
palette.setColor( QColorGroup::Highlight, QColor( r, g, b ) );
_progressBar->setPalette( palette );
}
void setIcon( QMessageBox::Icon icon )
{
#if QT_VERSION >= 0x030000
_mainWindow->setIcon( QMessageBox::standardIcon( icon ) );
#else // Qt version < 3.0.0
_mainWindow->setIcon( QMessageBox::standardIcon( icon, QApplication::style().guiStyle() ) );
#endif // QT_VERSION
}
void processEvents()
{
_application->processEvents();
}
void centerWindow()
{
QWidget *desktop = QApplication::desktop();
int xCenter = desktop->x() + (desktop->width() / 2);
int yCenter = desktop->y() + (desktop->height() / 2);
int windowWidth = (desktop->width() * 4) / 5;
int windowHeight = _mainWindow->height();
_mainWindow->setGeometry( xCenter - (windowWidth / 2), yCenter - (windowHeight / 2), windowWidth, windowHeight );
}
bool keep()
{
if ( !_keep )
return false;
if ( !_startMinimized )
return true;
return (_mainWindow == _application->activeWindow());
}
void showSummary()
{
QString summary = _strTotalTests + (_numTotalTests == 1 ? " test" : " tests");
if ( tracker().failedTests() )
summary = "Failed " + asString( tracker().failedTests() ) + " of " + summary;
else
summary = summary + " passed";
_mainWindow->setCaption( _title + " - " + summary );
_statusBar->removeWidget( _suiteName );
_statusBar->removeWidget( _testName );
_testsDone->setText( summary );
}
};
}
#endif // __cxxtest__QtGui_h__

View File

@@ -0,0 +1,310 @@
#ifndef __cxxtest__RealDescriptions_cpp__
#define __cxxtest__RealDescriptions_cpp__
//
// NOTE: If an error occur during world construction/deletion, CxxTest cannot
// know where the error originated.
//
#include <cxxtest/RealDescriptions.h>
namespace CxxTest
{
RealTestDescription::RealTestDescription()
{
}
RealTestDescription::RealTestDescription( List &argList,
SuiteDescription &argSuite,
unsigned argLine,
const char *argTestName )
{
initialize( argList, argSuite, argLine, argTestName );
}
void RealTestDescription::initialize( List &argList,
SuiteDescription &argSuite,
unsigned argLine,
const char *argTestName )
{
_suite = &argSuite;
_line = argLine;
_testName = argTestName;
attach( argList );
}
bool RealTestDescription::setUp()
{
if ( !suite() )
return false;
for ( GlobalFixture *gf = GlobalFixture::firstGlobalFixture(); gf != 0; gf = gf->nextGlobalFixture() ) {
bool ok;
_TS_TRY { ok = gf->setUp(); }
_TS_LAST_CATCH( { ok = false; } );
if ( !ok ) {
doFailTest( file(), line(), "Error in GlobalFixture::setUp()" );
return false;
}
}
_TS_TRY {
_TSM_ASSERT_THROWS_NOTHING( file(), line(), "Exception thrown from setUp()", suite()->setUp() );
}
_TS_CATCH_ABORT( { return false; } );
return true;
}
bool RealTestDescription::tearDown()
{
if ( !suite() )
return false;
_TS_TRY {
_TSM_ASSERT_THROWS_NOTHING( file(), line(), "Exception thrown from tearDown()", suite()->tearDown() );
}
_TS_CATCH_ABORT( { return false; } );
for ( GlobalFixture *gf = GlobalFixture::lastGlobalFixture(); gf != 0; gf = gf->prevGlobalFixture() ) {
bool ok;
_TS_TRY { ok = gf->tearDown(); }
_TS_LAST_CATCH( { ok = false; } );
if ( !ok ) {
doFailTest( file(), line(), "Error in GlobalFixture::tearDown()" );
return false;
}
}
return true;
}
const char *RealTestDescription::file() const { return _suite->file(); }
unsigned RealTestDescription::line() const { return _line; }
const char *RealTestDescription::testName() const { return _testName; }
const char *RealTestDescription::suiteName() const { return _suite->suiteName(); }
TestDescription *RealTestDescription::next() { return (RealTestDescription *)Link::next(); }
const TestDescription *RealTestDescription::next() const { return (const RealTestDescription *)Link::next(); }
TestSuite *RealTestDescription::suite() const { return _suite->suite(); }
void RealTestDescription::run()
{
_TS_TRY { runTest(); }
_TS_CATCH_ABORT( {} )
___TSM_CATCH( file(), line(), "Exception thrown from test" );
}
RealSuiteDescription::RealSuiteDescription() {}
RealSuiteDescription::RealSuiteDescription( const char *argFile,
unsigned argLine,
const char *argSuiteName,
List &argTests )
{
initialize( argFile, argLine, argSuiteName, argTests );
}
void RealSuiteDescription::initialize( const char *argFile,
unsigned argLine,
const char *argSuiteName,
List &argTests )
{
_file = argFile;
_line = argLine;
_suiteName = argSuiteName;
_tests = &argTests;
attach( _suites );
}
const char *RealSuiteDescription::file() const { return _file; }
unsigned RealSuiteDescription::line() const { return _line; }
const char *RealSuiteDescription::suiteName() const { return _suiteName; }
TestDescription *RealSuiteDescription::firstTest() { return (RealTestDescription *)_tests->head(); }
const TestDescription *RealSuiteDescription::firstTest() const { return (const RealTestDescription *)_tests->head(); }
SuiteDescription *RealSuiteDescription::next() { return (RealSuiteDescription *)Link::next(); }
const SuiteDescription *RealSuiteDescription::next() const { return (const RealSuiteDescription *)Link::next(); }
unsigned RealSuiteDescription::numTests() const { return _tests->size(); }
const TestDescription &RealSuiteDescription::testDescription( unsigned i ) const
{
return *(RealTestDescription *)_tests->nth( i );
}
void RealSuiteDescription::activateAllTests()
{
_tests->activateAll();
}
bool RealSuiteDescription::leaveOnly( const char *testName )
{
for ( TestDescription *td = firstTest(); td != 0; td = td->next() ) {
if ( stringsEqual( td->testName(), testName ) ) {
_tests->leaveOnly( *td );
return true;
}
}
return false;
}
StaticSuiteDescription::StaticSuiteDescription() {}
StaticSuiteDescription::StaticSuiteDescription( const char *argFile, unsigned argLine,
const char *argSuiteName, TestSuite &argSuite,
List &argTests ) :
RealSuiteDescription( argFile, argLine, argSuiteName, argTests )
{
doInitialize( argSuite );
}
void StaticSuiteDescription::initialize( const char *argFile, unsigned argLine,
const char *argSuiteName, TestSuite &argSuite,
List &argTests )
{
RealSuiteDescription::initialize( argFile, argLine, argSuiteName, argTests );
doInitialize( argSuite );
}
void StaticSuiteDescription::doInitialize( TestSuite &argSuite )
{
_suite = &argSuite;
}
TestSuite *StaticSuiteDescription::suite() const
{
return _suite;
}
bool StaticSuiteDescription::setUp() { return true; }
bool StaticSuiteDescription::tearDown() { return true; }
CommonDynamicSuiteDescription::CommonDynamicSuiteDescription() {}
CommonDynamicSuiteDescription::CommonDynamicSuiteDescription( const char *argFile, unsigned argLine,
const char *argSuiteName, List &argTests,
unsigned argCreateLine, unsigned argDestroyLine ) :
RealSuiteDescription( argFile, argLine, argSuiteName, argTests )
{
doInitialize( argCreateLine, argDestroyLine );
}
void CommonDynamicSuiteDescription::initialize( const char *argFile, unsigned argLine,
const char *argSuiteName, List &argTests,
unsigned argCreateLine, unsigned argDestroyLine )
{
RealSuiteDescription::initialize( argFile, argLine, argSuiteName, argTests );
doInitialize( argCreateLine, argDestroyLine );
}
void CommonDynamicSuiteDescription::doInitialize( unsigned argCreateLine, unsigned argDestroyLine )
{
_createLine = argCreateLine;
_destroyLine = argDestroyLine;
}
List &RealWorldDescription::suites()
{
return RealSuiteDescription::_suites;
}
unsigned RealWorldDescription::numSuites( void ) const
{
return suites().size();
}
unsigned RealWorldDescription::numTotalTests( void ) const
{
unsigned count = 0;
for ( const SuiteDescription *sd = firstSuite(); sd != 0; sd = sd->next() )
count += sd->numTests();
return count;
}
SuiteDescription *RealWorldDescription::firstSuite()
{
return (RealSuiteDescription *)suites().head();
}
const SuiteDescription *RealWorldDescription::firstSuite() const
{
return (const RealSuiteDescription *)suites().head();
}
const SuiteDescription &RealWorldDescription::suiteDescription( unsigned i ) const
{
return *(const RealSuiteDescription *)suites().nth( i );
}
void RealWorldDescription::activateAllTests()
{
suites().activateAll();
for ( SuiteDescription *sd = firstSuite(); sd != 0; sd = sd->next() )
sd->activateAllTests();
}
bool RealWorldDescription::leaveOnly( const char *suiteName, const char *testName )
{
for ( SuiteDescription *sd = firstSuite(); sd != 0; sd = sd->next() ) {
if ( stringsEqual( sd->suiteName(), suiteName ) ) {
if ( testName )
if ( !sd->leaveOnly( testName ) )
return false;
suites().leaveOnly( *sd );
return true;
}
}
return false;
}
bool RealWorldDescription::setUp()
{
for ( GlobalFixture *gf = GlobalFixture::firstGlobalFixture(); gf != 0; gf = gf->nextGlobalFixture() ) {
bool ok;
_TS_TRY { ok = gf->setUpWorld(); }
_TS_LAST_CATCH( { ok = false; } );
if ( !ok ) {
reportError( "Error setting up world" );
return false;
}
}
return true;
}
bool RealWorldDescription::tearDown()
{
for ( GlobalFixture *gf = GlobalFixture::lastGlobalFixture(); gf != 0; gf = gf->prevGlobalFixture() ) {
bool ok;
_TS_TRY { ok = gf->tearDownWorld(); }
_TS_LAST_CATCH( { ok = false; } );
if ( !ok ) {
reportError( "Error tearing down world" );
return false;
}
}
return true;
}
void RealWorldDescription::reportError( const char *message )
{
doWarn( __FILE__, 5, message );
}
void activateAllTests()
{
RealWorldDescription().activateAllTests();
}
bool leaveOnly( const char *suiteName, const char *testName )
{
return RealWorldDescription().leaveOnly( suiteName, testName );
}
}
#endif // __cxxtest__RealDescriptions_cpp__

View File

@@ -0,0 +1,222 @@
#ifndef __cxxtest__RealDescriptions_h__
#define __cxxtest__RealDescriptions_h__
//
// The "real" description classes
//
#include <cxxtest/Descriptions.h>
#include <cxxtest/TestSuite.h>
#include <cxxtest/GlobalFixture.h>
namespace CxxTest
{
class RealTestDescription : public TestDescription
{
public:
RealTestDescription();
RealTestDescription( List &argList, SuiteDescription &argSuite, unsigned argLine, const char *argTestName );
void initialize( List &argList, SuiteDescription &argSuite, unsigned argLine, const char *argTestName );
const char *file() const;
unsigned line() const;
const char *testName() const;
const char *suiteName() const;
TestDescription *next();
const TestDescription *next() const;
TestSuite *suite() const;
bool setUp();
void run();
bool tearDown();
private:
RealTestDescription( const RealTestDescription & );
RealTestDescription &operator=( const RealTestDescription & );
virtual void runTest() = 0;
SuiteDescription *_suite;
unsigned _line;
const char *_testName;
};
class RealSuiteDescription : public SuiteDescription
{
public:
RealSuiteDescription();
RealSuiteDescription( const char *argFile, unsigned argLine, const char *argSuiteName, List &argTests );
void initialize( const char *argFile, unsigned argLine, const char *argSuiteName, List &argTests );
const char *file() const;
unsigned line() const;
const char *suiteName() const;
TestDescription *firstTest();
const TestDescription *firstTest() const;
SuiteDescription *next();
const SuiteDescription *next() const;
unsigned numTests() const;
const TestDescription &testDescription( unsigned i ) const;
void activateAllTests();
bool leaveOnly( const char *testName );
private:
RealSuiteDescription( const RealSuiteDescription & );
RealSuiteDescription &operator=( const RealSuiteDescription & );
const char *_file;
unsigned _line;
const char *_suiteName;
List *_tests;
static List _suites;
friend class RealWorldDescription;
};
class StaticSuiteDescription : public RealSuiteDescription
{
public:
StaticSuiteDescription();
StaticSuiteDescription( const char *argFile, unsigned argLine,
const char *argSuiteName, TestSuite &argSuite,
List &argTests );
void initialize( const char *argFile, unsigned argLine,
const char *argSuiteName, TestSuite &argSuite,
List &argTests );
TestSuite *suite() const;
bool setUp();
bool tearDown();
private:
StaticSuiteDescription( const StaticSuiteDescription & );
StaticSuiteDescription &operator=( const StaticSuiteDescription & );
void doInitialize( TestSuite &argSuite );
TestSuite *_suite;
};
class CommonDynamicSuiteDescription : public RealSuiteDescription
{
public:
CommonDynamicSuiteDescription();
CommonDynamicSuiteDescription( const char *argFile, unsigned argLine,
const char *argSuiteName, List &argTests,
unsigned argCreateLine, unsigned argDestroyLine );
void initialize( const char *argFile, unsigned argLine,
const char *argSuiteName, List &argTests,
unsigned argCreateLine, unsigned argDestroyLine );
protected:
unsigned _createLine, _destroyLine;
private:
void doInitialize( unsigned argCreateLine, unsigned argDestroyLine );
};
template<class S>
class DynamicSuiteDescription : public CommonDynamicSuiteDescription
{
public:
DynamicSuiteDescription() {}
DynamicSuiteDescription( const char *argFile, unsigned argLine,
const char *argSuiteName, List &argTests,
S *&argSuite, unsigned argCreateLine,
unsigned argDestroyLine ) :
CommonDynamicSuiteDescription( argFile, argLine, argSuiteName, argTests, argCreateLine, argDestroyLine )
{
_suite = &argSuite;
}
void initialize( const char *argFile, unsigned argLine,
const char *argSuiteName, List &argTests,
S *&argSuite, unsigned argCreateLine,
unsigned argDestroyLine )
{
CommonDynamicSuiteDescription::initialize( argFile, argLine,
argSuiteName, argTests,
argCreateLine, argDestroyLine );
_suite = &argSuite;
}
TestSuite *suite() const { return realSuite(); }
bool setUp();
bool tearDown();
private:
S *realSuite() const { return *_suite; }
void setSuite( S *s ) { *_suite = s; }
void createSuite()
{
setSuite( S::createSuite() );
}
void destroySuite()
{
S *s = realSuite();
setSuite( 0 );
S::destroySuite( s );
}
S **_suite;
};
template<class S>
bool DynamicSuiteDescription<S>::setUp()
{
_TS_TRY {
_TSM_ASSERT_THROWS_NOTHING( file(), _createLine, "Exception thrown from createSuite()", createSuite() );
_TSM_ASSERT( file(), _createLine, "createSuite() failed", suite() != 0 );
}
_TS_CATCH_ABORT( { return false; } );
return (suite() != 0);
}
template<class S>
bool DynamicSuiteDescription<S>::tearDown()
{
if ( !_suite )
return true;
_TS_TRY {
_TSM_ASSERT_THROWS_NOTHING( file(), _destroyLine, "destroySuite() failed", destroySuite() );
}
_TS_CATCH_ABORT( { return false; } );
return true;
}
class RealWorldDescription : public WorldDescription
{
public:
static List &suites();
unsigned numSuites( void ) const;
unsigned numTotalTests( void ) const;
SuiteDescription *firstSuite();
const SuiteDescription *firstSuite() const;
const SuiteDescription &suiteDescription( unsigned i ) const;
void activateAllTests();
bool leaveOnly( const char *suiteName, const char *testName = 0 );
bool setUp();
bool tearDown();
static void reportError( const char *message );
};
void activateAllTests();
bool leaveOnly( const char *suiteName, const char *testName = 0 );
}
#endif // __cxxtest__RealDescriptions_h__

View File

@@ -0,0 +1,18 @@
#ifndef __cxxtest__Root_cpp__
#define __cxxtest__Root_cpp__
//
// This file holds the "root" of CxxTest, i.e.
// the parts that must be in a source file file.
//
#include <cxxtest/Descriptions.cpp>
#include <cxxtest/DummyDescriptions.cpp>
#include <cxxtest/GlobalFixture.cpp>
#include <cxxtest/LinkedList.cpp>
#include <cxxtest/RealDescriptions.cpp>
#include <cxxtest/TestSuite.cpp>
#include <cxxtest/TestTracker.cpp>
#include <cxxtest/ValueTraits.cpp>
#endif // __cxxtest__Root_cpp__

View File

@@ -0,0 +1,7 @@
#ifndef __cxxtest_SelfTest_h__
#define __cxxtest_SelfTest_h__
#define CXXTEST_SUITE(name)
#define CXXTEST_CODE(member)
#endif // __cxxtest_SelfTest_h__

View File

@@ -0,0 +1,25 @@
#ifndef __cxxtest_StdHeaders_h__
#define __cxxtest_StdHeaders_h__
//
// This file basically #includes the STL headers.
// It exists to support warning level 4 in Visual C++
//
#ifdef _MSC_VER
# pragma warning( push, 1 )
#endif // _MSC_VER
#include <complex>
#include <deque>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#ifdef _MSC_VER
# pragma warning( pop )
#endif // _MSC_VER
#endif // __cxxtest_StdHeaders_h__

View File

@@ -0,0 +1,229 @@
#ifndef __cxxtest_StdValueTraits_h__
#define __cxxtest_StdValueTraits_h__
//
// This file defines ValueTraits for std:: stuff.
// It is #included by <cxxtest/ValueTraits.h> if you
// define CXXTEST_HAVE_STD
//
#include <cxxtest/ValueTraits.h>
#include <cxxtest/StdHeaders.h>
#ifdef _CXXTEST_OLD_STD
# define CXXTEST_STD(x) x
#else // !_CXXTEST_OLD_STD
# define CXXTEST_STD(x) std::x
#endif // _CXXTEST_OLD_STD
#ifndef CXXTEST_USER_VALUE_TRAITS
namespace CxxTest
{
//
// NOTE: This should have been
// template<class Char, class Traits, class Allocator>
// class ValueTraits< std::basic_string<Char, Traits, Allocator> > {};
// But MSVC doesn't support it (yet).
//
//
// If we have std::string, we might as well use it
//
class StdTraitsBase
{
public:
StdTraitsBase &operator<<( const CXXTEST_STD(string) &s ) { _s += s; return *this; }
const char *asString() const { return _s.c_str(); }
private:
CXXTEST_STD(string) _s;
};
//
// std::string
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const CXXTEST_STD(string)> : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(string) &s )
{
*this << "\"";
for ( unsigned i = 0; i < s.length(); ++ i ) {
char c[sizeof("\\xXX")];
charToString( s[i], c );
*this << c;
}
*this << "\"";
}
};
CXXTEST_COPY_CONST_TRAITS( CXXTEST_STD(string) );
#ifndef _CXXTEST_OLD_STD
//
// std::wstring
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const CXXTEST_STD(basic_string<wchar_t>)> : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(basic_string<wchar_t>) &s )
{
*this << "L\"";
for ( unsigned i = 0; i < s.length(); ++ i ) {
char c[sizeof("\\x12345678")];
charToString( (unsigned long)s[i], c );
*this << c;
}
*this << "\"";
}
};
CXXTEST_COPY_CONST_TRAITS( CXXTEST_STD(basic_string<wchar_t>) );
#endif // _CXXTEST_OLD_STD
//
// Convert a range defined by iterators to a string
// This is useful for almost all STL containers
//
template<class Stream, class Iterator>
void dumpRange( Stream &s, Iterator first, Iterator last )
{
s << "{ ";
while ( first != last ) {
s << TS_AS_STRING(*first);
++ first;
s << ((first == last) ? " }" : ", ");
}
}
#ifdef _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
//
// std::pair
//
template<class First, class Second>
class ValueTraits< CXXTEST_STD(pair)<First, Second> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(pair)<First, Second> &p )
{
*this << "<" << TS_AS_STRING( p.first ) << ", " << TS_AS_STRING( p.second ) << ">";
}
};
//
// std::vector
//
template<class Element>
class ValueTraits< CXXTEST_STD(vector)<Element> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(vector)<Element> &v )
{
dumpRange( *this, v.begin(), v.end() );
}
};
//
// std::list
//
template<class Element>
class ValueTraits< CXXTEST_STD(list)<Element> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(list)<Element> &l )
{
dumpRange( *this, l.begin(), l.end() );
}
};
//
// std::set
//
template<class Element>
class ValueTraits< CXXTEST_STD(set)<Element> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(set)<Element> &s )
{
dumpRange( *this, s.begin(), s.end() );
}
};
//
// std::map
//
template<class Key, class Value>
class ValueTraits< CXXTEST_STD(map)<Key, Value> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(map)<Key, Value> &m )
{
dumpRange( *this, m.begin(), m.end() );
}
};
//
// std::deque
//
template<class Element>
class ValueTraits< CXXTEST_STD(deque)<Element> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(deque)<Element> &d )
{
dumpRange( *this, d.begin(), d.end() );
}
};
//
// std::multiset
//
template<class Element>
class ValueTraits< CXXTEST_STD(multiset)<Element> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(multiset)<Element> &ms )
{
dumpRange( *this, ms.begin(), ms.end() );
}
};
//
// std::multimap
//
template<class Key, class Value>
class ValueTraits< CXXTEST_STD(multimap)<Key, Value> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(multimap)<Key, Value> &mm )
{
dumpRange( *this, mm.begin(), mm.end() );
}
};
//
// std::complex
//
template<class Number>
class ValueTraits< CXXTEST_STD(complex)<Number> > : public StdTraitsBase
{
public:
ValueTraits( const CXXTEST_STD(complex)<Number> &c )
{
if ( !c.imag() )
*this << TS_AS_STRING(c.real());
else if ( !c.real() )
*this << "(" << TS_AS_STRING(c.imag()) << " * i)";
else
*this << "(" << TS_AS_STRING(c.real()) << " + " << TS_AS_STRING(c.imag()) << " * i)";
}
};
#endif // _CXXTEST_PARTIAL_TEMPLATE_SPECIALIZATION
}
#endif // CXXTEST_USER_VALUE_TRAITS
#endif // __cxxtest_StdValueTraits_h__

View File

@@ -0,0 +1,41 @@
#ifndef __cxxtest__StdioFilePrinter_h__
#define __cxxtest__StdioFilePrinter_h__
//
// The StdioFilePrinter is a simple TestListener that
// just prints "OK" if everything goes well, otherwise
// reports the error in the format of compiler messages.
// This class uses <stdio.h>, i.e. FILE * and fprintf().
//
#include <cxxtest/ErrorFormatter.h>
#include <stdio.h>
namespace CxxTest
{
class StdioFilePrinter : public ErrorFormatter
{
public:
StdioFilePrinter( FILE *o, const char *preLine = ":", const char *postLine = "" ) :
ErrorFormatter( new Adapter(o), preLine, postLine ) {}
virtual ~StdioFilePrinter() { delete outputStream(); }
private:
class Adapter : public OutputStream
{
Adapter( const Adapter & );
Adapter &operator=( const Adapter & );
FILE *_o;
public:
Adapter( FILE *o ) : _o(o) {}
void flush() { fflush( _o ); }
OutputStream &operator<<( unsigned i ) { fprintf( _o, "%u", i ); return *this; }
OutputStream &operator<<( const char *s ) { fputs( s, _o ); return *this; }
OutputStream &operator<<( Manipulator m ) { return OutputStream::operator<<( m ); }
};
};
}
#endif // __cxxtest__StdioFilePrinter_h__

View File

@@ -0,0 +1,22 @@
#ifndef __cxxtest__StdioPrinter_h__
#define __cxxtest__StdioPrinter_h__
//
// The StdioPrinter is an StdioFilePrinter which defaults to stdout.
// This should have been called StdOutPrinter or something, but the name
// has been historically used.
//
#include <cxxtest/StdioFilePrinter.h>
namespace CxxTest
{
class StdioPrinter : public StdioFilePrinter
{
public:
StdioPrinter( FILE *o = stdout, const char *preLine = ":", const char *postLine = "" ) :
StdioFilePrinter( o, preLine, postLine ) {}
};
}
#endif // __cxxtest__StdioPrinter_h__

View File

@@ -0,0 +1,181 @@
#ifndef __cxxtest__TeeListener_h__
#define __cxxtest__TeeListener_h__
//
// A TeeListener notifies two "reular" TestListeners
//
#include <cxxtest/TestListener.h>
#include <cxxtest/TestListener.h>
namespace CxxTest
{
class TeeListener : public TestListener
{
public:
TeeListener()
{
setFirst( _dummy );
setSecond( _dummy );
}
virtual ~TeeListener()
{
}
void setFirst( TestListener &first )
{
_first = &first;
}
void setSecond( TestListener &second )
{
_second = &second;
}
void enterWorld( const WorldDescription &d )
{
_first->enterWorld( d );
_second->enterWorld( d );
}
void enterSuite( const SuiteDescription &d )
{
_first->enterSuite( d );
_second->enterSuite( d );
}
void enterTest( const TestDescription &d )
{
_first->enterTest( d );
_second->enterTest( d );
}
void trace( const char *file, unsigned line, const char *expression )
{
_first->trace( file, line, expression );
_second->trace( file, line, expression );
}
void warning( const char *file, unsigned line, const char *expression )
{
_first->warning( file, line, expression );
_second->warning( file, line, expression );
}
void failedTest( const char *file, unsigned line, const char *expression )
{
_first->failedTest( file, line, expression );
_second->failedTest( file, line, expression );
}
void failedAssert( const char *file, unsigned line, const char *expression )
{
_first->failedAssert( file, line, expression );
_second->failedAssert( file, line, expression );
}
void failedAssertEquals( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
_first->failedAssertEquals( file, line, xStr, yStr, x, y );
_second->failedAssertEquals( file, line, xStr, yStr, x, y );
}
void failedAssertSameData( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *sizeStr, const void *x,
const void *y, unsigned size )
{
_first->failedAssertSameData( file, line, xStr, yStr, sizeStr, x, y, size );
_second->failedAssertSameData( file, line, xStr, yStr, sizeStr, x, y, size );
}
void failedAssertDelta( const char *file, unsigned line,
const char *xStr, const char *yStr, const char *dStr,
const char *x, const char *y, const char *d )
{
_first->failedAssertDelta( file, line, xStr, yStr, dStr, x, y, d );
_second->failedAssertDelta( file, line, xStr, yStr, dStr, x, y, d );
}
void failedAssertDiffers( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *value )
{
_first->failedAssertDiffers( file, line, xStr, yStr, value );
_second->failedAssertDiffers( file, line, xStr, yStr, value );
}
void failedAssertLessThan( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
_first->failedAssertLessThan( file, line, xStr, yStr, x, y );
_second->failedAssertLessThan( file, line, xStr, yStr, x, y );
}
void failedAssertLessThanEquals( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
_first->failedAssertLessThanEquals( file, line, xStr, yStr, x, y );
_second->failedAssertLessThanEquals( file, line, xStr, yStr, x, y );
}
void failedAssertPredicate( const char *file, unsigned line,
const char *predicate, const char *xStr, const char *x )
{
_first->failedAssertPredicate( file, line, predicate, xStr, x );
_second->failedAssertPredicate( file, line, predicate, xStr, x );
}
void failedAssertRelation( const char *file, unsigned line,
const char *relation, const char *xStr, const char *yStr,
const char *x, const char *y )
{
_first->failedAssertRelation( file, line, relation, xStr, yStr, x, y );
_second->failedAssertRelation( file, line, relation, xStr, yStr, x, y );
}
void failedAssertThrows( const char *file, unsigned line,
const char *expression, const char *type,
bool otherThrown )
{
_first->failedAssertThrows( file, line, expression, type, otherThrown );
_second->failedAssertThrows( file, line, expression, type, otherThrown );
}
void failedAssertThrowsNot( const char *file, unsigned line,
const char *expression )
{
_first->failedAssertThrowsNot( file, line, expression );
_second->failedAssertThrowsNot( file, line, expression );
}
void leaveTest( const TestDescription &d )
{
_first->leaveTest(d);
_second->leaveTest(d);
}
void leaveSuite( const SuiteDescription &d )
{
_first->leaveSuite(d);
_second->leaveSuite(d);
}
void leaveWorld( const WorldDescription &d )
{
_first->leaveWorld(d);
_second->leaveWorld(d);
}
private:
TestListener *_first, *_second;
TestListener _dummy;
};
}
#endif // __cxxtest__TeeListener_h__

View File

@@ -0,0 +1,70 @@
#ifndef __cxxtest__TestListener_h__
#define __cxxtest__TestListener_h__
//
// TestListener is the base class for all "listeners",
// i.e. classes that receive notifications of the
// testing process.
//
// The names of the parameters are in comments to avoid
// "unused parameter" warnings.
//
#include <cxxtest/Descriptions.h>
namespace CxxTest
{
class TestListener
{
public:
TestListener() {}
virtual ~TestListener() {}
virtual void enterWorld( const WorldDescription & /*desc*/ ) {}
virtual void enterSuite( const SuiteDescription & /*desc*/ ) {}
virtual void enterTest( const TestDescription & /*desc*/ ) {}
virtual void trace( const char * /*file*/, unsigned /*line*/,
const char * /*expression*/ ) {}
virtual void warning( const char * /*file*/, unsigned /*line*/,
const char * /*expression*/ ) {}
virtual void failedTest( const char * /*file*/, unsigned /*line*/,
const char * /*expression*/ ) {}
virtual void failedAssert( const char * /*file*/, unsigned /*line*/,
const char * /*expression*/ ) {}
virtual void failedAssertEquals( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*x*/, const char * /*y*/ ) {}
virtual void failedAssertSameData( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*sizeStr*/, const void * /*x*/,
const void * /*y*/, unsigned /*size*/ ) {}
virtual void failedAssertDelta( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*dStr*/, const char * /*x*/,
const char * /*y*/, const char * /*d*/ ) {}
virtual void failedAssertDiffers( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*value*/ ) {}
virtual void failedAssertLessThan( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*x*/, const char * /*y*/ ) {}
virtual void failedAssertLessThanEquals( const char * /*file*/, unsigned /*line*/,
const char * /*xStr*/, const char * /*yStr*/,
const char * /*x*/, const char * /*y*/ ) {}
virtual void failedAssertPredicate( const char * /*file*/, unsigned /*line*/,
const char * /*predicate*/, const char * /*xStr*/, const char * /*x*/ ) {}
virtual void failedAssertRelation( const char * /*file*/, unsigned /*line*/,
const char * /*relation*/, const char * /*xStr*/, const char * /*yStr*/,
const char * /*x*/, const char * /*y*/ ) {}
virtual void failedAssertThrows( const char * /*file*/, unsigned /*line*/,
const char * /*expression*/, const char * /*type*/,
bool /*otherThrown*/ ) {}
virtual void failedAssertThrowsNot( const char * /*file*/, unsigned /*line*/,
const char * /*expression*/ ) {}
virtual void leaveTest( const TestDescription & /*desc*/ ) {}
virtual void leaveSuite( const SuiteDescription & /*desc*/ ) {}
virtual void leaveWorld( const WorldDescription & /*desc*/ ) {}
};
}
#endif // __cxxtest__TestListener_h__

View File

@@ -0,0 +1,125 @@
#ifndef __cxxtest_TestRunner_h__
#define __cxxtest_TestRunner_h__
//
// TestRunner is the class that runs all the tests.
// To use it, create an object that implements the TestListener
// interface and call TestRunner::runAllTests( myListener );
//
#include <cxxtest/TestListener.h>
#include <cxxtest/RealDescriptions.h>
#include <cxxtest/TestSuite.h>
#include <cxxtest/TestTracker.h>
namespace CxxTest
{
class TestRunner
{
public:
static void runAllTests( TestListener &listener )
{
tracker().setListener( &listener );
_TS_TRY { TestRunner().runWorld(); }
_TS_LAST_CATCH( { tracker().failedTest( __FILE__, __LINE__, "Exception thrown from world" ); } );
tracker().setListener( 0 );
}
static void runAllTests( TestListener *listener )
{
if ( listener ) {
listener->warning( __FILE__, __LINE__, "Deprecated; Use runAllTests( TestListener & )" );
runAllTests( *listener );
}
}
private:
void runWorld()
{
RealWorldDescription wd;
WorldGuard sg;
tracker().enterWorld( wd );
if ( wd.setUp() ) {
for ( SuiteDescription *sd = wd.firstSuite(); sd; sd = sd->next() )
if ( sd->active() )
runSuite( *sd );
wd.tearDown();
}
tracker().leaveWorld( wd );
}
void runSuite( SuiteDescription &sd )
{
StateGuard sg;
tracker().enterSuite( sd );
if ( sd.setUp() ) {
for ( TestDescription *td = sd.firstTest(); td; td = td->next() )
if ( td->active() )
runTest( *td );
sd.tearDown();
}
tracker().leaveSuite( sd );
}
void runTest( TestDescription &td )
{
StateGuard sg;
tracker().enterTest( td );
if ( td.setUp() ) {
td.run();
td.tearDown();
}
tracker().leaveTest( td );
}
class StateGuard
{
#ifdef _CXXTEST_HAVE_EH
bool _abortTestOnFail;
#endif // _CXXTEST_HAVE_EH
unsigned _maxDumpSize;
public:
StateGuard()
{
#ifdef _CXXTEST_HAVE_EH
_abortTestOnFail = abortTestOnFail();
#endif // _CXXTEST_HAVE_EH
_maxDumpSize = maxDumpSize();
}
~StateGuard()
{
#ifdef _CXXTEST_HAVE_EH
setAbortTestOnFail( _abortTestOnFail );
#endif // _CXXTEST_HAVE_EH
setMaxDumpSize( _maxDumpSize );
}
};
class WorldGuard : public StateGuard
{
public:
WorldGuard() : StateGuard()
{
#ifdef _CXXTEST_HAVE_EH
setAbortTestOnFail( CXXTEST_DEFAULT_ABORT );
#endif // _CXXTEST_HAVE_EH
setMaxDumpSize( CXXTEST_MAX_DUMP_SIZE );
}
};
};
//
// For --no-static-init
//
void initialize();
}
#endif // __cxxtest_TestRunner_h__

View File

@@ -0,0 +1,138 @@
#ifndef __cxxtest__TestSuite_cpp__
#define __cxxtest__TestSuite_cpp__
#include <cxxtest/TestSuite.h>
namespace CxxTest
{
//
// TestSuite members
//
TestSuite::~TestSuite() {}
void TestSuite::setUp() {}
void TestSuite::tearDown() {}
//
// Test-aborting stuff
//
static bool currentAbortTestOnFail = false;
bool abortTestOnFail()
{
return currentAbortTestOnFail;
}
void setAbortTestOnFail( bool value )
{
currentAbortTestOnFail = value;
}
void doAbortTest()
{
# if defined(_CXXTEST_HAVE_EH)
if ( currentAbortTestOnFail )
throw AbortTest();
# endif // _CXXTEST_HAVE_EH
}
//
// Max dump size
//
static unsigned currentMaxDumpSize = CXXTEST_MAX_DUMP_SIZE;
unsigned maxDumpSize()
{
return currentMaxDumpSize;
}
void setMaxDumpSize( unsigned value )
{
currentMaxDumpSize = value;
}
//
// Some non-template functions
//
void doTrace( const char *file, unsigned line, const char *message )
{
tracker().trace( file, line, message );
}
void doWarn( const char *file, unsigned line, const char *message )
{
tracker().warning( file, line, message );
}
void doFailTest( const char *file, unsigned line, const char *message )
{
tracker().failedTest( file, line, message );
TS_ABORT();
}
void doFailAssert( const char *file, unsigned line,
const char *expression, const char *message )
{
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssert( file, line, expression );
TS_ABORT();
}
bool sameData( const void *x, const void *y, unsigned size )
{
if ( size == 0 )
return true;
if ( x == y )
return true;
if ( !x || !y )
return false;
const char *cx = (const char *)x;
const char *cy = (const char *)y;
while ( size -- )
if ( *cx++ != *cy++ )
return false;
return true;
}
void doAssertSameData( const char *file, unsigned line,
const char *xExpr, const void *x,
const char *yExpr, const void *y,
const char *sizeExpr, unsigned size,
const char *message )
{
if ( !sameData( x, y, size ) ) {
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertSameData( file, line, xExpr, yExpr, sizeExpr, x, y, size );
TS_ABORT();
}
}
void doFailAssertThrows( const char *file, unsigned line,
const char *expr, const char *type,
bool otherThrown,
const char *message )
{
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertThrows( file, line, expr, type, otherThrown );
TS_ABORT();
}
void doFailAssertThrowsNot( const char *file, unsigned line,
const char *expression, const char *message )
{
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertThrowsNot( file, line, expression );
TS_ABORT();
}
}
#endif // __cxxtest__TestSuite_cpp__

View File

@@ -0,0 +1,518 @@
#ifndef __cxxtest__TestSuite_h__
#define __cxxtest__TestSuite_h__
//
// class TestSuite is the base class for all test suites.
// To define a test suite, derive from this class and add
// member functions called void test*();
//
#include <cxxtest/Flags.h>
#include <cxxtest/TestTracker.h>
#include <cxxtest/Descriptions.h>
#include <cxxtest/ValueTraits.h>
#ifdef _CXXTEST_HAVE_STD
# include <stdexcept>
#endif // _CXXTEST_HAVE_STD
namespace CxxTest
{
class TestSuite
{
public:
virtual ~TestSuite();
virtual void setUp();
virtual void tearDown();
};
class AbortTest {};
void doAbortTest();
# define TS_ABORT() CxxTest::doAbortTest()
bool abortTestOnFail();
void setAbortTestOnFail( bool value = CXXTEST_DEFAULT_ABORT );
unsigned maxDumpSize();
void setMaxDumpSize( unsigned value = CXXTEST_MAX_DUMP_SIZE );
void doTrace( const char *file, unsigned line, const char *message );
void doWarn( const char *file, unsigned line, const char *message );
void doFailTest( const char *file, unsigned line, const char *message );
void doFailAssert( const char *file, unsigned line, const char *expression, const char *message );
template<class X, class Y>
bool equals( X x, Y y )
{
return (x == y);
}
template<>
bool equals<bool, int>(bool x, int y)
{
return (x == (bool)y);
}
template<class X, class Y>
void doAssertEquals( const char *file, unsigned line,
const char *xExpr, X x,
const char *yExpr, Y y,
const char *message )
{
if ( !equals( x, y ) ) {
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertEquals( file, line, xExpr, yExpr, TS_AS_STRING(x), TS_AS_STRING(y) );
TS_ABORT();
}
}
void doAssertSameData( const char *file, unsigned line,
const char *xExpr, const void *x,
const char *yExpr, const void *y,
const char *sizeExpr, unsigned size,
const char *message );
template<class X, class Y>
bool differs( X x, Y y )
{
return !(x == y);
}
template<class X, class Y>
void doAssertDiffers( const char *file, unsigned line,
const char *xExpr, X x,
const char *yExpr, Y y,
const char *message )
{
if ( !differs( x, y ) ) {
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertDiffers( file, line, xExpr, yExpr, TS_AS_STRING(x) );
TS_ABORT();
}
}
template<class X, class Y>
bool lessThan( X x, Y y )
{
return (x < y);
}
template<class X, class Y>
void doAssertLessThan( const char *file, unsigned line,
const char *xExpr, X x,
const char *yExpr, Y y,
const char *message )
{
if ( !lessThan(x, y) ) {
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertLessThan( file, line, xExpr, yExpr, TS_AS_STRING(x), TS_AS_STRING(y) );
TS_ABORT();
}
}
template<class X, class Y>
bool lessThanEquals( X x, Y y )
{
return (x <= y);
}
template<class X, class Y>
void doAssertLessThanEquals( const char *file, unsigned line,
const char *xExpr, X x,
const char *yExpr, Y y,
const char *message )
{
if ( !lessThanEquals( x, y ) ) {
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertLessThanEquals( file, line, xExpr, yExpr, TS_AS_STRING(x), TS_AS_STRING(y) );
TS_ABORT();
}
}
template<class X, class P>
void doAssertPredicate( const char *file, unsigned line,
const char *pExpr, const P &p,
const char *xExpr, X x,
const char *message )
{
if ( !p( x ) ) {
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertPredicate( file, line, pExpr, xExpr, TS_AS_STRING(x) );
TS_ABORT();
}
}
template<class X, class Y, class R>
void doAssertRelation( const char *file, unsigned line,
const char *rExpr, const R &r,
const char *xExpr, X x,
const char *yExpr, Y y,
const char *message )
{
if ( !r( x, y ) ) {
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertRelation( file, line, rExpr, xExpr, yExpr, TS_AS_STRING(x), TS_AS_STRING(y) );
TS_ABORT();
}
}
template<class X, class Y, class D>
bool delta( X x, Y y, D d )
{
return ((y >= x - d) && (y <= x + d));
}
template<class X, class Y, class D>
void doAssertDelta( const char *file, unsigned line,
const char *xExpr, X x,
const char *yExpr, Y y,
const char *dExpr, D d,
const char *message )
{
if ( !delta( x, y, d ) ) {
if ( message )
tracker().failedTest( file, line, message );
tracker().failedAssertDelta( file, line, xExpr, yExpr, dExpr,
TS_AS_STRING(x), TS_AS_STRING(y), TS_AS_STRING(d) );
TS_ABORT();
}
}
void doFailAssertThrows( const char *file, unsigned line,
const char *expr, const char *type,
bool otherThrown,
const char *message );
void doFailAssertThrowsNot( const char *file, unsigned line,
const char *expression, const char *message );
# ifdef _CXXTEST_HAVE_EH
# define _TS_TRY try
# define _TS_CATCH_TYPE(t, b) catch t b
# define _TS_CATCH_ABORT(b) _TS_CATCH_TYPE( (const CxxTest::AbortTest &), b )
# define _TS_LAST_CATCH(b) _TS_CATCH_TYPE( (...), b )
# define _TSM_LAST_CATCH(f,l,m) _TS_LAST_CATCH( { (CxxTest::tracker()).failedTest(f,l,m); } )
# ifdef _CXXTEST_HAVE_STD
# define ___TSM_CATCH(f,l,m) \
catch(const std::exception &e) { (CxxTest::tracker()).failedTest(f,l,e.what()); } \
_TSM_LAST_CATCH(f,l,m)
# else // !_CXXTEST_HAVE_STD
# define ___TSM_CATCH(f,l,m) _TSM_LAST_CATCH(f,l,m)
# endif // _CXXTEST_HAVE_STD
# define __TSM_CATCH(f,l,m) \
_TS_CATCH_ABORT( { throw; } ) \
___TSM_CATCH(f,l,m)
# define __TS_CATCH(f,l) __TSM_CATCH(f,l,"Unhandled exception")
# define _TS_CATCH __TS_CATCH(__FILE__,__LINE__)
# else // !_CXXTEST_HAVE_EH
# define _TS_TRY
# define ___TSM_CATCH(f,l,m)
# define __TSM_CATCH(f,l,m)
# define __TS_CATCH(f,l)
# define _TS_CATCH
# define _TS_CATCH_TYPE(t, b)
# define _TS_LAST_CATCH(b)
# define _TS_CATCH_ABORT(b)
# endif // _CXXTEST_HAVE_EH
// TS_TRACE
# define _TS_TRACE(f,l,e) CxxTest::doTrace( (f), (l), TS_AS_STRING(e) )
# define TS_TRACE(e) _TS_TRACE( __FILE__, __LINE__, e )
// TS_WARN
# define _TS_WARN(f,l,e) CxxTest::doWarn( (f), (l), TS_AS_STRING(e) )
# define TS_WARN(e) _TS_WARN( __FILE__, __LINE__, e )
// TS_FAIL
# define _TS_FAIL(f,l,e) CxxTest::doFailTest( (f), (l), TS_AS_STRING(e) )
# define TS_FAIL(e) _TS_FAIL( __FILE__, __LINE__, e )
// TS_ASSERT
# define ___ETS_ASSERT(f,l,e,m) { if ( !(e) ) CxxTest::doFailAssert( (f), (l), #e, (m) ); }
# define ___TS_ASSERT(f,l,e,m) { _TS_TRY { ___ETS_ASSERT(f,l,e,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT(f,l,e) ___ETS_ASSERT(f,l,e,0)
# define _TS_ASSERT(f,l,e) ___TS_ASSERT(f,l,e,0)
# define ETS_ASSERT(e) _ETS_ASSERT(__FILE__,__LINE__,e)
# define TS_ASSERT(e) _TS_ASSERT(__FILE__,__LINE__,e)
# define _ETSM_ASSERT(f,l,m,e) ___ETS_ASSERT(f,l,e,TS_AS_STRING(m) )
# define _TSM_ASSERT(f,l,m,e) ___TS_ASSERT(f,l,e,TS_AS_STRING(m) )
# define ETSM_ASSERT(m,e) _ETSM_ASSERT(__FILE__,__LINE__,m,e)
# define TSM_ASSERT(m,e) _TSM_ASSERT(__FILE__,__LINE__,m,e)
// TS_ASSERT_EQUALS
# define ___ETS_ASSERT_EQUALS(f,l,x,y,m) CxxTest::doAssertEquals( (f), (l), #x, (x), #y, (y), (m) )
# define ___TS_ASSERT_EQUALS(f,l,x,y,m) { _TS_TRY { ___ETS_ASSERT_EQUALS(f,l,x,y,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT_EQUALS(f,l,x,y) ___ETS_ASSERT_EQUALS(f,l,x,y,0)
# define _TS_ASSERT_EQUALS(f,l,x,y) ___TS_ASSERT_EQUALS(f,l,x,y,0)
# define ETS_ASSERT_EQUALS(x,y) _ETS_ASSERT_EQUALS(__FILE__,__LINE__,x,y)
# define TS_ASSERT_EQUALS(x,y) _TS_ASSERT_EQUALS(__FILE__,__LINE__,x,y)
# define _ETSM_ASSERT_EQUALS(f,l,m,x,y) ___ETS_ASSERT_EQUALS(f,l,x,y,TS_AS_STRING(m))
# define _TSM_ASSERT_EQUALS(f,l,m,x,y) ___TS_ASSERT_EQUALS(f,l,x,y,TS_AS_STRING(m))
# define ETSM_ASSERT_EQUALS(m,x,y) _ETSM_ASSERT_EQUALS(__FILE__,__LINE__,m,x,y)
# define TSM_ASSERT_EQUALS(m,x,y) _TSM_ASSERT_EQUALS(__FILE__,__LINE__,m,x,y)
// TS_ASSERT_SAME_DATA
# define ___ETS_ASSERT_SAME_DATA(f,l,x,y,s,m) CxxTest::doAssertSameData( (f), (l), #x, (x), #y, (y), #s, (s), (m) )
# define ___TS_ASSERT_SAME_DATA(f,l,x,y,s,m) { _TS_TRY { ___ETS_ASSERT_SAME_DATA(f,l,x,y,s,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT_SAME_DATA(f,l,x,y,s) ___ETS_ASSERT_SAME_DATA(f,l,x,y,s,0)
# define _TS_ASSERT_SAME_DATA(f,l,x,y,s) ___TS_ASSERT_SAME_DATA(f,l,x,y,s,0)
# define ETS_ASSERT_SAME_DATA(x,y,s) _ETS_ASSERT_SAME_DATA(__FILE__,__LINE__,x,y,s)
# define TS_ASSERT_SAME_DATA(x,y,s) _TS_ASSERT_SAME_DATA(__FILE__,__LINE__,x,y,s)
# define _ETSM_ASSERT_SAME_DATA(f,l,m,x,y,s) ___ETS_ASSERT_SAME_DATA(f,l,x,y,s,TS_AS_STRING(m))
# define _TSM_ASSERT_SAME_DATA(f,l,m,x,y,s) ___TS_ASSERT_SAME_DATA(f,l,x,y,s,TS_AS_STRING(m))
# define ETSM_ASSERT_SAME_DATA(m,x,y,s) _ETSM_ASSERT_SAME_DATA(__FILE__,__LINE__,m,x,y,s)
# define TSM_ASSERT_SAME_DATA(m,x,y,s) _TSM_ASSERT_SAME_DATA(__FILE__,__LINE__,m,x,y,s)
// TS_ASSERT_DIFFERS
# define ___ETS_ASSERT_DIFFERS(f,l,x,y,m) CxxTest::doAssertDiffers( (f), (l), #x, (x), #y, (y), (m) )
# define ___TS_ASSERT_DIFFERS(f,l,x,y,m) { _TS_TRY { ___ETS_ASSERT_DIFFERS(f,l,x,y,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT_DIFFERS(f,l,x,y) ___ETS_ASSERT_DIFFERS(f,l,x,y,0)
# define _TS_ASSERT_DIFFERS(f,l,x,y) ___TS_ASSERT_DIFFERS(f,l,x,y,0)
# define ETS_ASSERT_DIFFERS(x,y) _ETS_ASSERT_DIFFERS(__FILE__,__LINE__,x,y)
# define TS_ASSERT_DIFFERS(x,y) _TS_ASSERT_DIFFERS(__FILE__,__LINE__,x,y)
# define _ETSM_ASSERT_DIFFERS(f,l,m,x,y) ___ETS_ASSERT_DIFFERS(f,l,x,y,TS_AS_STRING(m))
# define _TSM_ASSERT_DIFFERS(f,l,m,x,y) ___TS_ASSERT_DIFFERS(f,l,x,y,TS_AS_STRING(m))
# define ETSM_ASSERT_DIFFERS(m,x,y) _ETSM_ASSERT_DIFFERS(__FILE__,__LINE__,m,x,y)
# define TSM_ASSERT_DIFFERS(m,x,y) _TSM_ASSERT_DIFFERS(__FILE__,__LINE__,m,x,y)
// TS_ASSERT_LESS_THAN
# define ___ETS_ASSERT_LESS_THAN(f,l,x,y,m) CxxTest::doAssertLessThan( (f), (l), #x, (x), #y, (y), (m) )
# define ___TS_ASSERT_LESS_THAN(f,l,x,y,m) { _TS_TRY { ___ETS_ASSERT_LESS_THAN(f,l,x,y,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT_LESS_THAN(f,l,x,y) ___ETS_ASSERT_LESS_THAN(f,l,x,y,0)
# define _TS_ASSERT_LESS_THAN(f,l,x,y) ___TS_ASSERT_LESS_THAN(f,l,x,y,0)
# define ETS_ASSERT_LESS_THAN(x,y) _ETS_ASSERT_LESS_THAN(__FILE__,__LINE__,x,y)
# define TS_ASSERT_LESS_THAN(x,y) _TS_ASSERT_LESS_THAN(__FILE__,__LINE__,x,y)
# define _ETSM_ASSERT_LESS_THAN(f,l,m,x,y) ___ETS_ASSERT_LESS_THAN(f,l,x,y,TS_AS_STRING(m))
# define _TSM_ASSERT_LESS_THAN(f,l,m,x,y) ___TS_ASSERT_LESS_THAN(f,l,x,y,TS_AS_STRING(m))
# define ETSM_ASSERT_LESS_THAN(m,x,y) _ETSM_ASSERT_LESS_THAN(__FILE__,__LINE__,m,x,y)
# define TSM_ASSERT_LESS_THAN(m,x,y) _TSM_ASSERT_LESS_THAN(__FILE__,__LINE__,m,x,y)
// TS_ASSERT_LESS_THAN_EQUALS
# define ___ETS_ASSERT_LESS_THAN_EQUALS(f,l,x,y,m) \
CxxTest::doAssertLessThanEquals( (f), (l), #x, (x), #y, (y), (m) )
# define ___TS_ASSERT_LESS_THAN_EQUALS(f,l,x,y,m) \
{ _TS_TRY { ___ETS_ASSERT_LESS_THAN_EQUALS(f,l,x,y,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT_LESS_THAN_EQUALS(f,l,x,y) ___ETS_ASSERT_LESS_THAN_EQUALS(f,l,x,y,0)
# define _TS_ASSERT_LESS_THAN_EQUALS(f,l,x,y) ___TS_ASSERT_LESS_THAN_EQUALS(f,l,x,y,0)
# define ETS_ASSERT_LESS_THAN_EQUALS(x,y) _ETS_ASSERT_LESS_THAN_EQUALS(__FILE__,__LINE__,x,y)
# define TS_ASSERT_LESS_THAN_EQUALS(x,y) _TS_ASSERT_LESS_THAN_EQUALS(__FILE__,__LINE__,x,y)
# define _ETSM_ASSERT_LESS_THAN_EQUALS(f,l,m,x,y) ___ETS_ASSERT_LESS_THAN_EQUALS(f,l,x,y,TS_AS_STRING(m))
# define _TSM_ASSERT_LESS_THAN_EQUALS(f,l,m,x,y) ___TS_ASSERT_LESS_THAN_EQUALS(f,l,x,y,TS_AS_STRING(m))
# define ETSM_ASSERT_LESS_THAN_EQUALS(m,x,y) _ETSM_ASSERT_LESS_THAN_EQUALS(__FILE__,__LINE__,m,x,y)
# define TSM_ASSERT_LESS_THAN_EQUALS(m,x,y) _TSM_ASSERT_LESS_THAN_EQUALS(__FILE__,__LINE__,m,x,y)
// TS_ASSERT_PREDICATE
# define ___ETS_ASSERT_PREDICATE(f,l,p,x,m) \
CxxTest::doAssertPredicate( (f), (l), #p, p(), #x, (x), (m) )
# define ___TS_ASSERT_PREDICATE(f,l,p,x,m) \
{ _TS_TRY { ___ETS_ASSERT_PREDICATE(f,l,p,x,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT_PREDICATE(f,l,p,x) ___ETS_ASSERT_PREDICATE(f,l,p,x,0)
# define _TS_ASSERT_PREDICATE(f,l,p,x) ___TS_ASSERT_PREDICATE(f,l,p,x,0)
# define ETS_ASSERT_PREDICATE(p,x) _ETS_ASSERT_PREDICATE(__FILE__,__LINE__,p,x)
# define TS_ASSERT_PREDICATE(p,x) _TS_ASSERT_PREDICATE(__FILE__,__LINE__,p,x)
# define _ETSM_ASSERT_PREDICATE(f,l,m,p,x) ___ETS_ASSERT_PREDICATE(f,l,p,x,TS_AS_STRING(m))
# define _TSM_ASSERT_PREDICATE(f,l,m,p,x) ___TS_ASSERT_PREDICATE(f,l,p,x,TS_AS_STRING(m))
# define ETSM_ASSERT_PREDICATE(m,p,x) _ETSM_ASSERT_PREDICATE(__FILE__,__LINE__,m,p,x)
# define TSM_ASSERT_PREDICATE(m,p,x) _TSM_ASSERT_PREDICATE(__FILE__,__LINE__,m,p,x)
// TS_ASSERT_RELATION
# define ___ETS_ASSERT_RELATION(f,l,r,x,y,m) \
CxxTest::doAssertRelation( (f), (l), #r, r(), #x, (x), #y, (y), (m) )
# define ___TS_ASSERT_RELATION(f,l,r,x,y,m) \
{ _TS_TRY { ___ETS_ASSERT_RELATION(f,l,r,x,y,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT_RELATION(f,l,r,x,y) ___ETS_ASSERT_RELATION(f,l,r,x,y,0)
# define _TS_ASSERT_RELATION(f,l,r,x,y) ___TS_ASSERT_RELATION(f,l,r,x,y,0)
# define ETS_ASSERT_RELATION(r,x,y) _ETS_ASSERT_RELATION(__FILE__,__LINE__,r,x,y)
# define TS_ASSERT_RELATION(r,x,y) _TS_ASSERT_RELATION(__FILE__,__LINE__,r,x,y)
# define _ETSM_ASSERT_RELATION(f,l,m,r,x,y) ___ETS_ASSERT_RELATION(f,l,r,x,y,TS_AS_STRING(m))
# define _TSM_ASSERT_RELATION(f,l,m,r,x,y) ___TS_ASSERT_RELATION(f,l,r,x,y,TS_AS_STRING(m))
# define ETSM_ASSERT_RELATION(m,r,x,y) _ETSM_ASSERT_RELATION(__FILE__,__LINE__,m,r,x,y)
# define TSM_ASSERT_RELATION(m,r,x,y) _TSM_ASSERT_RELATION(__FILE__,__LINE__,m,r,x,y)
// TS_ASSERT_DELTA
# define ___ETS_ASSERT_DELTA(f,l,x,y,d,m) CxxTest::doAssertDelta( (f), (l), #x, (x), #y, (y), #d, (d), (m) )
# define ___TS_ASSERT_DELTA(f,l,x,y,d,m) { _TS_TRY { ___ETS_ASSERT_DELTA(f,l,x,y,d,m); } __TS_CATCH(f,l) }
# define _ETS_ASSERT_DELTA(f,l,x,y,d) ___ETS_ASSERT_DELTA(f,l,x,y,d,0)
# define _TS_ASSERT_DELTA(f,l,x,y,d) ___TS_ASSERT_DELTA(f,l,x,y,d,0)
# define ETS_ASSERT_DELTA(x,y,d) _ETS_ASSERT_DELTA(__FILE__,__LINE__,x,y,d)
# define TS_ASSERT_DELTA(x,y,d) _TS_ASSERT_DELTA(__FILE__,__LINE__,x,y,d)
# define _ETSM_ASSERT_DELTA(f,l,m,x,y,d) ___ETS_ASSERT_DELTA(f,l,x,y,d,TS_AS_STRING(m))
# define _TSM_ASSERT_DELTA(f,l,m,x,y,d) ___TS_ASSERT_DELTA(f,l,x,y,d,TS_AS_STRING(m))
# define ETSM_ASSERT_DELTA(m,x,y,d) _ETSM_ASSERT_DELTA(__FILE__,__LINE__,m,x,y,d)
# define TSM_ASSERT_DELTA(m,x,y,d) _TSM_ASSERT_DELTA(__FILE__,__LINE__,m,x,y,d)
// TS_ASSERT_THROWS
# define ___TS_ASSERT_THROWS(f,l,e,t,m) { \
bool _ts_threw_expected = false, _ts_threw_else = false; \
_TS_TRY { e; } \
_TS_CATCH_TYPE( (t), { _ts_threw_expected = true; } ) \
_TS_CATCH_ABORT( { throw; } ) \
_TS_LAST_CATCH( { _ts_threw_else = true; } ) \
if ( !_ts_threw_expected ) { CxxTest::doFailAssertThrows( (f), (l), #e, #t, _ts_threw_else, (m) ); } }
# define _TS_ASSERT_THROWS(f,l,e,t) ___TS_ASSERT_THROWS(f,l,e,t,0)
# define TS_ASSERT_THROWS(e,t) _TS_ASSERT_THROWS(__FILE__,__LINE__,e,t)
# define _TSM_ASSERT_THROWS(f,l,m,e,t) ___TS_ASSERT_THROWS(f,l,e,t,TS_AS_STRING(m))
# define TSM_ASSERT_THROWS(m,e,t) _TSM_ASSERT_THROWS(__FILE__,__LINE__,m,e,t)
// TS_ASSERT_THROWS_ASSERT
# define ___TS_ASSERT_THROWS_ASSERT(f,l,e,t,a,m) { \
bool _ts_threw_expected = false, _ts_threw_else = false; \
_TS_TRY { e; } \
_TS_CATCH_TYPE( (t), { a; _ts_threw_expected = true; } ) \
_TS_CATCH_ABORT( { throw; } ) \
_TS_LAST_CATCH( { _ts_threw_else = true; } ) \
if ( !_ts_threw_expected ) { CxxTest::doFailAssertThrows( (f), (l), #e, #t, _ts_threw_else, (m) ); } }
# define _TS_ASSERT_THROWS_ASSERT(f,l,e,t,a) ___TS_ASSERT_THROWS_ASSERT(f,l,e,t,a,0)
# define TS_ASSERT_THROWS_ASSERT(e,t,a) _TS_ASSERT_THROWS_ASSERT(__FILE__,__LINE__,e,t,a)
# define _TSM_ASSERT_THROWS_ASSERT(f,l,m,e,t,a) ___TS_ASSERT_THROWS_ASSERT(f,l,e,t,a,TS_AS_STRING(m))
# define TSM_ASSERT_THROWS_ASSERT(m,e,t,a) _TSM_ASSERT_THROWS_ASSERT(__FILE__,__LINE__,m,e,t,a)
// TS_ASSERT_THROWS_EQUALS
# define TS_ASSERT_THROWS_EQUALS(e,t,x,y) TS_ASSERT_THROWS_ASSERT(e,t,TS_ASSERT_EQUALS(x,y))
# define TSM_ASSERT_THROWS_EQUALS(m,e,t,x,y) TSM_ASSERT_THROWS_ASSERT(m,e,t,TSM_ASSERT_EQUALS(m,x,y))
// TS_ASSERT_THROWS_DIFFERS
# define TS_ASSERT_THROWS_DIFFERS(e,t,x,y) TS_ASSERT_THROWS_ASSERT(e,t,TS_ASSERT_DIFFERS(x,y))
# define TSM_ASSERT_THROWS_DIFFERS(m,e,t,x,y) TSM_ASSERT_THROWS_ASSERT(m,e,t,TSM_ASSERT_DIFFERS(m,x,y))
// TS_ASSERT_THROWS_DELTA
# define TS_ASSERT_THROWS_DELTA(e,t,x,y,d) TS_ASSERT_THROWS_ASSERT(e,t,TS_ASSERT_DELTA(x,y,d))
# define TSM_ASSERT_THROWS_DELTA(m,e,t,x,y,d) TSM_ASSERT_THROWS_ASSERT(m,e,t,TSM_ASSERT_DELTA(m,x,y,d))
// TS_ASSERT_THROWS_SAME_DATA
# define TS_ASSERT_THROWS_SAME_DATA(e,t,x,y,s) TS_ASSERT_THROWS_ASSERT(e,t,TS_ASSERT_SAME_DATA(x,y,s))
# define TSM_ASSERT_THROWS_SAME_DATA(m,e,t,x,y,s) TSM_ASSERT_THROWS_ASSERT(m,e,t,TSM_ASSERT_SAME_DATA(m,x,y,s))
// TS_ASSERT_THROWS_LESS_THAN
# define TS_ASSERT_THROWS_LESS_THAN(e,t,x,y) TS_ASSERT_THROWS_ASSERT(e,t,TS_ASSERT_LESS_THAN(x,y))
# define TSM_ASSERT_THROWS_LESS_THAN(m,e,t,x,y) TSM_ASSERT_THROWS_ASSERT(m,e,t,TSM_ASSERT_LESS_THAN(m,x,y))
// TS_ASSERT_THROWS_LESS_THAN_EQUALS
# define TS_ASSERT_THROWS_LESS_THAN_EQUALS(e,t,x,y) TS_ASSERT_THROWS_ASSERT(e,t,TS_ASSERT_LESS_THAN_EQUALS(x,y))
# define TSM_ASSERT_THROWS_LESS_THAN_EQUALS(m,e,t,x,y) TSM_ASSERT_THROWS_ASSERT(m,e,t,TSM_ASSERT_LESS_THAN_EQUALS(m,x,y))
// TS_ASSERT_THROWS_PREDICATE
# define TS_ASSERT_THROWS_PREDICATE(e,t,p,v) TS_ASSERT_THROWS_ASSERT(e,t,TS_ASSERT_PREDICATE(p,v))
# define TSM_ASSERT_THROWS_PREDICATE(m,e,t,p,v) TSM_ASSERT_THROWS_ASSERT(m,e,t,TSM_ASSERT_PREDICATE(m,p,v))
// TS_ASSERT_THROWS_RELATION
# define TS_ASSERT_THROWS_RELATION(e,t,r,x,y) TS_ASSERT_THROWS_ASSERT(e,t,TS_ASSERT_RELATION(r,x,y))
# define TSM_ASSERT_THROWS_RELATION(m,e,t,r,x,y) TSM_ASSERT_THROWS_ASSERT(m,e,t,TSM_ASSERT_RELATION(m,r,x,y))
// TS_ASSERT_THROWS_ANYTHING
# define ___TS_ASSERT_THROWS_ANYTHING(f,l,e,m) { \
bool _ts_threw = false; \
_TS_TRY { e; } \
_TS_LAST_CATCH( { _ts_threw = true; } ) \
if ( !_ts_threw ) { CxxTest::doFailAssertThrows( (f), (l), #e, "...", false, (m) ); } }
# define _TS_ASSERT_THROWS_ANYTHING(f,l,e) ___TS_ASSERT_THROWS_ANYTHING(f,l,e,0)
# define TS_ASSERT_THROWS_ANYTHING(e) _TS_ASSERT_THROWS_ANYTHING(__FILE__, __LINE__, e)
# define _TSM_ASSERT_THROWS_ANYTHING(f,l,m,e) ___TS_ASSERT_THROWS_ANYTHING(f,l,e,TS_AS_STRING(m))
# define TSM_ASSERT_THROWS_ANYTHING(m,e) _TSM_ASSERT_THROWS_ANYTHING(__FILE__,__LINE__,m,e)
// TS_ASSERT_THROWS_NOTHING
# define ___TS_ASSERT_THROWS_NOTHING(f,l,e,m) { \
_TS_TRY { e; } \
_TS_CATCH_ABORT( { throw; } ) \
_TS_LAST_CATCH( { CxxTest::doFailAssertThrowsNot( (f), (l), #e, (m) ); } ) }
# define _TS_ASSERT_THROWS_NOTHING(f,l,e) ___TS_ASSERT_THROWS_NOTHING(f,l,e,0)
# define TS_ASSERT_THROWS_NOTHING(e) _TS_ASSERT_THROWS_NOTHING(__FILE__,__LINE__,e)
# define _TSM_ASSERT_THROWS_NOTHING(f,l,m,e) ___TS_ASSERT_THROWS_NOTHING(f,l,e,TS_AS_STRING(m))
# define TSM_ASSERT_THROWS_NOTHING(m,e) _TSM_ASSERT_THROWS_NOTHING(__FILE__,__LINE__,m,e)
//
// This takes care of "signed <-> unsigned" warnings
//
# define CXXTEST_COMPARISONS(CXXTEST_X, CXXTEST_Y, CXXTEST_T) \
inline bool equals( CXXTEST_X x, CXXTEST_Y y ) { return (((CXXTEST_T)x) == ((CXXTEST_T)y)); } \
inline bool equals( CXXTEST_Y y, CXXTEST_X x ) { return (((CXXTEST_T)y) == ((CXXTEST_T)x)); } \
inline bool differs( CXXTEST_X x, CXXTEST_Y y ) { return (((CXXTEST_T)x) != ((CXXTEST_T)y)); } \
inline bool differs( CXXTEST_Y y, CXXTEST_X x ) { return (((CXXTEST_T)y) != ((CXXTEST_T)x)); } \
inline bool lessThan( CXXTEST_X x, CXXTEST_Y y ) { return (((CXXTEST_T)x) < ((CXXTEST_T)y)); } \
inline bool lessThan( CXXTEST_Y y, CXXTEST_X x ) { return (((CXXTEST_T)y) < ((CXXTEST_T)x)); } \
inline bool lessThanEquals( CXXTEST_X x, CXXTEST_Y y ) { return (((CXXTEST_T)x) <= ((CXXTEST_T)y)); } \
inline bool lessThanEquals( CXXTEST_Y y, CXXTEST_X x ) { return (((CXXTEST_T)y) <= ((CXXTEST_T)x)); }
# define CXXTEST_INTEGRAL(CXXTEST_T) \
CXXTEST_COMPARISONS( signed CXXTEST_T, unsigned CXXTEST_T, unsigned CXXTEST_T )
CXXTEST_INTEGRAL( char )
CXXTEST_INTEGRAL( short )
CXXTEST_INTEGRAL( int )
CXXTEST_INTEGRAL( long )
# ifdef _CXXTEST_LONGLONG
CXXTEST_INTEGRAL( _CXXTEST_LONGLONG )
# endif // _CXXTEST_LONGLONG
# define CXXTEST_SMALL_BIG(CXXTEST_SMALL, CXXTEST_BIG) \
CXXTEST_COMPARISONS( signed CXXTEST_SMALL, unsigned CXXTEST_BIG, unsigned CXXTEST_BIG ) \
CXXTEST_COMPARISONS( signed CXXTEST_BIG, unsigned CXXTEST_SMALL, unsigned CXXTEST_BIG )
CXXTEST_SMALL_BIG( char, short )
CXXTEST_SMALL_BIG( char, int )
CXXTEST_SMALL_BIG( short, int )
CXXTEST_SMALL_BIG( char, long )
CXXTEST_SMALL_BIG( short, long )
CXXTEST_SMALL_BIG( int, long )
# ifdef _CXXTEST_LONGLONG
CXXTEST_SMALL_BIG( char, _CXXTEST_LONGLONG )
CXXTEST_SMALL_BIG( short, _CXXTEST_LONGLONG )
CXXTEST_SMALL_BIG( int, _CXXTEST_LONGLONG )
CXXTEST_SMALL_BIG( long, _CXXTEST_LONGLONG )
# endif // _CXXTEST_LONGLONG
}
#endif // __cxxtest__TestSuite_h__

View File

@@ -0,0 +1,248 @@
#ifndef __cxxtest__TestTracker_cpp__
#define __cxxtest__TestTracker_cpp__
#include <cxxtest/TestTracker.h>
namespace CxxTest
{
bool TestTracker::_created = false;
TestTracker::TestTracker()
{
if ( !_created ) {
initialize();
_created = true;
}
}
TestTracker::~TestTracker()
{
}
TestTracker & TestTracker::tracker()
{
static TestTracker theTracker;
return theTracker;
}
void TestTracker::initialize()
{
_warnings = 0;
_failedTests = 0;
_testFailedAsserts = 0;
_suiteFailedTests = 0;
_failedSuites = 0;
setListener( 0 );
_world = 0;
_suite = 0;
_test = 0;
}
const TestDescription *TestTracker::fixTest( const TestDescription *d ) const
{
return d ? d : &dummyTest();
}
const SuiteDescription *TestTracker::fixSuite( const SuiteDescription *d ) const
{
return d ? d : &dummySuite();
}
const WorldDescription *TestTracker::fixWorld( const WorldDescription *d ) const
{
return d ? d : &dummyWorld();
}
const TestDescription &TestTracker::dummyTest() const
{
return dummySuite().testDescription(0);
}
const SuiteDescription &TestTracker::dummySuite() const
{
return dummyWorld().suiteDescription(0);
}
const WorldDescription &TestTracker::dummyWorld() const
{
return _dummyWorld;
}
void TestTracker::setListener( TestListener *l )
{
_l = l ? l : &_dummyListener;
}
void TestTracker::enterWorld( const WorldDescription &wd )
{
setWorld( &wd );
_warnings = _failedTests = _testFailedAsserts = _suiteFailedTests = _failedSuites = 0;
_l->enterWorld( wd );
}
void TestTracker::enterSuite( const SuiteDescription &sd )
{
setSuite( &sd );
_testFailedAsserts = _suiteFailedTests = 0;
_l->enterSuite(sd);
}
void TestTracker::enterTest( const TestDescription &td )
{
setTest( &td );
_testFailedAsserts = false;
_l->enterTest(td);
}
void TestTracker::leaveTest( const TestDescription &td )
{
_l->leaveTest( td );
setTest( 0 );
}
void TestTracker::leaveSuite( const SuiteDescription &sd )
{
_l->leaveSuite( sd );
setSuite( 0 );
}
void TestTracker::leaveWorld( const WorldDescription &wd )
{
_l->leaveWorld( wd );
setWorld( 0 );
}
void TestTracker::trace( const char *file, unsigned line, const char *expression )
{
_l->trace( file, line, expression );
}
void TestTracker::warning( const char *file, unsigned line, const char *expression )
{
countWarning();
_l->warning( file, line, expression );
}
void TestTracker::failedTest( const char *file, unsigned line, const char *expression )
{
countFailure();
_l->failedTest( file, line, expression );
}
void TestTracker::failedAssert( const char *file, unsigned line, const char *expression )
{
countFailure();
_l->failedAssert( file, line, expression );
}
void TestTracker::failedAssertEquals( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
countFailure();
_l->failedAssertEquals( file, line, xStr, yStr, x, y );
}
void TestTracker::failedAssertSameData( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *sizeStr, const void *x,
const void *y, unsigned size )
{
countFailure();
_l->failedAssertSameData( file, line, xStr, yStr, sizeStr, x, y, size );
}
void TestTracker::failedAssertDelta( const char *file, unsigned line,
const char *xStr, const char *yStr, const char *dStr,
const char *x, const char *y, const char *d )
{
countFailure();
_l->failedAssertDelta( file, line, xStr, yStr, dStr, x, y, d );
}
void TestTracker::failedAssertDiffers( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *value )
{
countFailure();
_l->failedAssertDiffers( file, line, xStr, yStr, value );
}
void TestTracker::failedAssertLessThan( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
countFailure();
_l->failedAssertLessThan( file, line, xStr, yStr, x, y );
}
void TestTracker::failedAssertLessThanEquals( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y )
{
countFailure();
_l->failedAssertLessThanEquals( file, line, xStr, yStr, x, y );
}
void TestTracker::failedAssertPredicate( const char *file, unsigned line,
const char *predicate, const char *xStr, const char *x )
{
countFailure();
_l->failedAssertPredicate( file, line, predicate, xStr, x );
}
void TestTracker::failedAssertRelation( const char *file, unsigned line,
const char *relation, const char *xStr, const char *yStr,
const char *x, const char *y )
{
countFailure();
_l->failedAssertRelation( file, line, relation, xStr, yStr, x, y );
}
void TestTracker::failedAssertThrows( const char *file, unsigned line,
const char *expression, const char *type,
bool otherThrown )
{
countFailure();
_l->failedAssertThrows( file, line, expression, type, otherThrown );
}
void TestTracker::failedAssertThrowsNot( const char *file, unsigned line, const char *expression )
{
countFailure();
_l->failedAssertThrowsNot( file, line, expression );
}
void TestTracker::setWorld( const WorldDescription *w )
{
_world = fixWorld( w );
setSuite( 0 );
}
void TestTracker::setSuite( const SuiteDescription *s )
{
_suite = fixSuite( s );
setTest( 0 );
}
void TestTracker::setTest( const TestDescription *t )
{
_test = fixTest( t );
}
void TestTracker::countWarning()
{
++ _warnings;
}
void TestTracker::countFailure()
{
if ( ++ _testFailedAsserts == 1 ) {
++ _failedTests;
if ( ++ _suiteFailedTests == 1 )
++ _failedSuites;
}
}
}
#endif // __cxxtest__TestTracker_cpp__

View File

@@ -0,0 +1,114 @@
#ifndef __cxxtest__TestTracker_h__
#define __cxxtest__TestTracker_h__
//
// The TestTracker tracks running tests
// The actual work is done in CountingListenerProxy,
// but this way avoids cyclic references TestListener<->CountingListenerProxy
//
#include <cxxtest/TestListener.h>
#include <cxxtest/DummyDescriptions.h>
namespace CxxTest
{
class TestListener;
class TestTracker : public TestListener
{
public:
virtual ~TestTracker();
static TestTracker &tracker();
const TestDescription *fixTest( const TestDescription *d ) const;
const SuiteDescription *fixSuite( const SuiteDescription *d ) const;
const WorldDescription *fixWorld( const WorldDescription *d ) const;
const TestDescription &test() const { return *_test; }
const SuiteDescription &suite() const { return *_suite; }
const WorldDescription &world() const { return *_world; }
bool testFailed() const { return (testFailedAsserts() > 0); }
bool suiteFailed() const { return (suiteFailedTests() > 0); }
bool worldFailed() const { return (failedSuites() > 0); }
unsigned warnings() const { return _warnings; }
unsigned failedTests() const { return _failedTests; }
unsigned testFailedAsserts() const { return _testFailedAsserts; }
unsigned suiteFailedTests() const { return _suiteFailedTests; }
unsigned failedSuites() const { return _failedSuites; }
void enterWorld( const WorldDescription &wd );
void enterSuite( const SuiteDescription &sd );
void enterTest( const TestDescription &td );
void leaveTest( const TestDescription &td );
void leaveSuite( const SuiteDescription &sd );
void leaveWorld( const WorldDescription &wd );
void trace( const char *file, unsigned line, const char *expression );
void warning( const char *file, unsigned line, const char *expression );
void failedTest( const char *file, unsigned line, const char *expression );
void failedAssert( const char *file, unsigned line, const char *expression );
void failedAssertEquals( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y );
void failedAssertSameData( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *sizeStr, const void *x,
const void *y, unsigned size );
void failedAssertDelta( const char *file, unsigned line,
const char *xStr, const char *yStr, const char *dStr,
const char *x, const char *y, const char *d );
void failedAssertDiffers( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *value );
void failedAssertLessThan( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y );
void failedAssertLessThanEquals( const char *file, unsigned line,
const char *xStr, const char *yStr,
const char *x, const char *y );
void failedAssertPredicate( const char *file, unsigned line,
const char *predicate, const char *xStr, const char *x );
void failedAssertRelation( const char *file, unsigned line,
const char *relation, const char *xStr, const char *yStr,
const char *x, const char *y );
void failedAssertThrows( const char *file, unsigned line,
const char *expression, const char *type,
bool otherThrown );
void failedAssertThrowsNot( const char *file, unsigned line, const char *expression );
private:
TestTracker( const TestTracker & );
TestTracker &operator=( const TestTracker & );
static bool _created;
TestListener _dummyListener;
DummyWorldDescription _dummyWorld;
unsigned _warnings, _failedTests, _testFailedAsserts, _suiteFailedTests, _failedSuites;
TestListener *_l;
const WorldDescription *_world;
const SuiteDescription *_suite;
const TestDescription *_test;
const TestDescription &dummyTest() const;
const SuiteDescription &dummySuite() const;
const WorldDescription &dummyWorld() const;
void setWorld( const WorldDescription *w );
void setSuite( const SuiteDescription *s );
void setTest( const TestDescription *t );
void countWarning();
void countFailure();
friend class TestRunner;
TestTracker();
void initialize();
void setListener( TestListener *l );
};
inline TestTracker &tracker() { return TestTracker::tracker(); }
}
#endif // __cxxtest__TestTracker_h__

View File

@@ -0,0 +1,140 @@
#ifndef __cxxtest__ValueTraits_cpp__
#define __cxxtest__ValueTraits_cpp__
#include <cxxtest/ValueTraits.h>
namespace CxxTest
{
//
// Non-inline functions from ValueTraits.h
//
char digitToChar( unsigned digit )
{
if ( digit < 10 )
return (char)('0' + digit);
if ( digit <= 10 + 'Z' - 'A' )
return (char)('A' + digit - 10);
return '?';
}
const char *byteToHex( unsigned char byte )
{
static char asHex[3];
asHex[0] = digitToChar( byte >> 4 );
asHex[1] = digitToChar( byte & 0x0F );
asHex[2] = '\0';
return asHex;
}
char *copyString( char *dst, const char *src )
{
while ( (*dst = *src) != '\0' ) {
++ dst;
++ src;
}
return dst;
}
bool stringsEqual( const char *s1, const char *s2 )
{
char c;
while ( (c = *s1++) == *s2++ )
if ( c == '\0' )
return true;
return false;
}
char *charToString( unsigned long c, char *s )
{
switch( c ) {
case '\\': return copyString( s, "\\\\" );
case '\"': return copyString( s, "\\\"" );
case '\'': return copyString( s, "\\\'" );
case '\0': return copyString( s, "\\0" );
case '\a': return copyString( s, "\\a" );
case '\b': return copyString( s, "\\b" );
case '\n': return copyString( s, "\\n" );
case '\r': return copyString( s, "\\r" );
case '\t': return copyString( s, "\\t" );
}
if ( c >= 32 && c <= 127 ) {
s[0] = (char)c;
s[1] = '\0';
return s + 1;
}
else {
s[0] = '\\';
s[1] = 'x';
if ( c < 0x10 ) {
s[2] = '0';
++ s;
}
return numberToString( c, s + 2, 16UL );
}
}
char *charToString( char c, char *s )
{
return charToString( (unsigned long)(unsigned char)c, s );
}
char *bytesToString( const unsigned char *bytes, unsigned numBytes, unsigned maxBytes, char *s )
{
bool truncate = (numBytes > maxBytes);
if ( truncate )
numBytes = maxBytes;
s = copyString( s, "{ " );
for ( unsigned i = 0; i < numBytes; ++ i, ++ bytes )
s = copyString( copyString( s, byteToHex( *bytes ) ), " " );
if ( truncate )
s = copyString( s, "..." );
return copyString( s, " }" );
}
#ifndef CXXTEST_USER_VALUE_TRAITS
unsigned ValueTraits<const double>::requiredDigitsOnLeft( double t )
{
unsigned digits = 1;
for ( t = (t < 0.0) ? -t : t; t > 1.0; t /= BASE )
++ digits;
return digits;
}
char *ValueTraits<const double>::doNegative( double &t )
{
if ( t >= 0 )
return _asString;
_asString[0] = '-';
t = -t;
return _asString + 1;
}
void ValueTraits<const double>::hugeNumber( double t )
{
char *s = doNegative( t );
s = doubleToString( t, s, 0, 1 );
s = copyString( s, "." );
s = doubleToString( t, s, 1, DIGITS_ON_RIGHT );
s = copyString( s, "E" );
s = numberToString( requiredDigitsOnLeft( t ) - 1, s );
}
void ValueTraits<const double>::normalNumber( double t )
{
char *s = doNegative( t );
s = doubleToString( t, s );
s = copyString( s, "." );
for ( unsigned i = 0; i < DIGITS_ON_RIGHT; ++ i )
s = numberToString( (unsigned)(t *= BASE) % BASE, s );
}
char *ValueTraits<const double>::doubleToString( double t, char *s, unsigned skip, unsigned max )
{
return numberToString<double>( t, s, BASE, skip, max );
}
#endif // !CXXTEST_USER_VALUE_TRAITS
}
#endif // __cxxtest__ValueTraits_cpp__

View File

@@ -0,0 +1,386 @@
#ifndef __cxxtest__ValueTraits_h__
#define __cxxtest__ValueTraits_h__
//
// ValueTraits are used by CxxTest to convert arbitrary
// values used in TS_ASSERT_EQUALS() to a string representation.
//
// This header file contains value traits for builtin integral types.
// To declare value traits for new types you should instantiate the class
// ValueTraits<YourClass>.
//
#include <cxxtest/Flags.h>
#ifdef _CXXTEST_OLD_TEMPLATE_SYNTAX
# define CXXTEST_TEMPLATE_INSTANTIATION
#else // !_CXXTEST_OLD_TEMPLATE_SYNTAX
# define CXXTEST_TEMPLATE_INSTANTIATION template<>
#endif // _CXXTEST_OLD_TEMPLATE_SYNTAX
namespace CxxTest
{
/// remove_const
template<typename T>
struct remove_const
{ typedef T type; };
template<typename T>
struct remove_const<T const>
{ typedef T type; };
//
// This is how we use the value traits
//
# define TS_AS_STRING(x) CxxTest::traits(x).asString()
//
// Char representation of a digit
//
char digitToChar( unsigned digit );
//
// Convert byte value to hex digits
// Returns pointer to internal buffer
//
const char *byteToHex( unsigned char byte );
//
// Convert byte values to string
// Returns one past the copied data
//
char *bytesToString( const unsigned char *bytes, unsigned numBytes, unsigned maxBytes, char *s );
//
// Copy a string.
// Returns one past the end of the destination string
// Remember -- we can't use the standard library!
//
char *copyString( char *dst, const char *src );
//
// Compare two strings.
// Remember -- we can't use the standard library!
//
bool stringsEqual( const char *s1, const char *s2 );
//
// Represent a character value as a string
// Returns one past the end of the string
// This will be the actual char if printable or '\xXXXX' otherwise
//
char *charToString( unsigned long c, char *s );
//
// Prevent problems with negative (signed char)s
//
char *charToString( char c, char *s );
//
// The default ValueTraits class dumps up to 8 bytes as hex values
//
template<class T>
class ValueTraits
{
enum { MAX_BYTES = 8 };
char _asString[sizeof("{ ") + sizeof("XX ") * MAX_BYTES + sizeof("... }")];
public:
ValueTraits( const T &t ) { bytesToString( (const unsigned char *)&t, sizeof(T), MAX_BYTES, _asString ); }
const char *asString( void ) const { return _asString; }
};
//
// traits( T t )
// Creates an object of type ValueTraits<T>
//
template<class T>
inline ValueTraits<T> traits( T t )
{
return ValueTraits<T>( t );
}
//
// You can duplicate the implementation of an existing ValueTraits
//
# define CXXTEST_COPY_TRAITS(CXXTEST_NEW_CLASS, CXXTEST_OLD_CLASS) \
CXXTEST_TEMPLATE_INSTANTIATION \
class ValueTraits< CXXTEST_NEW_CLASS > \
{ \
ValueTraits< CXXTEST_OLD_CLASS > _old; \
public: \
ValueTraits( CXXTEST_NEW_CLASS n ) : _old( static_cast<remove_const<CXXTEST_OLD_CLASS>::type>(n) ) {} \
const char *asString( void ) const { return _old.asString(); } \
}
//
// Certain compilers need separate declarations for T and const T
//
# ifdef _CXXTEST_NO_COPY_CONST
# define CXXTEST_COPY_CONST_TRAITS(CXXTEST_CLASS)
# else // !_CXXTEST_NO_COPY_CONST
# define CXXTEST_COPY_CONST_TRAITS(CXXTEST_CLASS) CXXTEST_COPY_TRAITS(CXXTEST_CLASS, const CXXTEST_CLASS)
# endif // _CXXTEST_NO_COPY_CONST
//
// Avoid compiler warnings about unsigned types always >= 0
//
template<class N> inline bool negative( N n ) { return n < 0; }
template<class N> inline N abs( N n ) { return negative(n) ? -n : n; }
# define CXXTEST_NON_NEGATIVE(Type) \
CXXTEST_TEMPLATE_INSTANTIATION \
inline bool negative<Type>( Type ) { return false; } \
CXXTEST_TEMPLATE_INSTANTIATION \
inline Type abs<Type>( Type value ) { return value; }
CXXTEST_NON_NEGATIVE( bool )
CXXTEST_NON_NEGATIVE( unsigned char )
CXXTEST_NON_NEGATIVE( unsigned short int )
CXXTEST_NON_NEGATIVE( unsigned int )
CXXTEST_NON_NEGATIVE( unsigned long int )
# ifdef _CXXTEST_LONGLONG
CXXTEST_NON_NEGATIVE( unsigned _CXXTEST_LONGLONG )
# endif // _CXXTEST_LONGLONG
//
// Represent (integral) number as a string
// Returns one past the end of the string
// Remember -- we can't use the standard library!
//
template<class N>
char *numberToString( N n, char *s,
N base = 10,
unsigned skipDigits = 0,
unsigned maxDigits = (unsigned)-1 )
{
if ( negative(n) ) {
*s++ = '-';
n = abs(n);
}
N digit = 1;
while ( digit <= (n / base) )
digit *= base;
N digitValue;
for ( ; digit >= 1 && skipDigits; n -= digit * digitValue, digit /= base, -- skipDigits )
digitValue = (unsigned)(n / digit);
for ( ; digit >= 1 && maxDigits; n -= digit * digitValue, digit /= base, -- maxDigits )
*s++ = digitToChar( (unsigned)(digitValue = (unsigned)(n / digit)) );
*s = '\0';
return s;
}
//
// All the specific ValueTraits follow.
// You can #define CXXTEST_USER_VALUE_TRAITS if you don't want them
//
#ifndef CXXTEST_USER_VALUE_TRAITS
//
// ValueTraits: const char * const &
// This is used for printing strings, as in TS_FAIL( "Message" )
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const char * const &>
{
ValueTraits &operator=( const ValueTraits & );
const char *_asString;
public:
ValueTraits( const char * const &value ) : _asString( value ) {}
ValueTraits( const ValueTraits &other ) : _asString( other._asString ) {}
const char *asString( void ) const { return _asString; }
};
CXXTEST_COPY_TRAITS( const char *, const char * const & );
CXXTEST_COPY_TRAITS( char *, const char * const & );
//
// ValueTraits: bool
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const bool>
{
bool _value;
public:
ValueTraits( const bool value ) : _value( value ) {}
const char *asString( void ) const { return _value ? "true" : "false"; }
};
CXXTEST_COPY_CONST_TRAITS( bool );
# ifdef _CXXTEST_LONGLONG
//
// ValueTraits: signed long long
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const signed _CXXTEST_LONGLONG>
{
typedef _CXXTEST_LONGLONG T;
char _asString[2 + 3 * sizeof(T)];
public:
ValueTraits( T t ) { numberToString<T>( t, _asString ); }
const char *asString( void ) const { return _asString; }
};
CXXTEST_COPY_CONST_TRAITS( signed _CXXTEST_LONGLONG );
//
// ValueTraits: unsigned long long
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const unsigned _CXXTEST_LONGLONG>
{
typedef unsigned _CXXTEST_LONGLONG T;
char _asString[1 + 3 * sizeof(T)];
public:
ValueTraits( T t ) { numberToString<T>( t, _asString ); }
const char *asString( void ) const { return _asString; }
};
CXXTEST_COPY_CONST_TRAITS( unsigned _CXXTEST_LONGLONG );
# endif // _CXXTEST_LONGLONG
//
// ValueTraits: signed long
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const signed long int>
{
typedef signed long int T;
char _asString[2 + 3 * sizeof(T)];
public:
ValueTraits( T t ) { numberToString<T>( t, _asString ); }
const char *asString( void ) const { return _asString; }
};
CXXTEST_COPY_CONST_TRAITS( signed long int );
//
// ValueTraits: unsigned long
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const unsigned long int>
{
typedef unsigned long int T;
char _asString[1 + 3 * sizeof(T)];
public:
ValueTraits( T t ) { numberToString<T>( t, _asString ); }
const char *asString( void ) const { return _asString; }
};
CXXTEST_COPY_CONST_TRAITS( unsigned long int );
//
// All decimals are the same as the long version
//
CXXTEST_COPY_TRAITS( const signed int, const signed long int );
CXXTEST_COPY_TRAITS( const unsigned int, const unsigned long int );
CXXTEST_COPY_TRAITS( const signed short int, const signed long int );
CXXTEST_COPY_TRAITS( const unsigned short int, const unsigned long int );
CXXTEST_COPY_TRAITS( const unsigned char, const unsigned long int );
CXXTEST_COPY_CONST_TRAITS( signed int );
CXXTEST_COPY_CONST_TRAITS( unsigned int );
CXXTEST_COPY_CONST_TRAITS( signed short int );
CXXTEST_COPY_CONST_TRAITS( unsigned short int );
CXXTEST_COPY_CONST_TRAITS( unsigned char );
//
// ValueTraits: char
// Returns 'x' for printable chars, '\x??' for others
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const char>
{
char _asString[sizeof("'\\xXX'")];
public:
ValueTraits( char c ) { copyString( charToString( c, copyString( _asString, "'" ) ), "'" ); }
const char *asString( void ) const { return _asString; }
};
CXXTEST_COPY_CONST_TRAITS( char );
//
// ValueTraits: signed char
// Same as char, some compilers need it
//
CXXTEST_COPY_TRAITS( const signed char, const char );
CXXTEST_COPY_CONST_TRAITS( signed char );
//
// ValueTraits: double
//
CXXTEST_TEMPLATE_INSTANTIATION
class ValueTraits<const double>
{
public:
ValueTraits( double t )
{
( requiredDigitsOnLeft( t ) > MAX_DIGITS_ON_LEFT ) ?
hugeNumber( t ) :
normalNumber( t );
}
const char *asString( void ) const { return _asString; }
private:
enum { MAX_DIGITS_ON_LEFT = 24, DIGITS_ON_RIGHT = 4, BASE = 10 };
char _asString[1 + MAX_DIGITS_ON_LEFT + 1 + DIGITS_ON_RIGHT + 1];
static unsigned requiredDigitsOnLeft( double t );
char *doNegative( double &t );
void hugeNumber( double t );
void normalNumber( double t );
char *doubleToString( double t, char *s, unsigned skip = 0, unsigned max = (unsigned)-1 );
};
CXXTEST_COPY_CONST_TRAITS( double );
//
// ValueTraits: float
//
CXXTEST_COPY_TRAITS( const float, const double );
CXXTEST_COPY_CONST_TRAITS( float );
#endif // !CXXTEST_USER_VALUE_TRAITS
}
#ifdef _CXXTEST_HAVE_STD
# include <cxxtest/StdValueTraits.h>
#endif // _CXXTEST_HAVE_STD
//
// CXXTEST_ENUM_TRAITS
//
#define CXXTEST_ENUM_TRAITS( TYPE, VALUES ) \
namespace CxxTest \
{ \
CXXTEST_TEMPLATE_INSTANTIATION \
class ValueTraits<TYPE> \
{ \
TYPE _value; \
char _fallback[sizeof("(" #TYPE ")") + 3 * sizeof(TYPE)]; \
public: \
ValueTraits( TYPE value ) { \
_value = value; \
numberToString<unsigned long int>( _value, copyString( _fallback, "(" #TYPE ")" ) ); \
} \
const char *asString( void ) const \
{ \
switch ( _value ) \
{ \
VALUES \
default: return _fallback; \
} \
} \
}; \
}
#define CXXTEST_ENUM_MEMBER( MEMBER ) \
case MEMBER: return #MEMBER;
#endif // __cxxtest__ValueTraits_h__

View File

@@ -0,0 +1,531 @@
#ifndef __cxxtest__Win32Gui_h__
#define __cxxtest__Win32Gui_h__
//
// The Win32Gui displays a simple progress bar using the Win32 API.
//
// It accepts the following command line options:
// -minimized Start minimized, pop up on error
// -keep Don't close the window at the end
// -title TITLE Set the window caption
//
// If both -minimized and -keep are specified, GUI will only keep the
// window if it's in focus.
//
// N.B. If you're wondering why this class doesn't use any standard
// library or STL (<string> would have been nice) it's because it only
// uses "straight" Win32 API.
//
#include <cxxtest/Gui.h>
#include <windows.h>
#include <commctrl.h>
namespace CxxTest
{
class Win32Gui : public GuiListener
{
public:
void enterGui( int &argc, char **argv )
{
parseCommandLine( argc, argv );
}
void enterWorld( const WorldDescription &wd )
{
getTotalTests( wd );
_testsDone = 0;
startGuiThread();
}
void guiEnterSuite( const char *suiteName )
{
showSuiteName( suiteName );
reset( _suiteStart );
}
void guiEnterTest( const char *suiteName, const char *testName )
{
++ _testsDone;
setTestCaption( suiteName, testName );
showTestName( testName );
showTestsDone();
progressBarMessage( PBM_STEPIT );
reset( _testStart );
}
void yellowBar()
{
setColor( 255, 255, 0 );
setIcon( IDI_WARNING );
getTotalTests();
}
void redBar()
{
if ( _startMinimized )
showMainWindow( SW_SHOWNORMAL );
setColor( 255, 0, 0 );
setIcon( IDI_ERROR );
getTotalTests();
}
void leaveGui()
{
if ( keep() )
{
showSummary();
WaitForSingleObject( _gui, INFINITE );
}
DestroyWindow( _mainWindow );
}
private:
const char *_title;
bool _startMinimized, _keep;
HANDLE _gui;
WNDCLASSEX _windowClass;
HWND _mainWindow, _progressBar, _statusBar;
HANDLE _canStartTests;
unsigned _numTotalTests, _testsDone;
char _strTotalTests[WorldDescription::MAX_STRLEN_TOTAL_TESTS];
enum {
STATUS_SUITE_NAME, STATUS_SUITE_TIME,
STATUS_TEST_NAME, STATUS_TEST_TIME,
STATUS_TESTS_DONE, STATUS_WORLD_TIME,
STATUS_TOTAL_PARTS
};
int _statusWidths[STATUS_TOTAL_PARTS];
unsigned _statusOffsets[STATUS_TOTAL_PARTS];
unsigned _statusTotal;
char _statusTestsDone[sizeof("1000000000 of (100%)") + WorldDescription::MAX_STRLEN_TOTAL_TESTS];
DWORD _worldStart, _suiteStart, _testStart;
char _timeString[sizeof("00:00:00")];
void parseCommandLine( int argc, char **argv )
{
_startMinimized = _keep = false;
_title = argv[0];
for ( int i = 1; i < argc; ++ i )
{
if ( !lstrcmpA( argv[i], "-minimized" ) )
_startMinimized = true;
else if ( !lstrcmpA( argv[i], "-keep" ) )
_keep = true;
else if ( !lstrcmpA( argv[i], "-title" ) && (i + 1 < argc) )
_title = argv[++i];
}
}
void getTotalTests()
{
getTotalTests( tracker().world() );
}
void getTotalTests( const WorldDescription &wd )
{
_numTotalTests = wd.numTotalTests();
wd.strTotalTests( _strTotalTests );
}
void startGuiThread()
{
_canStartTests = CreateEvent( NULL, TRUE, FALSE, NULL );
DWORD threadId;
_gui = CreateThread( NULL, 0, &(Win32Gui::guiThread), (LPVOID)this, 0, &threadId );
WaitForSingleObject( _canStartTests, INFINITE );
}
static DWORD WINAPI guiThread( LPVOID parameter )
{
((Win32Gui *)parameter)->gui();
return 0;
}
void gui()
{
registerWindowClass();
createMainWindow();
initCommonControls();
createProgressBar();
createStatusBar();
centerMainWindow();
showMainWindow();
startTimer();
startTests();
messageLoop();
}
void registerWindowClass()
{
_windowClass.cbSize = sizeof(_windowClass);
_windowClass.style = CS_HREDRAW | CS_VREDRAW;
_windowClass.lpfnWndProc = &(Win32Gui::windowProcedure);
_windowClass.cbClsExtra = 0;
_windowClass.cbWndExtra = sizeof(LONG);
_windowClass.hInstance = (HINSTANCE)NULL;
_windowClass.hIcon = (HICON)NULL;
_windowClass.hCursor = (HCURSOR)NULL;
_windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
_windowClass.lpszMenuName = NULL;
_windowClass.lpszClassName = TEXT("CxxTest Window Class");
_windowClass.hIconSm = (HICON)NULL;
RegisterClassEx( &_windowClass );
}
void createMainWindow()
{
_mainWindow = createWindow( _windowClass.lpszClassName, WS_OVERLAPPEDWINDOW );
}
void initCommonControls()
{
HMODULE dll = LoadLibraryA( "comctl32.dll" );
if ( !dll )
return;
typedef void (WINAPI *FUNC)( void );
FUNC func = (FUNC)GetProcAddress( dll, "InitCommonControls" );
if ( !func )
return;
func();
}
void createProgressBar()
{
_progressBar = createWindow( PROGRESS_CLASS, WS_CHILD | WS_VISIBLE | PBS_SMOOTH, _mainWindow );
#ifdef PBM_SETRANGE32
progressBarMessage( PBM_SETRANGE32, 0, _numTotalTests );
#else // No PBM_SETRANGE32, use PBM_SETRANGE
progressBarMessage( PBM_SETRANGE, 0, MAKELPARAM( 0, (WORD)_numTotalTests ) );
#endif // PBM_SETRANGE32
progressBarMessage( PBM_SETPOS, 0 );
progressBarMessage( PBM_SETSTEP, 1 );
greenBar();
UpdateWindow( _progressBar );
}
void createStatusBar()
{
_statusBar = createWindow( STATUSCLASSNAME, WS_CHILD | WS_VISIBLE, _mainWindow );
setRatios( 4, 1, 3, 1, 3, 1 );
}
void setRatios( unsigned suiteNameRatio, unsigned suiteTimeRatio,
unsigned testNameRatio, unsigned testTimeRatio,
unsigned testsDoneRatio, unsigned worldTimeRatio )
{
_statusTotal = 0;
_statusOffsets[STATUS_SUITE_NAME] = (_statusTotal += suiteNameRatio);
_statusOffsets[STATUS_SUITE_TIME] = (_statusTotal += suiteTimeRatio);
_statusOffsets[STATUS_TEST_NAME] = (_statusTotal += testNameRatio);
_statusOffsets[STATUS_TEST_TIME] = (_statusTotal += testTimeRatio);
_statusOffsets[STATUS_TESTS_DONE] = (_statusTotal += testsDoneRatio);
_statusOffsets[STATUS_WORLD_TIME] = (_statusTotal += worldTimeRatio);
}
HWND createWindow( LPCTSTR className, DWORD style, HWND parent = (HWND)NULL )
{
return CreateWindow( className, NULL, style, 0, 0, 0, 0, parent,
(HMENU)NULL, (HINSTANCE)NULL, (LPVOID)this );
}
void progressBarMessage( UINT message, WPARAM wParam = 0, LPARAM lParam = 0 )
{
SendMessage( _progressBar, message, wParam, lParam );
}
void centerMainWindow()
{
RECT screen;
getScreenArea( screen );
LONG screenWidth = screen.right - screen.left;
LONG screenHeight = screen.bottom - screen.top;
LONG xCenter = (screen.right + screen.left) / 2;
LONG yCenter = (screen.bottom + screen.top) / 2;
LONG windowWidth = (screenWidth * 4) / 5;
LONG windowHeight = screenHeight / 10;
LONG minimumHeight = 2 * (GetSystemMetrics( SM_CYCAPTION ) + GetSystemMetrics( SM_CYFRAME ));
if ( windowHeight < minimumHeight )
windowHeight = minimumHeight;
SetWindowPos( _mainWindow, HWND_TOP,
xCenter - (windowWidth / 2), yCenter - (windowHeight / 2),
windowWidth, windowHeight, 0 );
}
void getScreenArea( RECT &area )
{
if ( !getScreenAreaWithoutTaskbar( area ) )
getWholeScreenArea( area );
}
bool getScreenAreaWithoutTaskbar( RECT &area )
{
return (SystemParametersInfo( SPI_GETWORKAREA, sizeof(RECT), &area, 0 ) != 0);
}
void getWholeScreenArea( RECT &area )
{
area.left = area.top = 0;
area.right = GetSystemMetrics( SM_CXSCREEN );
area.bottom = GetSystemMetrics( SM_CYSCREEN );
}
void showMainWindow()
{
showMainWindow( _startMinimized ? SW_MINIMIZE : SW_SHOWNORMAL );
UpdateWindow( _mainWindow );
}
void showMainWindow( int mode )
{
ShowWindow( _mainWindow, mode );
}
enum { TIMER_ID = 1, TIMER_DELAY = 1000 };
void startTimer()
{
reset( _worldStart );
reset( _suiteStart );
reset( _testStart );
SetTimer( _mainWindow, TIMER_ID, TIMER_DELAY, 0 );
}
void reset( DWORD &tick )
{
tick = GetTickCount();
}
void startTests()
{
SetEvent( _canStartTests );
}
void messageLoop()
{
MSG message;
while ( BOOL haveMessage = GetMessage( &message, NULL, 0, 0 ) )
if ( haveMessage != -1 )
DispatchMessage( &message );
}
static LRESULT CALLBACK windowProcedure( HWND window, UINT message, WPARAM wParam, LPARAM lParam )
{
if ( message == WM_CREATE )
setUp( window, (LPCREATESTRUCT)lParam );
Win32Gui *that = (Win32Gui *)GetWindowLong( window, GWL_USERDATA );
return that->handle( window, message, wParam, lParam );
}
static void setUp( HWND window, LPCREATESTRUCT create )
{
SetWindowLong( window, GWL_USERDATA, (LONG)create->lpCreateParams );
}
LRESULT handle( HWND window, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_SIZE: resizeControls(); break;
case WM_TIMER: updateTime(); break;
case WM_CLOSE:
case WM_DESTROY:
case WM_QUIT:
ExitProcess( 0 );
default: return DefWindowProc( window, message, wParam, lParam );
}
return 0;
}
void resizeControls()
{
RECT r;
GetClientRect( _mainWindow, &r );
LONG width = r.right - r.left;
LONG height = r.bottom - r.top;
GetClientRect( _statusBar, &r );
LONG statusHeight = r.bottom - r.top;
LONG resizeGripWidth = statusHeight;
LONG progressHeight = height - statusHeight;
SetWindowPos( _progressBar, HWND_TOP, 0, 0, width, progressHeight, 0 );
SetWindowPos( _statusBar, HWND_TOP, 0, progressHeight, width, statusHeight, 0 );
setStatusParts( width - resizeGripWidth );
}
void setStatusParts( LONG width )
{
for ( unsigned i = 0; i < STATUS_TOTAL_PARTS; ++ i )
_statusWidths[i] = (width * _statusOffsets[i]) / _statusTotal;
statusBarMessage( SB_SETPARTS, STATUS_TOTAL_PARTS, _statusWidths );
}
void statusBarMessage( UINT message, WPARAM wParam = 0, const void *lParam = 0 )
{
SendMessage( _statusBar, message, wParam, (LPARAM)lParam );
}
void greenBar()
{
setColor( 0, 255, 0 );
setIcon( IDI_INFORMATION );
}
#ifdef PBM_SETBARCOLOR
void setColor( BYTE red, BYTE green, BYTE blue )
{
progressBarMessage( PBM_SETBARCOLOR, 0, RGB( red, green, blue ) );
}
#else // !PBM_SETBARCOLOR
void setColor( BYTE, BYTE, BYTE )
{
}
#endif // PBM_SETBARCOLOR
void setIcon( LPCTSTR icon )
{
SendMessage( _mainWindow, WM_SETICON, ICON_BIG, (LPARAM)loadStandardIcon( icon ) );
}
HICON loadStandardIcon( LPCTSTR icon )
{
return LoadIcon( (HINSTANCE)NULL, icon );
}
void setTestCaption( const char *suiteName, const char *testName )
{
setCaption( suiteName, "::", testName, "()" );
}
void setCaption( const char *a = "", const char *b = "", const char *c = "", const char *d = "" )
{
unsigned length = lstrlenA( _title ) + sizeof( " - " ) +
lstrlenA( a ) + lstrlenA( b ) + lstrlenA( c ) + lstrlenA( d );
char *name = allocate( length );
lstrcpyA( name, _title );
lstrcatA( name, " - " );
lstrcatA( name, a );
lstrcatA( name, b );
lstrcatA( name, c );
lstrcatA( name, d );
SetWindowTextA( _mainWindow, name );
deallocate( name );
}
void showSuiteName( const char *suiteName )
{
setStatusPart( STATUS_SUITE_NAME, suiteName );
}
void showTestName( const char *testName )
{
setStatusPart( STATUS_TEST_NAME, testName );
}
void showTestsDone()
{
wsprintfA( _statusTestsDone, "%u of %s (%u%%)",
_testsDone, _strTotalTests,
(_testsDone * 100) / _numTotalTests );
setStatusPart( STATUS_TESTS_DONE, _statusTestsDone );
}
void updateTime()
{
setStatusTime( STATUS_WORLD_TIME, _worldStart );
setStatusTime( STATUS_SUITE_TIME, _suiteStart );
setStatusTime( STATUS_TEST_TIME, _testStart );
}
void setStatusTime( unsigned part, DWORD start )
{
unsigned total = (GetTickCount() - start) / 1000;
unsigned hours = total / 3600;
unsigned minutes = (total / 60) % 60;
unsigned seconds = total % 60;
if ( hours )
wsprintfA( _timeString, "%u:%02u:%02u", hours, minutes, seconds );
else
wsprintfA( _timeString, "%02u:%02u", minutes, seconds );
setStatusPart( part, _timeString );
}
bool keep()
{
if ( !_keep )
return false;
if ( !_startMinimized )
return true;
return (_mainWindow == GetForegroundWindow());
}
void showSummary()
{
stopTimer();
setSummaryStatusBar();
setSummaryCaption();
}
void setStatusPart( unsigned part, const char *text )
{
statusBarMessage( SB_SETTEXTA, part, text );
}
void stopTimer()
{
KillTimer( _mainWindow, TIMER_ID );
setStatusTime( STATUS_WORLD_TIME, _worldStart );
}
void setSummaryStatusBar()
{
setRatios( 0, 0, 0, 0, 1, 1 );
resizeControls();
const char *tests = (_numTotalTests == 1) ? "test" : "tests";
if ( tracker().failedTests() )
wsprintfA( _statusTestsDone, "Failed %u of %s %s",
tracker().failedTests(), _strTotalTests, tests );
else
wsprintfA( _statusTestsDone, "%s %s passed", _strTotalTests, tests );
setStatusPart( STATUS_TESTS_DONE, _statusTestsDone );
}
void setSummaryCaption()
{
setCaption( _statusTestsDone );
}
char *allocate( unsigned length )
{
return (char *)HeapAlloc( GetProcessHeap(), 0, length );
}
void deallocate( char *data )
{
HeapFree( GetProcessHeap(), 0, data );
}
};
}
#endif // __cxxtest__Win32Gui_h__

View File

@@ -0,0 +1,327 @@
#ifndef __cxxtest__X11Gui_h__
#define __cxxtest__X11Gui_h__
//
// X11Gui displays a simple progress bar using X11
//
// It accepts the following command-line arguments:
// -title <title> - Sets the application title
// -fn or -font <font> - Sets the font
// -bg or -background <color> - Sets the background color (default=Grey)
// -fg or -foreground <color> - Sets the text color (default=Black)
// -green/-yellow/-red <color> - Sets the colors of the bar
//
#include <cxxtest/Gui.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
namespace CxxTest
{
class X11Gui : public GuiListener
{
public:
void enterGui( int &argc, char **argv )
{
parseCommandLine( argc, argv );
}
void enterWorld( const WorldDescription &wd )
{
openDisplay();
if ( _display ) {
createColors();
createWindow();
createGc();
createFont();
centerWindow();
initializeEvents();
initializeBar( wd );
processEvents();
}
}
void guiEnterTest( const char *suiteName, const char *testName )
{
if ( _display ) {
++ _testsDone;
setWindowName( suiteName, testName );
redraw();
}
}
void yellowBar()
{
if ( _display ) {
_barColor = getColor( _yellowName );
getTotalTests();
processEvents();
}
}
void redBar()
{
if ( _display ) {
_barColor = getColor( _redName );
getTotalTests();
processEvents();
}
}
void leaveGui()
{
if ( _display ) {
freeFontInfo();
destroyGc();
destroyWindow();
closeDisplay();
}
}
private:
const char *_programName;
Display *_display;
Window _window;
unsigned _numTotalTests, _testsDone;
char _strTotalTests[WorldDescription::MAX_STRLEN_TOTAL_TESTS];
const char *_foregroundName, *_backgroundName;
const char *_greenName, *_yellowName, *_redName;
unsigned long _foreground, _background, _barColor;
int _width, _height;
GC _gc;
const char *_fontName;
XID _fontId;
XFontStruct *_fontInfo;
int _textHeight, _textDescent;
long _eventMask;
Colormap _colormap;
void parseCommandLine( int &argc, char **argv )
{
_programName = argv[0];
_fontName = 0;
_foregroundName = "Black";
_backgroundName = "Grey";
_greenName = "Green";
_yellowName = "Yellow";
_redName = "Red";
for ( int i = 1; i + 1 < argc; ++ i ) {
if ( !strcmp( argv[i], "-title" ) )
_programName = argv[++ i];
else if ( !strcmp( argv[i], "-fn" ) || !strcmp( argv[i], "-font" ) )
_fontName = argv[++ i];
else if ( !strcmp( argv[i], "-fg" ) || !strcmp( argv[i], "-foreground" ) )
_foregroundName = argv[++ i];
else if ( !strcmp( argv[i], "-bg" ) || !strcmp( argv[i], "-background" ) )
_backgroundName = argv[++ i];
else if ( !strcmp( argv[i], "-green" ) )
_greenName = argv[++ i];
else if ( !strcmp( argv[i], "-yellow" ) )
_yellowName = argv[++ i];
else if ( !strcmp( argv[i], "-red" ) )
_redName = argv[++ i];
}
}
void openDisplay()
{
_display = XOpenDisplay( NULL );
}
void createColors()
{
_colormap = DefaultColormap( _display, 0 );
_foreground = getColor( _foregroundName );
_background = getColor( _backgroundName );
}
unsigned long getColor( const char *colorName )
{
XColor color;
XParseColor( _display, _colormap, colorName, &color );
XAllocColor( _display, _colormap, &color );
return color.pixel;
}
void createWindow()
{
_window = XCreateSimpleWindow( _display, RootWindow( _display, 0 ), 0, 0, 1, 1, 0, 0, _background );
}
void createGc()
{
_gc = XCreateGC( _display, _window, 0, 0 );
}
void createFont()
{
if ( !loadFont() )
useDefaultFont();
getFontInfo();
_textHeight = _fontInfo->ascent + _fontInfo->descent;
_textDescent = _fontInfo->descent;
}
bool loadFont()
{
if ( !_fontName )
return false;
_fontId = XLoadFont( _display, _fontName );
return (XSetFont( _display, _gc, _fontId ) == Success);
}
void useDefaultFont()
{
_fontId = XGContextFromGC( _gc );
}
void getFontInfo()
{
_fontInfo = XQueryFont( _display, _fontId );
}
void freeFontInfo()
{
XFreeFontInfo( NULL, _fontInfo, 1 );
}
void initializeEvents()
{
_eventMask = ExposureMask;
XSelectInput( _display, _window, _eventMask );
}
void initializeBar( const WorldDescription &wd )
{
getTotalTests( wd );
_testsDone = 0;
_barColor = getColor( _greenName );
}
void getTotalTests()
{
getTotalTests( tracker().world() );
}
void getTotalTests( const WorldDescription &wd )
{
_numTotalTests = wd.numTotalTests();
wd.strTotalTests( _strTotalTests );
}
void centerWindow()
{
XMapWindow( _display, _window );
Screen *screen = XDefaultScreenOfDisplay( _display );
int screenWidth = WidthOfScreen( screen );
int screenHeight = HeightOfScreen( screen );
int xCenter = screenWidth / 2;
int yCenter = screenHeight / 2;
_width = (screenWidth * 4) / 5;
_height = screenHeight / 14;
XMoveResizeWindow( _display, _window, xCenter - (_width / 2), yCenter - (_height / 2), _width, _height );
}
void processEvents()
{
redraw();
XEvent event;
while( XCheckMaskEvent( _display, _eventMask, &event ) )
redraw();
}
void setWindowName( const char *suiteName, const char *testName )
{
unsigned length = strlen( _programName ) + strlen( suiteName ) + strlen( testName ) + sizeof( " - ::()" );
char *name = (char *)malloc( length );
sprintf( name, "%s - %s::%s()", _programName, suiteName, testName );
XSetStandardProperties( _display, _window, name, 0, 0, 0, 0, 0 );
free( name );
}
void redraw()
{
getWindowSize();
drawSolidBar();
drawDividers();
drawPercentage();
flush();
}
void getWindowSize()
{
XWindowAttributes attributes;
XGetWindowAttributes( _display, _window, &attributes );
_width = attributes.width;
_height = attributes.height;
}
void drawSolidBar()
{
unsigned barWidth = (_width * _testsDone) / _numTotalTests;
XSetForeground( _display, _gc, _barColor );
XFillRectangle( _display, _window, _gc, 0, 0, barWidth, _height );
XSetForeground( _display, _gc, _background );
XFillRectangle( _display, _window, _gc, barWidth, 0, _width + 1 - barWidth, _height );
}
void drawDividers()
{
if(_width / _numTotalTests < 5)
return;
for ( unsigned i = 1; i < _testsDone; ++ i ) {
int x = (_width * i) / _numTotalTests;
XDrawLine( _display, _window, _gc, x, 0, x, _height);
}
}
void drawPercentage()
{
XSetForeground( _display, _gc, _foreground );
char str[sizeof("1000000000 of ") + sizeof(_strTotalTests) + sizeof(" (100%)")];
sprintf( str, "%u of %s (%u%%)", _testsDone, _strTotalTests, (_testsDone * 100) / _numTotalTests );
unsigned len = strlen( str );
int textWidth = XTextWidth( _fontInfo, str, len );
XDrawString( _display, _window, _gc,
(_width - textWidth) / 2, ((_height + _textHeight) / 2) - _textDescent,
str, len );
}
void flush()
{
XFlush( _display );
}
void destroyGc()
{
XFreeGC( _display, _gc );
}
void destroyWindow()
{
XDestroyWindow( _display, _window );
}
void closeDisplay()
{
XCloseDisplay( _display );
}
};
}
#endif //__cxxtest__X11Gui_h__

View File

@@ -0,0 +1,29 @@
#ifndef __cxxtest__YesNoRunner_h__
#define __cxxtest__YesNoRunner_h__
//
// The YesNoRunner is a simple TestListener that
// just returns true iff all tests passed.
//
#include <cxxtest/TestRunner.h>
#include <cxxtest/TestListener.h>
namespace CxxTest
{
class YesNoRunner : public TestListener
{
public:
YesNoRunner()
{
}
int run()
{
TestRunner::runAllTests( *this );
return tracker().failedTests();
}
};
}
#endif // __cxxtest__YesNoRunner_h__

551
test/cxxtest/cxxtestgen.pl Normal file
View File

@@ -0,0 +1,551 @@
#!/usr/bin/perl -w
use strict;
use Getopt::Long;
sub usage() {
print STDERR "Usage: $0 [OPTIONS] <input file(s)>\n";
print STDERR "Generate test source file for CxxTest.\n";
print STDERR "\n";
print STDERR " -v, --version Write CxxTest version\n";
print STDERR " -o, --output=NAME Write output to file NAME\n";
print STDERR " --runner=CLASS Create a main() function that runs CxxTest::CLASS\n";
print STDERR " --gui=CLASS Like --runner, with GUI component\n";
print STDERR " --error-printer Same as --runner=ErrorPrinter\n";
print STDERR " --abort-on-fail Abort tests on failed asserts (like xUnit)\n";
print STDERR " --have-std Use standard library (even if not found in tests)\n";
print STDERR " --no-std Don't use standard library (even if found in tests)\n";
print STDERR " --have-eh Use exception handling (even if not found in tests)\n";
print STDERR " --no-eh Don't use exception handling (even if found in tests)\n";
print STDERR " --longlong=[TYPE] Use TYPE as `long long' (defaut = long long)\n";
print STDERR " --template=TEMPLATE Use TEMPLATE file to generate the test runner\n";
print STDERR " --include=HEADER Include \"HEADER\" in test runner before other headers\n";
print STDERR " --root Write CxxTest globals\n";
print STDERR " --part Don't write CxxTest globals\n";
print STDERR " --no-static-init Don't rely on static initialization\n";
exit -1;
}
main();
sub main {
parseCommandline();
scanInputFiles();
writeOutput();
}
#
# Handling the command line
#
my ($output, $runner, $gui, $template, $abortOnFail, $haveEh, $noEh, $haveStd, $noStd);
my ($root, $part, $noStaticInit, $longlong, $factor);
my @headers = ();
sub parseCommandline() {
@ARGV = expandWildcards(@ARGV);
GetOptions( 'version' => \&printVersion,
'output=s' => \$output,
'template=s' => \$template,
'runner=s' => \$runner,
'gui=s', => \$gui,
'error-printer' => sub { $runner = 'ErrorPrinter'; $haveStd = 1; },
'abort-on-fail' => \$abortOnFail,
'have-eh' => \$haveEh,
'no-eh' => \$noEh,
'have-std' => \$haveStd,
'no-std' => \$noStd,
'include=s' => \@headers,
'root' => \$root,
'part' => \$part,
'no-static-init' => \$noStaticInit,
'factor' => \$factor,
'longlong:s' => \$longlong
) or usage();
scalar @ARGV or $root or usage();
if ( defined($noStaticInit) && (defined($root) || defined($part)) ) {
die "--no-static-init cannot be used with --root/--part\n";
}
if ( $gui && !$runner ) {
$runner = 'StdioPrinter';
}
if ( defined($longlong) && !$longlong ) {
$longlong = 'long long';
}
foreach my $header (@headers) {
if ( !($header =~ m/^["<].*[>"]$/) ) {
$header = "\"$header\"";
}
}
}
sub printVersion() {
print "This is CxxTest version 3.10.1.\n";
exit 0;
}
sub expandWildcards() {
my @result = ();
while( my $fn = shift @_ ) {
push @result, glob($fn);
}
return @result;
}
#
# Reading the input files and scanning for test cases
#
my (@suites, $suite, $test, $inBlock);
my $numTotalTests = 0;
sub scanInputFiles() {
foreach my $file (@ARGV) {
scanInputFile( $file );
}
scalar @suites or $root or die("No tests defined\n");
}
sub scanInputFile($) {
my ($file) = @_;
open FILE, "<$file" or die("Cannot open input file \"$file\"\n");
my $line;
while (defined($line = <FILE>)) {
scanLineForExceptionHandling( $line );
scanLineForStandardLibrary( $line );
scanLineForSuiteStart( $file, $., $line );
if ( $suite ) {
if ( lineBelongsToSuite( $suite, $., $line ) ) {
scanLineForTest( $., $line );
scanLineForCreate( $., $line );
scanLineForDestroy( $., $line );
}
}
}
closeSuite();
close FILE;
}
sub lineBelongsToSuite($$$) {
my ($suite, $lineNo, $line) = @_;
if ( !$suite->{'generated'} ) {
return 1;
}
if ( !$inBlock ) {
$inBlock = lineStartsBlock( $line );
}
if ( $inBlock ) {
addLineToBlock( $suite->{'file'}, $lineNo, $line );
}
return $inBlock;
}
sub scanLineForExceptionHandling($) {
my ($line) = @_;
if ( $line =~ m/\b(try|throw|catch|TSM?_ASSERT_THROWS[A-Z_]*)\b/ ) {
addExceptionHandling();
}
}
sub scanLineForStandardLibrary($) {
my ($line) = @_;
if ( $line =~ m/\b(std\s*::|CXXTEST_STD|using\s+namespace\s+std\b|^\s*\#\s*include\s+<[a-z0-9]+>)/ ) {
addStandardLibrary();
}
}
sub scanLineForSuiteStart($$$) {
my ($fileName, $lineNo, $line) = @_;
if ( $line =~ m/\bclass\s+(\w+)\s*:\s*public\s+((::)?\s*CxxTest\s*::\s*)?TestSuite\b/ ) {
startSuite( $1, $fileName, $lineNo, 0 );
}
if ( $line =~ m/\bCXXTEST_SUITE\s*\(\s*(\w*)\s*\)/ ) {
print "$fileName:$lineNo: Warning: Inline test suites are deprecated.\n";
startSuite( $1, $fileName, $lineNo, 1 );
}
}
sub startSuite($$$$) {
my ($name, $file, $line, $generated) = @_;
closeSuite();
$suite = { 'name' => $name,
'file' => $file,
'line' => $line,
'generated' => $generated,
'create' => 0,
'destroy' => 0,
'tests' => [],
'lines' => [] };
}
sub lineStartsBlock($) {
my ($line) = @_;
return $line =~ m/\bCXXTEST_CODE\s*\(/;
}
sub scanLineForTest($$) {
my ($lineNo, $line) = @_;
if ( $line =~ m/^([^\/]|\/[^\/])*\bvoid\s+([Tt]est\w+)\s*\(\s*(void)?\s*\)/ ) {
addTest( $2, $lineNo );
}
}
sub addTest($$$) {
my ($name, $line) = @_;
$test = { 'name' => $name,
'line' => $line };
push @{suiteTests()}, $test;
}
sub addLineToBlock($$$) {
my ($fileName, $lineNo, $line) = @_;
$line = fixBlockLine( $fileName, $lineNo, $line );
$line =~ s/^.*\{\{//;
my $end = ($line =~ s/\}\}.*//s);
push @{$suite->{'lines'}}, $line;
if ( $end ) {
$inBlock = 0;
}
}
sub fixBlockLine($$$) {
my ($fileName, $lineNo, $line) = @_;
my $fileLine = cstr($fileName) . "," . $lineNo;
$line =~ s/\b(E?TSM?_(ASSERT[A-Z_]*|FAIL))\s*\(/_$1($fileLine,/g;
return $line;
}
sub scanLineForCreate($$) {
my ($lineNo, $line) = @_;
if ( $line =~ m/\bstatic\s+\w+\s*\*\s*createSuite\s*\(\s*(void)?\s*\)/ ) {
addCreateSuite( $lineNo );
}
}
sub scanLineForDestroy($$) {
my ($lineNo, $line) = @_;
if ( $line =~ m/\bstatic\s+void\s+destroySuite\s*\(\s*\w+\s*\*\s*\w*\s*\)/ ) {
addDestroySuite( $lineNo );
}
}
sub closeSuite() {
if ( $suite && scalar @{suiteTests()} ) {
verifySuite();
rememberSuite();
}
undef $suite;
}
sub addCreateSuite($) {
$suite->{'createSuite'} = $_[0];
}
sub addDestroySuite($) {
$suite->{'destroySuite'} = $_[0];
}
sub addExceptionHandling() {
$haveEh = 1 unless defined($noEh);
}
sub addStandardLibrary() {
$haveStd = 1 unless defined($noStd);
}
sub verifySuite() {
if (suiteCreateLine() || suiteDestroyLine()) {
die("Suite ", suiteName(), " must have both createSuite() and destroySuite()\n")
unless (suiteCreateLine() && suiteDestroyLine());
}
}
sub rememberSuite() {
push @suites, $suite;
$numTotalTests += scalar @{$suite->{'tests'}};
}
sub suiteName() { return $suite->{'name'}; }
sub suiteTests() { return $suite->{'tests'}; }
sub suiteCreateLine() { return $suite->{'createSuite'}; }
sub suiteDestroyLine() { return $suite->{'destroySuite'}; }
sub fileName() { return $suite->{'file'}; }
sub fileString() { return cstr(fileName()); }
sub testName() { return $test->{'name'}; }
sub testLine() { return $test->{'line'}; }
sub suiteObject() { return "suite_".suiteName(); }
sub cstr($) {
my $file = $_[0];
$file =~ s/\\/\\\\/g;
return "\"".$file."\"";
}
#
# Writing the test source file
#
sub writeOutput() {
$template ? writeTemplateOutput() : writeSimpleOutput();
}
sub startOutputFile() {
if ( !standardOutput() ) {
open OUTPUT_FILE,">$output" or die("Cannot create output file \"$output\"\n");
select OUTPUT_FILE;
}
print "/* Generated file, do not edit */\n\n";
}
sub standardOutput() {
return !$output;
}
sub writeSimpleOutput() {
startOutputFile();
writePreamble();
writeMain();
writeWorld();
}
my ($didPreamble, $didWorld);
sub writeTemplateOutput() {
openTemplateFile();
startOutputFile();
my $line;
while (defined($line = <TEMPLATE_FILE>)) {
if ( $line =~ m/^\s*\#\s*include\s*<cxxtest\// ) {
writePreamble();
print $line;
} elsif ( $line =~ m/^\s*<CxxTest\s+preamble>\s*$/ ) {
writePreamble();
} elsif ( $line =~ m/^\s*<CxxTest\s+world>\s*$/ ) {
writeWorld();
} else {
print $line;
}
}
}
sub openTemplateFile() {
open TEMPLATE_FILE, "<$template" or die("Cannot open template file \"$template\"\n");
}
sub writePreamble() {
return if $didPreamble;
print "#ifndef CXXTEST_RUNNING\n";
print "#define CXXTEST_RUNNING\n";
print "#endif\n";
print "\n";
if ( $haveStd ) {
print "#define _CXXTEST_HAVE_STD\n";
}
if ( $haveEh ) {
print "#define _CXXTEST_HAVE_EH\n";
}
if ( $abortOnFail ) {
print "#define _CXXTEST_ABORT_TEST_ON_FAIL\n";
}
if ( $longlong ) {
print "#define _CXXTEST_LONGLONG $longlong\n";
}
if ( $factor ) {
print "#define _CXXTEST_FACTOR\n";
}
foreach my $header (@headers) {
print "#include $header\n";
}
print "#include <cxxtest/TestListener.h>\n";
print "#include <cxxtest/TestTracker.h>\n";
print "#include <cxxtest/TestRunner.h>\n";
print "#include <cxxtest/RealDescriptions.h>\n";
print "#include <cxxtest/$runner.h>\n" if $runner;
print "#include <cxxtest/$gui.h>\n" if $gui;
print "\n";
$didPreamble = 1;
}
sub writeWorld() {
return if $didWorld;
writePreamble();
writeSuites();
($root or !$part) and writeRoot();
$noStaticInit and writeInitialize();
$didWorld = 1;
}
sub writeSuites() {
foreach (@suites) {
$suite = $_;
writeInclude(fileName());
if ( $suite->{'generated'} ) { generateSuite(); }
dynamicSuite() ? writeSuitePointer() : writeSuiteObject();
writeTestList();
writeSuiteDescription();
writeTestDescriptions();
}
}
sub dynamicSuite() {
return suiteCreateLine();
}
my $lastIncluded;
sub writeInclude($) {
my $file = $_[0];
return if $lastIncluded && ($file eq $lastIncluded);
print "#include \"$file\"\n\n";
$lastIncluded = $file;
}
sub generateSuite() {
print "class ", suiteName(), " : public CxxTest::TestSuite {\n";
print "public:\n";
foreach my $line (@{$suite->{'lines'}}) {
print $line;
}
print "};\n\n";
}
sub writeTestDescriptionsBase() {
my $class = "TestDescriptionBase_" . suiteName();
print "class $class : public CxxTest::TestDescription {\n";
print "public:\n";
print " const char *file() const { return ", fileString(), "; }\n";
print " const char *suiteName() const { return \"", suiteName(), "\"; }\n";
print "};\n\n";
}
sub writeSuitePointer() {
if ( $noStaticInit ) {
print "static ", suiteName(), " *", suiteObject(), ";\n\n";
} else {
print "static ", suiteName(), " *", suiteObject(), " = 0;\n\n";
}
}
sub writeSuiteObject() {
print "static ", suiteName(), " ", suiteObject(), ";\n\n";
}
sub testList() {
return "Tests_" . suiteName();
}
sub writeTestList() {
if ( $noStaticInit ) {
printf "static CxxTest::List %s;\n", testList();
} else {
printf "static CxxTest::List %s = { 0, 0 };\n", testList();
}
}
sub writeTestDescriptions() {
foreach (@{suiteTests()}) {
$test = $_;
writeTestDescription();
}
}
sub suiteDescription() {
return "suiteDescription_" . suiteName();
}
sub writeTestDescription() {
my $class = "TestDescription_" . suiteName() . "_" . testName();
printf "static class $class : public CxxTest::RealTestDescription {\n";
printf "public:\n";
$noStaticInit or
printf " $class() : CxxTest::RealTestDescription( %s, %s, %s, \"%s\" ) {}\n",
testList(), suiteDescription(), testLine(), testName();
printf " void runTest() { %s }\n", dynamicSuite() ? dynamicRun() : staticRun();
printf "} testDescription_%s_%s;\n\n", suiteName(), testName();
}
sub dynamicRun() {
return sprintf( "if ( %s ) %s->%s();", suiteObject(), suiteObject(), testName() );
}
sub staticRun() {
return sprintf( "%s.%s();", suiteObject(), testName() );
}
sub writeSuiteDescription() {
dynamicSuite() ? writeDynamicDescription() : writeStaticDescription();
}
sub writeDynamicDescription() {
printf "CxxTest::DynamicSuiteDescription<%s> %s", suiteName(), suiteDescription();
if ( !$noStaticInit ) {
printf "( %s, %s, \"%s\", %s, %s, %s, %s )",
fileString(), $suite->{'line'}, suiteName(), testList(),
suiteObject(), suiteCreateLine(), suiteDestroyLine();
}
print ";\n\n";
}
sub writeStaticDescription() {
printf "CxxTest::StaticSuiteDescription %s", suiteDescription();
if ( !$noStaticInit ) {
printf "( %s, %s, \"%s\", %s, %s )", fileString(), $suite->{'line'}, suiteName(), suiteObject(), testList();
}
print ";\n\n";
}
sub writeRoot() {
print "#include <cxxtest/Root.cpp>\n";
}
sub writeInitialize() {
print "namespace CxxTest {\n";
print " void initialize()\n";
print " {\n";
foreach (@suites) {
$suite = $_;
printf " %s.initialize();\n", testList();
if ( dynamicSuite() ) {
printf " %s = 0;\n", suiteObject();
printf " %s.initialize( %s, %s, \"%s\", %s, %s, %s, %s );\n",
suiteDescription(), fileString(), $suite->{'line'}, suiteName(), testList(),
suiteObject(), suiteCreateLine(), suiteDestroyLine();
} else {
printf " %s.initialize( %s, %s, \"%s\", %s, %s );\n",
suiteDescription(), fileString(), $suite->{'line'}, suiteName(), suiteObject(), testList();
}
foreach (@{suiteTests()}) {
$test = $_;
printf " testDescription_%s_%s.initialize( %s, %s, %s, \"%s\" );\n",
suiteName(), testName(), testList(), suiteDescription(), testLine(), testName();
}
}
print " }\n";
print "}\n";
}
sub writeMain() {
if ( $gui ) {
print "int main( int argc, char *argv[] ) {\n";
$noStaticInit &&
print " CxxTest::initialize();\n";
print " return CxxTest::GuiTuiRunner<CxxTest::$gui, CxxTest::$runner>( argc, argv ).run();\n";
print "}\n";
}
elsif ( $runner ) {
print "int main() {\n";
$noStaticInit &&
print " CxxTest::initialize();\n";
print " return CxxTest::$runner().run();\n";
print "}\n";
}
}

597
test/cxxtest/cxxtestgen.py Normal file
View File

@@ -0,0 +1,597 @@
#!/usr/bin/env python
'''Usage: %s [OPTIONS] <input file(s)>
Generate test source file for CxxTest.
-v, --version Write CxxTest version
-o, --output=NAME Write output to file NAME
--runner=CLASS Create a main() function that runs CxxTest::CLASS
--gui=CLASS Like --runner, with GUI component
--error-printer Same as --runner=ErrorPrinter
--abort-on-fail Abort tests on failed asserts (like xUnit)
--have-std Use standard library (even if not found in tests)
--no-std Don\'t use standard library (even if found in tests)
--have-eh Use exception handling (even if not found in tests)
--no-eh Don\'t use exception handling (even if found in tests)
--longlong=[TYPE] Use TYPE (default: long long) as long long
--template=TEMPLATE Use TEMPLATE file to generate the test runner
--include=HEADER Include HEADER in test runner before other headers
--root Write CxxTest globals
--part Don\'t write CxxTest globals
--no-static-init Don\'t rely on static initialization
'''
import re
import sys
import getopt
import glob
import string
# Global variables
suites = []
suite = None
inBlock = 0
outputFileName = None
runner = None
gui = None
root = None
part = None
noStaticInit = None
templateFileName = None
headers = []
haveExceptionHandling = 0
noExceptionHandling = 0
haveStandardLibrary = 0
noStandardLibrary = 0
abortOnFail = 0
factor = 0
longlong = 0
def main():
'''The main program'''
files = parseCommandline()
scanInputFiles( files )
writeOutput()
def usage( problem = None ):
'''Print usage info and exit'''
if problem is None:
print( usageString() )
sys.exit(0)
else:
sys.stderr.write( usageString() )
abort( problem )
def usageString():
'''Construct program usage string'''
return __doc__ % sys.argv[0]
def abort( problem ):
'''Print error message and exit'''
sys.stderr.write( '\n' )
sys.stderr.write( problem )
sys.stderr.write( '\n\n' )
sys.exit(2)
def parseCommandline():
'''Analyze command line arguments'''
try:
options, patterns = getopt.getopt( sys.argv[1:], 'o:r:',
['version', 'output=', 'runner=', 'gui=',
'error-printer', 'abort-on-fail', 'have-std', 'no-std',
'have-eh', 'no-eh', 'template=', 'include=',
'root', 'part', 'no-static-init', 'factor', 'longlong='] )
except getopt.error as problem:
usage( problem )
setOptions( options )
return setFiles( patterns )
def setOptions( options ):
'''Set options specified on command line'''
global outputFileName, templateFileName, runner, gui, haveStandardLibrary, factor, longlong
global haveExceptionHandling, noExceptionHandling, abortOnFail, headers, root, part, noStaticInit
for o, a in options:
if o in ('-v', '--version'):
printVersion()
elif o in ('-o', '--output'):
outputFileName = a
elif o == '--template':
templateFileName = a
elif o == '--runner':
runner = a
elif o == '--gui':
gui = a
elif o == '--include':
if not re.match( r'^["<].*[>"]$', a ):
a = ('"%s"' % a)
headers.append( a )
elif o == '--error-printer':
runner = 'ErrorPrinter'
haveStandardLibrary = 1
elif o == '--abort-on-fail':
abortOnFail = 1
elif o == '--have-std':
haveStandardLibrary = 1
elif o == '--no-std':
noStandardLibrary = 1
elif o == '--have-eh':
haveExceptionHandling = 1
elif o == '--no-eh':
noExceptionHandling = 1
elif o == '--root':
root = 1
elif o == '--part':
part = 1
elif o == '--no-static-init':
noStaticInit = 1
elif o == '--factor':
factor = 1
elif o == '--longlong':
if a:
longlong = a
else:
longlong = 'long long'
if noStaticInit and (root or part):
abort( '--no-static-init cannot be used with --root/--part' )
if gui and not runner:
runner = 'StdioPrinter'
def printVersion():
'''Print CxxTest version and exit'''
sys.stdout.write( "This is CxxTest version 3.10.1.\n" )
sys.exit(0)
def setFiles( patterns ):
'''Set input files specified on command line'''
files = expandWildcards( patterns )
if len(files) == 0 and not root:
usage( "No input files found" )
return files
def expandWildcards( patterns ):
'''Expand all wildcards in an array (glob)'''
fileNames = []
for pathName in patterns:
patternFiles = glob.glob( pathName )
for fileName in patternFiles:
fileNames.append( fixBackslashes( fileName ) )
return fileNames
def fixBackslashes( fileName ):
'''Convert backslashes to slashes in file name'''
return re.sub( r'\\', '/', fileName )
def scanInputFiles(files):
'''Scan all input files for test suites'''
for file in files:
scanInputFile(file)
global suites
if len(suites) == 0 and not root:
abort( 'No tests defined' )
def scanInputFile(fileName):
'''Scan single input file for test suites'''
if sys.version_info.major >= 3:
file = open(fileName, encoding='utf-8')
else:
file = open(fileName)
lineNo = 0
while 1:
line = file.readline()
if not line:
break
lineNo = lineNo + 1
scanInputLine( fileName, lineNo, line )
closeSuite()
file.close()
def scanInputLine( fileName, lineNo, line ):
'''Scan single input line for interesting stuff'''
scanLineForExceptionHandling( line )
scanLineForStandardLibrary( line )
scanLineForSuiteStart( fileName, lineNo, line )
global suite
if suite:
scanLineInsideSuite( suite, lineNo, line )
def scanLineInsideSuite( suite, lineNo, line ):
'''Analyze line which is part of a suite'''
global inBlock
if lineBelongsToSuite( suite, lineNo, line ):
scanLineForTest( suite, lineNo, line )
scanLineForCreate( suite, lineNo, line )
scanLineForDestroy( suite, lineNo, line )
def lineBelongsToSuite( suite, lineNo, line ):
'''Returns whether current line is part of the current suite.
This can be false when we are in a generated suite outside of CXXTEST_CODE() blocks
If the suite is generated, adds the line to the list of lines'''
if not suite['generated']:
return 1
global inBlock
if not inBlock:
inBlock = lineStartsBlock( line )
if inBlock:
inBlock = addLineToBlock( suite, lineNo, line )
return inBlock
std_re = re.compile( r"\b(std\s*::|CXXTEST_STD|using\s+namespace\s+std\b|^\s*\#\s*include\s+<[a-z0-9]+>)" )
def scanLineForStandardLibrary( line ):
'''Check if current line uses standard library'''
global haveStandardLibrary, noStandardLibrary
if not haveStandardLibrary and std_re.search(line):
if not noStandardLibrary:
haveStandardLibrary = 1
exception_re = re.compile( r"\b(throw|try|catch|TSM?_ASSERT_THROWS[A-Z_]*)\b" )
def scanLineForExceptionHandling( line ):
'''Check if current line uses exception handling'''
global haveExceptionHandling, noExceptionHandling
if not haveExceptionHandling and exception_re.search(line):
if not noExceptionHandling:
haveExceptionHandling = 1
suite_re = re.compile( r'\bclass\s+(\w+)\s*:\s*public\s+((::)?\s*CxxTest\s*::\s*)?TestSuite\b' )
generatedSuite_re = re.compile( r'\bCXXTEST_SUITE\s*\(\s*(\w*)\s*\)' )
def scanLineForSuiteStart( fileName, lineNo, line ):
'''Check if current line starts a new test suite'''
m = suite_re.search( line )
if m:
startSuite( m.group(1), fileName, lineNo, 0 )
m = generatedSuite_re.search( line )
if m:
sys.stdout.write( "%s:%s: Warning: Inline test suites are deprecated.\n" % (fileName, lineNo) )
startSuite( m.group(1), fileName, lineNo, 1 )
def startSuite( name, file, line, generated ):
'''Start scanning a new suite'''
global suite
closeSuite()
suite = { 'name' : name,
'file' : file,
'cfile' : cstr(file),
'line' : line,
'generated' : generated,
'object' : 'suite_%s' % name,
'dobject' : 'suiteDescription_%s' % name,
'tlist' : 'Tests_%s' % name,
'tests' : [],
'lines' : [] }
def lineStartsBlock( line ):
'''Check if current line starts a new CXXTEST_CODE() block'''
return re.search( r'\bCXXTEST_CODE\s*\(', line ) is not None
test_re = re.compile( r'^([^/]|/[^/])*\bvoid\s+([Tt]est\w+)\s*\(\s*(void)?\s*\)' )
def scanLineForTest( suite, lineNo, line ):
'''Check if current line starts a test'''
m = test_re.search( line )
if m:
addTest( suite, m.group(2), lineNo )
def addTest( suite, name, line ):
'''Add a test function to the current suite'''
test = { 'name' : name,
'suite' : suite,
'class' : 'TestDescription_%s_%s' % (suite['name'], name),
'object' : 'testDescription_%s_%s' % (suite['name'], name),
'line' : line,
}
suite['tests'].append( test )
def addLineToBlock( suite, lineNo, line ):
'''Append the line to the current CXXTEST_CODE() block'''
line = fixBlockLine( suite, lineNo, line )
line = re.sub( r'^.*\{\{', '', line )
e = re.search( r'\}\}', line )
if e:
line = line[:e.start()]
suite['lines'].append( line )
return e is None
def fixBlockLine( suite, lineNo, line):
'''Change all [E]TS_ macros used in a line to _[E]TS_ macros with the correct file/line'''
return re.sub( r'\b(E?TSM?_(ASSERT[A-Z_]*|FAIL))\s*\(',
r'_\1(%s,%s,' % (suite['cfile'], lineNo),
line, 0 )
create_re = re.compile( r'\bstatic\s+\w+\s*\*\s*createSuite\s*\(\s*(void)?\s*\)' )
def scanLineForCreate( suite, lineNo, line ):
'''Check if current line defines a createSuite() function'''
if create_re.search( line ):
addSuiteCreateDestroy( suite, 'create', lineNo )
destroy_re = re.compile( r'\bstatic\s+void\s+destroySuite\s*\(\s*\w+\s*\*\s*\w*\s*\)' )
def scanLineForDestroy( suite, lineNo, line ):
'''Check if current line defines a destroySuite() function'''
if destroy_re.search( line ):
addSuiteCreateDestroy( suite, 'destroy', lineNo )
def cstr( str ):
'''Convert a string to its C representation'''
return '"' + str.replace( '\\', '\\\\' ) + '"'
def addSuiteCreateDestroy( suite, which, line ):
'''Add createSuite()/destroySuite() to current suite'''
if suite.has_key(which):
abort( '%s:%s: %sSuite() already declared' % ( suite['file'], str(line), which ) )
suite[which] = line
def closeSuite():
'''Close current suite and add it to the list if valid'''
global suite
if suite is not None:
if len(suite['tests']) != 0:
verifySuite(suite)
rememberSuite(suite)
suite = None
def verifySuite(suite):
'''Verify current suite is legal'''
if 'create' in suite and not 'destroy' in suite:
abort( '%s:%s: Suite %s has createSuite() but no destroySuite()' %
(suite['file'], suite['create'], suite['name']) )
if 'destroy' in suite and not 'create' in suite:
abort( '%s:%s: Suite %s has destroySuite() but no createSuite()' %
(suite['file'], suite['destroy'], suite['name']) )
def rememberSuite(suite):
'''Add current suite to list'''
global suites
suites.append( suite )
def writeOutput():
'''Create output file'''
if templateFileName:
writeTemplateOutput()
else:
writeSimpleOutput()
def writeSimpleOutput():
'''Create output not based on template'''
output = startOutputFile()
writePreamble( output )
writeMain( output )
writeWorld( output )
output.close()
include_re = re.compile( r"\s*\#\s*include\s+<cxxtest/" )
preamble_re = re.compile( r"^\s*<CxxTest\s+preamble>\s*$" )
world_re = re.compile( r"^\s*<CxxTest\s+world>\s*$" )
def writeTemplateOutput():
'''Create output based on template file'''
template = open(templateFileName)
output = startOutputFile()
while 1:
line = template.readline()
if not line:
break;
if include_re.search( line ):
writePreamble( output )
output.write( line )
elif preamble_re.search( line ):
writePreamble( output )
elif world_re.search( line ):
writeWorld( output )
else:
output.write( line )
template.close()
output.close()
def startOutputFile():
'''Create output file and write header'''
if outputFileName is not None:
output = open( outputFileName, 'w' )
else:
output = sys.stdout
output.write( "/* Generated file, do not edit */\n\n" )
return output
wrotePreamble = 0
def writePreamble( output ):
'''Write the CxxTest header (#includes and #defines)'''
global wrotePreamble, headers, longlong
if wrotePreamble: return
output.write( "#ifndef CXXTEST_RUNNING\n" )
output.write( "#define CXXTEST_RUNNING\n" )
output.write( "#endif\n" )
output.write( "\n" )
if haveStandardLibrary:
output.write( "#define _CXXTEST_HAVE_STD\n" )
if haveExceptionHandling:
output.write( "#define _CXXTEST_HAVE_EH\n" )
if abortOnFail:
output.write( "#define _CXXTEST_ABORT_TEST_ON_FAIL\n" )
if longlong:
output.write( "#define _CXXTEST_LONGLONG %s\n" % longlong )
if factor:
output.write( "#define _CXXTEST_FACTOR\n" )
for header in headers:
output.write( "#include %s\n" % header )
output.write( "#include <cxxtest/TestListener.h>\n" )
output.write( "#include <cxxtest/TestTracker.h>\n" )
output.write( "#include <cxxtest/TestRunner.h>\n" )
output.write( "#include <cxxtest/RealDescriptions.h>\n" )
if runner:
output.write( "#include <cxxtest/%s.h>\n" % runner )
if gui:
output.write( "#include <cxxtest/%s.h>\n" % gui )
output.write( "\n" )
wrotePreamble = 1
def writeMain( output ):
'''Write the main() function for the test runner'''
if gui:
output.write( 'int main( int argc, char *argv[] ) {\n' )
if noStaticInit:
output.write( ' CxxTest::initialize();\n' )
output.write( ' return CxxTest::GuiTuiRunner<CxxTest::%s, CxxTest::%s>( argc, argv ).run();\n' % (gui, runner) )
output.write( '}\n' )
elif runner:
output.write( 'int main() {\n' )
if noStaticInit:
output.write( ' CxxTest::initialize();\n' )
output.write( ' return CxxTest::%s().run();\n' % runner )
output.write( '}\n' )
wroteWorld = 0
def writeWorld( output ):
'''Write the world definitions'''
global wroteWorld, part
if wroteWorld: return
writePreamble( output )
writeSuites( output )
if root or not part:
writeRoot( output )
if noStaticInit:
writeInitialize( output )
wroteWorld = 1
def writeSuites(output):
'''Write all TestDescriptions and SuiteDescriptions'''
for suite in suites:
writeInclude( output, suite['file'] )
if isGenerated(suite):
generateSuite( output, suite )
if isDynamic(suite):
writeSuitePointer( output, suite )
else:
writeSuiteObject( output, suite )
writeTestList( output, suite )
writeSuiteDescription( output, suite )
writeTestDescriptions( output, suite )
def isGenerated(suite):
'''Checks whether a suite class should be created'''
return suite['generated']
def isDynamic(suite):
'''Checks whether a suite is dynamic'''
return 'create' in suite
lastIncluded = ''
def writeInclude(output, file):
'''Add #include "file" statement'''
global lastIncluded
if file == lastIncluded: return
output.writelines( [ '#include "', file, '"\n\n' ] )
lastIncluded = file
def generateSuite( output, suite ):
'''Write a suite declared with CXXTEST_SUITE()'''
output.write( 'class %s : public CxxTest::TestSuite {\n' % suite['name'] )
output.write( 'public:\n' )
for line in suite['lines']:
output.write(line)
output.write( '};\n\n' )
def writeSuitePointer( output, suite ):
'''Create static suite pointer object for dynamic suites'''
if noStaticInit:
output.write( 'static %s *%s;\n\n' % (suite['name'], suite['object']) )
else:
output.write( 'static %s *%s = 0;\n\n' % (suite['name'], suite['object']) )
def writeSuiteObject( output, suite ):
'''Create static suite object for non-dynamic suites'''
output.writelines( [ "static ", suite['name'], " ", suite['object'], ";\n\n" ] )
def writeTestList( output, suite ):
'''Write the head of the test linked list for a suite'''
if noStaticInit:
output.write( 'static CxxTest::List %s;\n' % suite['tlist'] )
else:
output.write( 'static CxxTest::List %s = { 0, 0 };\n' % suite['tlist'] )
def writeTestDescriptions( output, suite ):
'''Write all test descriptions for a suite'''
for test in suite['tests']:
writeTestDescription( output, suite, test )
def writeTestDescription( output, suite, test ):
'''Write test description object'''
output.write( 'static class %s : public CxxTest::RealTestDescription {\n' % test['class'] )
output.write( 'public:\n' )
if not noStaticInit:
output.write( ' %s() : CxxTest::RealTestDescription( %s, %s, %s, "%s" ) {}\n' %
(test['class'], suite['tlist'], suite['dobject'], test['line'], test['name']) )
output.write( ' void runTest() { %s }\n' % runBody( suite, test ) )
output.write( '} %s;\n\n' % test['object'] )
def runBody( suite, test ):
'''Body of TestDescription::run()'''
if isDynamic(suite): return dynamicRun( suite, test )
else: return staticRun( suite, test )
def dynamicRun( suite, test ):
'''Body of TestDescription::run() for test in a dynamic suite'''
return 'if ( ' + suite['object'] + ' ) ' + suite['object'] + '->' + test['name'] + '();'
def staticRun( suite, test ):
'''Body of TestDescription::run() for test in a non-dynamic suite'''
return suite['object'] + '.' + test['name'] + '();'
def writeSuiteDescription( output, suite ):
'''Write SuiteDescription object'''
if isDynamic( suite ):
writeDynamicDescription( output, suite )
else:
writeStaticDescription( output, suite )
def writeDynamicDescription( output, suite ):
'''Write SuiteDescription for a dynamic suite'''
output.write( 'CxxTest::DynamicSuiteDescription<%s> %s' % (suite['name'], suite['dobject']) )
if not noStaticInit:
output.write( '( %s, %s, "%s", %s, %s, %s, %s )' %
(suite['cfile'], suite['line'], suite['name'], suite['tlist'],
suite['object'], suite['create'], suite['destroy']) )
output.write( ';\n\n' )
def writeStaticDescription( output, suite ):
'''Write SuiteDescription for a static suite'''
output.write( 'CxxTest::StaticSuiteDescription %s' % suite['dobject'] )
if not noStaticInit:
output.write( '( %s, %s, "%s", %s, %s )' %
(suite['cfile'], suite['line'], suite['name'], suite['object'], suite['tlist']) )
output.write( ';\n\n' )
def writeRoot(output):
'''Write static members of CxxTest classes'''
output.write( '#include <cxxtest/Root.cpp>\n' )
def writeInitialize(output):
'''Write CxxTest::initialize(), which replaces static initialization'''
output.write( 'namespace CxxTest {\n' )
output.write( ' void initialize()\n' )
output.write( ' {\n' )
for suite in suites:
output.write( ' %s.initialize();\n' % suite['tlist'] )
if isDynamic(suite):
output.write( ' %s = 0;\n' % suite['object'] )
output.write( ' %s.initialize( %s, %s, "%s", %s, %s, %s, %s );\n' %
(suite['dobject'], suite['cfile'], suite['line'], suite['name'],
suite['tlist'], suite['object'], suite['create'], suite['destroy']) )
else:
output.write( ' %s.initialize( %s, %s, "%s", %s, %s );\n' %
(suite['dobject'], suite['cfile'], suite['line'], suite['name'],
suite['object'], suite['tlist']) )
for test in suite['tests']:
output.write( ' %s.initialize( %s, %s, %s, "%s" );\n' %
(test['object'], suite['tlist'], suite['dobject'], test['line'], test['name']) )
output.write( ' }\n' )
output.write( '}\n' )
main()

View File

@@ -0,0 +1,83 @@
#!/usr/bin/perl
die "Usage: $0 <text file> <html file> <TexInfo file>\n"
unless scalar @ARGV == 3;
my ($text, $html, $texi) = @ARGV;
open TEXT, "<$text" or die "Cannot open text file \"$text\"\n";
open HTML, ">$html" or die "Cannot create html file \"$html\"\n";
open TEXI, ">$texi" or die "Cannot create TexInfo file \"$texi\"\n";
print HTML "<html>";
sub analyze($) {
my ($line) = @_;
my ($htmlLine, $texiLine) = ($line, $line);
# command line options
$texiLine =~ s/ (--?[a-z-]*)/ \@option{$1}/g;
$htmlLine =~ s/ (--?[a-z-]*)/ <tt>$1<\/tt>/g;
# [Class::]function()
$texiLine =~ s/([^A-Za-z])(([A-Z][A-Za-z0-9]*::)?[A-Za-z0-9]+\(\))/$1\@code{$2}/g;
$htmlLine =~ s/([^A-Za-z])(([A-Z][A-Za-z0-9]*::)?[A-Za-z0-9]+\(\))/$1<code>$2<\/code>/g;
# `file'
$texiLine =~ s/`([A-Za-z.\/]*)'/\@file{$1}/g;
$htmlLine =~ s/`([A-Za-z.\/]*)'/<tt>`$1'<\/tt>/g;
# TS...
$texiLine =~ s/(^|[^A-Z])(TS[A-Za-z_*()]*)/$1\@code{$2}/g;
$htmlLine =~ s/(^|[^A-Z])(TS[A-Za-z_*()]*)/$1<code>$2<\/code>/g;
# CXXTEST_
$texiLine =~ s/(CXXTEST_[A-Z_]*)/\@code{$1}/g;
$htmlLine =~ s/(CXXTEST_[A-Z_]*)/<tt>$1<\/tt>/g;
return ($htmlLine, $texiLine);
}
my $line;
my $inRelease = 0;
while ( defined( $line = <TEXT> ) ) {
chomp $line;
if ( $line =~ m/^CxxTest Releases/ ) {
print HTML "<title>CxxTest Releases</title>\n";
print HTML "<h1>CxxTest Releases</h1>\n\n";
print TEXI "\@appendix Version history\n";
print TEXI "\@itemize \@bullet\n";
}
elsif ( $line =~ m/^(.*):$/ ) {
if ( $inRelease ) {
print HTML "</ul>\n\n";
print TEXI "\@end itemize\n";
}
print HTML "<h2>$1</h2>\n";
print HTML "<ul>\n";
print TEXI "\@item\n\@strong{$1}\n";
print TEXI "\@itemize \@minus\n";
$inRelease = 1;
}
elsif ( $line =~ m/^ - (.*)$/ ) {
my ($htmlLine, $texiLine) = analyze($1);
print HTML "<li>$htmlLine</li>\n";
print TEXI "\@item\n$texiLine\n";
}
}
if ( $inRelease ) {
print HTML "</ul>\n\n";
print TEXI "\@end itemize\n\n";
}
print HTML "</html>\n";
print TEXI "\@end itemize\n";
close TEXT or die "Error closing text file \"$text\"\n";
close HTML or die "Error closing html file \"$html\"\n";
close TEXI or die "Error closing TexInfo file \"$texi\"\n";

1959
test/cxxtest/docs/guide.html Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,56 @@
<html>
<title>CxxTest</title>
<h1>Introduction</h1>
<p>CxxTest is a JUnit/CppUnit/xUnit-like framework for C++.
<p>Its advantages over existing alternatives are that it:
<ul>
<li>Doesn't require RTTI
<li>Doesn't require member template functions
<li>Doesn't require exception handling
<li>Doesn't require any external libraries (including memory management,
file/console I/O, graphics libraries)
<li>Is distributed entirely as a set of header files
</ul>
<p>This makes it extremely portable and usable.
<p>CxxTest is available under the <a href="http://www.gnu.org/copyleft/lesser.html">GNU
Lesser General Public License</a>.
<p>See <a href="guide.html">the user's guide</a> for information.
It is also available as <a href="http://cxxtest.sourceforge.net/guide.pdf">a PDF file</a>.
<p>The version history is available <a href="http://cxxtest.sourceforge.net/Versions.html">here</a>.
<h1>Getting CxxTest</h1>
You can always get the latest release from
<a href="http://sourceforge.net/project/showfiles.php?group_id=52834">here</a> or
<a href="http://dl.sourceforge.net/cxxtest">here</a>.
<p>There are several files you can download:
<ul>
<li><code>cxxtest-<i>version</i>-1.noarch.rpm</code>
<li><code>cxxtest-<i>version</i>.tar.gz</code>
<li><code>cxxtest-<i>version</i>.zip</code>
<li><code>cxxtest-guide-<i>version</i>.pdf</code> (the user's guide)
</ul>
Note that, since CxxTest consists entirely of header files,
there is no distinction between source and binary distribution.
<p>There are also files called <code>cxxtest-selftest-*</code>: these
are used (usually by me) to test the portability of CxxTest, so you
can probably do without them.
<p>If you just can't wait for the next release, I sometimes upload betas
to <a href="http://cxxtest.sourceforge.net/beta">here</a>.
<h1>Getting started</h1>
Get the sources and build the samples in the sample subdirectory.
<br>
<p>
<A href="http://sourceforge.net"> <IMG src="http://sourceforge.net/sflogo.php?group_id=52834&type=4" border="0" alt="SourceForge Logo"></A>
</html>

BIN
test/cxxtest/docs/qt.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
test/cxxtest/docs/qt2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
test/cxxtest/docs/win32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
test/cxxtest/docs/x11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,62 @@
# -*- Perl -*-
#
# This file shows how to use CxxTest with Cons
#
$env = new cons( CXX => ("$^O" eq 'MSWin32') ? 'cl -nologo -GX' : 'c++',
CPPPATH => '..',
CXXTESTGEN => 'perl -w ../cxxtestgen.pl' );
@tests = <*.h>;
# The error printer is the most basic runner
CxxTestErrorPrinter $env 'error_printer', @tests;
# You can also specify which runner you want to use
CxxTestRunner $env 'stdio_printer', 'StdioPrinter', @tests;
# For more control, use template files
CxxTestTemplate $env 'file_printer', 'file_printer.tpl', @tests;
# Or, you can always separate the tests from the runner
CxxTest $env 'tests.cpp', '', @tests;
Program $env 'yes_no_runner', ('yes_no_runner.cpp', 'tests.cpp');
#
# Here is the code used to build these files
# You can use this in your own Construct files
#
# cons::CxxTest $env $dst, $options, @srcs
# Generates a CxxTest source file, passing the specified options to cxxtestgen
sub cons::CxxTest($$$@) {
my ($env, $dst, $options, @srcs) = @_;
Command $env $dst, @srcs, "%CXXTESTGEN -o %> ${options} %<";
}
# cons::CxxTestTemplate $env $dst, $template, @srcs
# Generates and builds a CxxTest runner using a template file
sub cons::CxxTestTemplate($$$@) {
my ($env, $dst, $template, @srcs) = @_;
my $source = "${dst}.cpp";
CxxTest $env $source, "--template=${template}", ($template, @srcs);
Program $env $dst, $source;
}
# cons::CxxTestRunner $env $dst, $runner, @srcs
# Generates and builds a CxxTest runner using the --runner option
sub cons::CxxTestRunner($$$@) {
my ($env, $dst, $runner, @srcs) = @_;
my $source = "${dst}.cpp";
CxxTest $env $source, "--runner=${runner}", @srcs;
Program $env $dst, $source;
}
# cons::CxxTestErrorPrinter $env $dst, @srcs
# Generates and builds a CxxTest ErrorPrinter
sub cons::CxxTestErrorPrinter($$@) {
my ($env, $dst, @srcs) = @_;
CxxTestRunner $env $dst, 'ErrorPrinter', @srcs;
}

View File

@@ -0,0 +1,31 @@
#ifndef __CREATEDTEST_H
#define __CREATEDTEST_H
#include <cxxtest/TestSuite.h>
#include <string.h>
#include <memory.h>
//
// This test suite shows what to do when your test case
// class cannot be instantiated statically.
// As an example, this test suite requires a non-default constructor.
//
class CreatedTest : public CxxTest::TestSuite
{
char *_buffer;
public:
CreatedTest( unsigned size ) : _buffer( new char[size] ) {}
virtual ~CreatedTest() { delete[] _buffer; }
static CreatedTest *createSuite() { return new CreatedTest( 16 ); }
static void destroySuite( CreatedTest *suite ) { delete suite; }
void test_nothing()
{
TS_FAIL( "Nothing to test" );
}
};
#endif // __CREATEDTEST_H

View File

@@ -0,0 +1,27 @@
#ifndef __DELTATEST_H
#define __DELTATEST_H
#include <cxxtest/TestSuite.h>
#include <math.h>
class DeltaTest : public CxxTest::TestSuite
{
double _pi, _delta;
public:
void setUp()
{
_pi = 3.1415926535;
_delta = 0.0001;
}
void testSine()
{
TS_ASSERT_DELTA( sin(0.0), 0.0, _delta );
TS_ASSERT_DELTA( sin(_pi / 6), 0.5, _delta );
TS_ASSERT_DELTA( sin(_pi / 2), 1.0, _delta );
TS_ASSERT_DELTA( sin(_pi), 0.0, _delta );
}
};
#endif // __DELTATEST_H

View File

@@ -0,0 +1,39 @@
//
// This is a test of CxxTest's ValueTraits for enumerations.
//
#include <cxxtest/TestSuite.h>
//
// First define your enumeration
//
enum Answer {
Yes,
No,
Maybe,
DontKnow,
DontCare
};
//
// Now make CxxTest aware of it
//
CXXTEST_ENUM_TRAITS( Answer,
CXXTEST_ENUM_MEMBER( Yes )
CXXTEST_ENUM_MEMBER( No )
CXXTEST_ENUM_MEMBER( Maybe )
CXXTEST_ENUM_MEMBER( DontKnow )
CXXTEST_ENUM_MEMBER( DontCare ) );
class EnumTraits : public CxxTest::TestSuite
{
public:
void test_Enum_traits()
{
TS_FAIL( Yes );
TS_FAIL( No );
TS_FAIL( Maybe );
TS_FAIL( DontKnow );
TS_FAIL( DontCare );
TS_FAIL( (Answer)1000 );
}
};

Some files were not shown because too many files have changed in this diff Show More