aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/common/span.h789
-rw-r--r--test/common/str.h23
-rw-r--r--test/engines/wintermute/path_utils.h236
-rw-r--r--test/module.mk5
4 files changed, 1053 insertions, 0 deletions
diff --git a/test/common/span.h b/test/common/span.h
new file mode 100644
index 0000000000..d73a2e2266
--- /dev/null
+++ b/test/common/span.h
@@ -0,0 +1,789 @@
+#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() : super_type() {}
+ 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() : super_type() {}
+ 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() : super_type() {}
+ 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() : super_type() {}
+ 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);
+#ifdef SCUMM_LITTLE_ENDIAN
+ TS_ASSERT_EQUALS((it + 3).getUint32(), 4278256131U);
+#elif 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.release();
+ TS_ASSERT_EQUALS((bool)owner2, false);
+ }
+
+ {
+ Common::SpanOwner<Common::Span<byte> > owner2;
+ TS_ASSERT_EQUALS((bool)owner, true);
+ void *dataPtr = owner->data();
+ owner2 = 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);
+ void *dataPtr = owner->data();
+ TS_ASSERT_EQUALS(owner.release(), dataPtr);
+ TS_ASSERT_EQUALS((bool)owner, false);
+ }
+ }
+
+ 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.release();
+ TS_ASSERT_EQUALS((bool)owner2, false);
+ }
+
+ {
+ Common::SpanOwner<Common::NamedSpan<byte> > owner2;
+ TS_ASSERT_EQUALS((bool)owner, true);
+ void *dataPtr = owner->data();
+ owner2 = 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);
+ void *dataPtr = owner->data();
+ TS_ASSERT_EQUALS(owner.release(), dataPtr);
+ TS_ASSERT_EQUALS((bool)owner, false);
+ }
+ }
+
+ 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);
+
+#ifdef SCUMM_LITTLE_ENDIAN
+ TS_ASSERT_EQUALS(span.getUint32At(3), 4278256131U);
+#elif 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");
+ 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);
+
+#ifdef SCUMM_LITTLE_ENDIAN
+ TS_ASSERT_EQUALS(span.subspan<uint16>(0)[1], 4 << 8 | 3);
+#elif 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);
+
+#ifdef SCUMM_LITTLE_ENDIAN
+ TS_ASSERT_EQUALS(span.subspan<uint16>(0)[1], 4 << 8 | 3);
+#elif 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 ptrdiff_t big = 1L << (8 * sizeof(ptrdiff_t) - 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(-34, -56, Common::kValidateSeek);
+ expected = Common::String::format("Access violation seeking %s: -34 + -56 > 1", source.c_str());
+ TS_ASSERT_EQUALS(actual, expected);
+ }
+
+ void test_span_comparators() {
+ byte data[2];
+ 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: -34 + -56 > 4 (abs: -32 + -56 > 6)";
+ actual = subspan.getValidationMessage(-34, -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: -34 + -56 > 4 (abs: -34 + -56 > 4)";
+ actual = subspan.getValidationMessage(-34, -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: -34 + -56 > 4 (abs: -32 + -56 > 6)";
+ actual = subspan.getValidationMessage(-34, -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: -34 + -56 > 4 (abs: -34 + -56 > 4)";
+ actual = subspan.getValidationMessage(-34, -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: -34 + -56 > 4 (abs: -32 + -56 > 6)";
+ actual = subspan.getValidationMessage(-34, -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]);
+ }
+ }
+ }
+};
diff --git a/test/common/str.h b/test/common/str.h
index c59c5a5efd..b7ad28e56e 100644
--- a/test/common/str.h
+++ b/test/common/str.h
@@ -403,6 +403,29 @@ class StringTestSuite : public CxxTest::TestSuite
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);
diff --git a/test/engines/wintermute/path_utils.h b/test/engines/wintermute/path_utils.h
new file mode 100644
index 0000000000..26f3404396
--- /dev/null
+++ b/test/engines/wintermute/path_utils.h
@@ -0,0 +1,236 @@
+#include <cxxtest/TestSuite.h>
+#include "engines/wintermute/utils/path_util.h"
+/**
+ * Test suite for the functions in engines/wintermute/utils/path_util.h
+ *
+ * NOTE: This is not a prescription;
+ * this was not written by the original engine author;
+ * this was not written by the engine porter.
+ *
+ * It might, however, help to spot variations in behavior that are introduced by modifications
+ */
+
+class PathUtilTestSuite : public CxxTest::TestSuite {
+ public:
+ const Common::String unixPath;
+ const Common::String unixCapPath;
+ const Common::String windowsPath;
+ const Common::String windowsCapPath;
+ const Common::String emptyString;
+ const Common::String dualExtPath;
+ const Common::String manyExtPath;
+ const Common::String mixedSlashesPath1;
+ const Common::String mixedSlashesPath2;
+ const Common::String unixRelativePath;
+ const Common::String windowsRelativePath;
+ const Common::String unixDirPath;
+ const Common::String windowsDirPath;
+ PathUtilTestSuite () :
+ unixPath("/some/file.ext"),
+ unixCapPath("/SOME/FILE.EXT"),
+ windowsPath("C:\\some\\file.ext"),
+ windowsCapPath("C:\\SOME\\FILE.EXT"),
+ emptyString(""),
+ dualExtPath("/some/file.tar.gz"),
+ manyExtPath("/some/file.tar.bz2.gz.zip"),
+ mixedSlashesPath1("C:\\this/IS_REALLY\\weird.exe"),
+ mixedSlashesPath2("/pretty\\weird/indeed.txt"),
+ unixRelativePath("some/file.ext"),
+ windowsRelativePath("some\\file.ext"),
+ unixDirPath("/some/dir/"),
+ windowsDirPath("C:\\some\\dir\\")
+ {}
+ void test_getdirectoryname() {
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(unixPath),
+ Common::String("/some/")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(unixCapPath),
+ Common::String("/SOME/")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(windowsPath),
+ Common::String("C:\\some\\")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(windowsCapPath),
+ Common::String("C:\\SOME\\")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(emptyString),
+ Common::String("")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(unixDirPath),
+ Common::String("/some/dir/")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(windowsDirPath),
+ Common::String("C:\\some\\dir\\")
+ );
+ }
+
+ void test_getfilename() {
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(unixPath),
+ Common::String("file.ext")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(unixCapPath),
+ Common::String("FILE.EXT")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(windowsPath),
+ Common::String("file.ext")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(windowsCapPath),
+ Common::String("FILE.EXT")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(emptyString),
+ Common::String("")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(unixRelativePath),
+ Common::String("file.ext")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(windowsRelativePath),
+ Common::String("file.ext")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(windowsDirPath),
+ Common::String("")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileName(unixDirPath),
+ Common::String("")
+ );
+ }
+
+ void test_getextension() {
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getExtension(windowsPath),
+ Common::String("ext")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getExtension(windowsCapPath),
+ Common::String("EXT")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getExtension(emptyString),
+ Common::String("")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getExtension(dualExtPath),
+ Common::String("gz")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getExtension(manyExtPath),
+ Common::String("zip")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getExtension(unixRelativePath),
+ Common::String("ext")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getExtension(windowsRelativePath),
+ Common::String("ext")
+ );
+ }
+
+ void test_getfilenamewithoutextension() {
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileNameWithoutExtension(windowsPath),
+ Common::String("file")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileNameWithoutExtension(windowsCapPath),
+ Common::String("FILE")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileNameWithoutExtension(emptyString),
+ Common::String("")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileNameWithoutExtension(dualExtPath),
+ Common::String("file.tar")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileNameWithoutExtension(manyExtPath),
+ Common::String("file.tar.bz2.gz")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileNameWithoutExtension(unixRelativePath),
+ Common::String("file")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getFileNameWithoutExtension(windowsRelativePath),
+ Common::String("file")
+ );
+ }
+
+ void test_combine_identity() {
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(windowsPath) +
+ Wintermute::PathUtil::getFileNameWithoutExtension(windowsPath) +
+ "." +
+ Wintermute::PathUtil::getExtension(windowsPath),
+ windowsPath
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(windowsCapPath) +
+ Wintermute::PathUtil::getFileNameWithoutExtension(windowsCapPath) +
+ "." +
+ Wintermute::PathUtil::getExtension(windowsCapPath),
+ windowsCapPath
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(unixCapPath) +
+ Wintermute::PathUtil::getFileNameWithoutExtension(unixCapPath) +
+ "." +
+ Wintermute::PathUtil::getExtension(unixCapPath),
+ unixCapPath
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::getDirectoryName(manyExtPath) +
+ Wintermute::PathUtil::getFileNameWithoutExtension(manyExtPath) +
+ "." +
+ Wintermute::PathUtil::getExtension(manyExtPath),
+ manyExtPath
+ );
+ }
+
+ void test_normalize() {
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::normalizeFileName(windowsCapPath),
+ Common::String("c:/some/file.ext")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::normalizeFileName(windowsPath),
+ Common::String("c:/some/file.ext")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::normalizeFileName(mixedSlashesPath1),
+ Common::String("c:/this/is_really/weird.exe")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::normalizeFileName(mixedSlashesPath2),
+ Common::String("/pretty/weird/indeed.txt")
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::normalizeFileName(emptyString),
+ emptyString
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::normalizeFileName(unixRelativePath),
+ unixRelativePath
+ );
+ TS_ASSERT_EQUALS(
+ Wintermute::PathUtil::normalizeFileName(windowsRelativePath),
+ unixRelativePath // NOT windows
+ );
+ }
+};
diff --git a/test/module.mk b/test/module.mk
index 11ee6bd200..04e7deeacd 100644
--- a/test/module.mk
+++ b/test/module.mk
@@ -8,6 +8,11 @@
TESTS := $(srcdir)/test/common/*.h $(srcdir)/test/audio/*.h
TEST_LIBS := audio/libaudio.a common/libcommon.a
+ifdef ENABLE_WINTERMUTE
+ TESTS += $(srcdir)/test/engines/wintermute/*.h
+ TEST_LIBS += engines/wintermute/libwintermute.a
+endif
+
#
TEST_FLAGS := --runner=StdioPrinter --no-std --no-eh --include=$(srcdir)/test/cxxtest_mingw.h
TEST_CFLAGS := -I$(srcdir)/test/cxxtest