--- /dev/null
+package "mspcore-tests"
+{
+ require "mspcore";
+ require "msptest";
+
+ program "test"
+ {
+ source ".";
+ };
+
+ program "consoletest"
+ {
+ source "console/console.cpp";
+ };
+};
--- /dev/null
+#include <msp/stringcodec/ascii.h>
+#include <msp/stringcodec/utf8.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class CodecTests: public Test::RegisteredTest<CodecTests>
+{
+public:
+ CodecTests();
+
+ static const char *get_name() { return "Codec"; }
+
+private:
+ void invalid_character();
+ void invalid_sequence();
+};
+
+
+CodecTests::CodecTests()
+{
+ add(&CodecTests::invalid_character, "invalid_character").expect_throw<StringCodec::invalid_character>();
+ add(&CodecTests::invalid_sequence, "invalid_sequence").expect_throw<StringCodec::invalid_sequence>();
+}
+
+void CodecTests::invalid_character()
+{
+ StringCodec::unichar ch = 0xE4;
+ StringCodec::Ascii::Encoder enc;
+ string buf;
+ enc.encode_char(ch, buf);
+}
+
+void CodecTests::invalid_sequence()
+{
+ string str = "\343\201";
+ string::const_iterator iter = str.begin();
+ StringCodec::Utf8::Decoder dec;
+ dec.decode_char(str, iter);
+}
--- /dev/null
+#include <msp/io/console.h>
+#include <msp/io/poll.h>
+#include <msp/io/print.h>
+
+using namespace Msp;
+
+int main()
+{
+ IO::cin.set_local_echo(false);
+ IO::cin.set_line_buffer(false);
+ while(1)
+ {
+ if(IO::poll(IO::cin, IO::P_INPUT)==IO::P_INPUT)
+ {
+ char c = IO::cin.get();
+ IO::print("Got character '%c' (%02X)\n", c, c);
+ }
+ else
+ {
+ IO::print("EOF\n");
+ break;
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+#include <msp/time/datetime.h>
+#include <msp/time/timestamp.h>
+#include <msp/time/timezone.h>
+#include <msp/time/units.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class DateTimeTests: public Test::RegisteredTest<DateTimeTests>
+{
+public:
+ DateTimeTests();
+
+ static const char *get_name() { return "DateTime"; }
+
+private:
+ void add_days();
+ void add_timedelta();
+ void leap_year();
+ void format();
+ void timestamp();
+ void timezone();
+};
+
+
+DateTimeTests::DateTimeTests()
+{
+ add(&DateTimeTests::add_days, "add_days");
+ add(&DateTimeTests::add_timedelta, "+= TimeDelta");
+ add(&DateTimeTests::leap_year, "Leap years");
+ add(&DateTimeTests::format, "Formatting");
+ add(&DateTimeTests::timestamp, "Timestamp conversion");
+ add(&DateTimeTests::timezone, "Timezone conversion");
+}
+
+void DateTimeTests::add_days()
+{
+ Time::DateTime dt(2010, 1, 1);
+ dt.add_days(1);
+ EXPECT_EQUAL(dt, Time::DateTime(2010, 1, 2));
+ dt.add_days(57);
+ EXPECT_EQUAL(dt, Time::DateTime(2010, 2, 28));
+ dt.add_days(307);
+ EXPECT_EQUAL(dt, Time::DateTime(2011, 1, 1));
+ dt.add_days(-366);
+ EXPECT_EQUAL(dt, Time::DateTime(2009, 12, 31));
+}
+
+void DateTimeTests::add_timedelta()
+{
+ Time::DateTime dt(2010, 1, 1, 23, 50, 0);
+ dt += 20*Time::min;
+ EXPECT_EQUAL(dt, Time::DateTime(2010, 1, 2, 0, 10, 0));
+ dt += 23*Time::hour+50*Time::min;
+ EXPECT_EQUAL(dt, Time::DateTime(2010, 1, 3));
+ dt += 52*Time::week;
+ EXPECT_EQUAL(dt, Time::DateTime(2011, 1, 2));
+}
+
+void DateTimeTests::leap_year()
+{
+ Time::DateTime dt(1996, 2, 1);
+ dt.add_days(29);
+ EXPECT_EQUAL(dt, Time::DateTime(1996, 3, 1));
+
+ dt = Time::DateTime(2000, 2, 1);
+ dt.add_days(29);
+ EXPECT_EQUAL(dt, Time::DateTime(2000, 3, 1));
+
+ dt = Time::DateTime(2100, 2, 1);
+ dt.add_days(29);
+ EXPECT_EQUAL(dt, Time::DateTime(2100, 3, 2));
+
+ dt = Time::DateTime(1996, 2, 1);
+ dt.add_days(8*365);
+ EXPECT_EQUAL(dt, Time::DateTime(2004, 1, 30));
+
+ dt = Time::DateTime(2096, 2, 1);
+ dt.add_days(8*365);
+ EXPECT_EQUAL(dt, Time::DateTime(2104, 1, 31));
+
+ dt = Time::DateTime(2010, 2, 1);
+ dt.add_days(400*365+96);
+ EXPECT_EQUAL(dt, Time::DateTime(2410, 1, 31));
+}
+
+void DateTimeTests::format()
+{
+ Time::DateTime dt(2010, 4, 27, 13, 57, 12);
+ EXPECT_EQUAL(dt.format("%Y-%m-%d"), "2010-04-27");
+ EXPECT_EQUAL(dt.format("%d%m%y"), "270410");
+ EXPECT_EQUAL(dt.format("%H:%M:%S"), "13:57:12");
+ EXPECT_EQUAL(dt.format("%I:%M %p"), "01:57 PM");
+ EXPECT_EQUAL(Time::DateTime(2010, 4, 27, 12, 0, 0).format("%p"), "PM");
+ EXPECT_EQUAL(dt.format_rfc3339(), "2010-04-27T13:57:12Z");
+ dt.set_timezone(Time::TimeZone(120));
+ EXPECT_EQUAL(dt.format_rfc3339(), "2010-04-27T13:57:12+02:00");
+}
+
+void DateTimeTests::timestamp()
+{
+ Time::DateTime dt(2010, 1, 1);
+ Time::TimeStamp ts = dt.get_timestamp();
+ Time::DateTime dt2(ts);
+ EXPECT_EQUAL(dt, dt2);
+}
+
+void DateTimeTests::timezone()
+{
+ Time::DateTime dt(2010, 1, 1, 2, 0, 0);
+ dt.convert_timezone(Time::TimeZone(120));
+ EXPECT_EQUAL(dt, Time::DateTime(2010, 1, 1, 4, 0, 0));
+ dt.convert_timezone(Time::TimeZone(-300));
+ EXPECT_EQUAL(dt, Time::DateTime(2009, 12, 31, 21, 0, 0));
+ dt.convert_timezone(Time::TimeZone::utc());
+ EXPECT_EQUAL(dt, Time::DateTime(2010, 1, 1, 2, 0, 0));
+}
--- /dev/null
+#include <msp/core/systemerror.h>
+#include <msp/io/file.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class FileTests: public Test::RegisteredTest<FileTests>
+{
+public:
+ FileTests();
+
+ static const char *get_name() { return "File"; }
+
+private:
+ void write();
+ void read();
+ void seek();
+ void file_not_found();
+ void invalid_access();
+};
+
+
+FileTests::FileTests()
+{
+ add(&FileTests::write, "Writing");
+ add(&FileTests::read, "Reading");
+ add(&FileTests::seek, "Seeking");
+ add(&FileTests::file_not_found, "file_not_found").expect_throw<IO::file_not_found>();
+ add(&FileTests::invalid_access, "invalid_access").expect_throw<IO::invalid_access>();
+}
+
+void FileTests::write()
+{
+ IO::File out("test.txt", IO::M_WRITE);
+ out.write("foobar\n");
+ out.write("quux\n");
+}
+
+void FileTests::read()
+{
+ IO::File in("test.txt");
+
+ string line;
+ EXPECT(in.getline(line));
+ EXPECT_EQUAL(line, "foobar");
+
+ char buf[128];
+ unsigned len = in.read(buf, sizeof(buf));
+ EXPECT_EQUAL(len, 5U);
+ EXPECT_EQUAL(string(buf, len), "quux\n");
+
+ len = in.read(buf, sizeof(buf));
+ EXPECT_EQUAL(len, 0U);
+ EXPECT(in.eof());
+}
+
+void FileTests::seek()
+{
+ IO::File in("test.txt");
+
+ IO::SeekOffset pos = in.seek(3, IO::S_BEG);
+ EXPECT_EQUAL(pos, 3);
+ char c = in.get();
+ EXPECT_EQUAL(c, 'b');
+
+ pos = in.seek(1, IO::S_CUR);
+ EXPECT_EQUAL(pos, 5);
+ c = in.get();
+ EXPECT_EQUAL(c, 'r');
+
+ pos = in.seek(-2, IO::S_END);
+ EXPECT_EQUAL(pos, 10);
+ c = in.get();
+ EXPECT_EQUAL(c, 'x');
+}
+
+void FileTests::file_not_found()
+{
+ IO::File in("does.not.exist");
+}
+
+void FileTests::invalid_access()
+{
+ IO::File in("test.txt");
+ in.write("foo\n");
+}
--- /dev/null
+#include <msp/core/getopt.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class GetOptTests: public Test::RegisteredTest<GetOptTests>
+{
+public:
+ GetOptTests();
+
+ static const char *get_name() { return "GetOpt"; }
+
+private:
+ void short_options();
+ void long_options();
+ void arguments();
+ void non_options();
+ void help();
+ void invalid_option();
+ void invalid_arg();
+ void missing_arg();
+};
+
+GetOptTests::GetOptTests()
+{
+ add(&GetOptTests::short_options, "Short options");
+ add(&GetOptTests::long_options, "Long options");
+ add(&GetOptTests::arguments, "Option arguments");
+ add(&GetOptTests::non_options, "Non-options");
+ add(&GetOptTests::help, "Help").expect_throw<usage_error>();
+ add(&GetOptTests::invalid_option, "Invalid option").expect_throw<usage_error>();
+ add(&GetOptTests::invalid_arg, "Invalid argument").expect_throw<usage_error>();
+ add(&GetOptTests::missing_arg, "Missing argument").expect_throw<usage_error>();
+}
+
+void GetOptTests::short_options()
+{
+ static const char *argv[] = { "test", "-a", "-bc", 0 };
+
+ bool a = false;
+ bool b = false;
+ bool c = false;
+
+ GetOpt getopt;
+ getopt.add_option('a', "a", a, GetOpt::NO_ARG);
+ getopt.add_option('b', "b", b, GetOpt::NO_ARG);
+ getopt.add_option('c', "c", c, GetOpt::NO_ARG);
+ getopt(3, argv);
+
+ EXPECT(a && b && c);
+}
+
+void GetOptTests::long_options()
+{
+ static const char *argv[] = { "test", "--foo", "--bar", 0 };
+
+ bool foo = false;
+ bool bar = false;
+
+ GetOpt getopt;
+ getopt.add_option("foo", foo, GetOpt::NO_ARG);
+ getopt.add_option("bar", bar, GetOpt::NO_ARG);
+ getopt(3, argv);
+
+ EXPECT(foo && bar);
+}
+
+void GetOptTests::arguments()
+{
+ static const char *argv[] = { "test", "-aabc", "-b", "x y z", "--foo=42", "--bar", "69", 0 };
+
+ string a;
+ string b;
+ int foo = 0;
+ int bar = 0;
+
+ GetOpt getopt;
+ getopt.add_option('a', "a", a, GetOpt::REQUIRED_ARG);
+ getopt.add_option('b', "b", b, GetOpt::REQUIRED_ARG);
+ getopt.add_option("foo", foo, GetOpt::REQUIRED_ARG);
+ getopt.add_option("bar", bar, GetOpt::REQUIRED_ARG);
+ getopt(7, argv);
+
+ EXPECT_EQUAL(a, "abc");
+ EXPECT_EQUAL(b, "x y z");
+ EXPECT_EQUAL(foo, 42);
+ EXPECT_EQUAL(bar, 69);
+}
+
+void GetOptTests::non_options()
+{
+ static const char *argv[] = { "test", "-a", "foo", "-b", "bar", "baz", 0 };
+
+ bool a = false;
+ bool b = false;
+
+ GetOpt getopt;
+ getopt.add_option('a', "a", a, GetOpt::NO_ARG);
+ getopt.add_option('b', "b", b, GetOpt::NO_ARG);
+ getopt(6, argv);
+
+ EXPECT(a && b);
+ EXPECT_EQUAL(getopt.get_args().size(), 3U);
+}
+
+void GetOptTests::help()
+{
+ static const char *argv[] = { "test", "--help", 0 };
+
+ GetOpt getopt;
+ getopt(2, argv);
+}
+
+void GetOptTests::invalid_option()
+{
+ static const char *argv[] = { "test", "--invalid", 0 };
+
+ GetOpt getopt;
+ getopt(2, argv);
+}
+
+void GetOptTests::invalid_arg()
+{
+ static const char *argv[] = { "test", "--intval=foo", 0 };
+
+ int value;
+ GetOpt getopt;
+ getopt.add_option("intval", value, GetOpt::REQUIRED_ARG);
+ getopt(2, argv);
+}
+
+void GetOptTests::missing_arg()
+{
+ static const char *argv[] = { "test", "--value", 0 };
+
+ string value;
+ GetOpt getopt;
+ getopt.add_option("value", value, GetOpt::REQUIRED_ARG);
+ getopt(2, argv);
+}
--- /dev/null
+#include <map>
+#include <msp/core/maputils.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class MapUtilTests: public Test::RegisteredTest<MapUtilTests>
+{
+public:
+ MapUtilTests();
+
+ static const char *get_name() { return "maputils"; }
+
+private:
+ void success();
+ void error();
+};
+
+
+MapUtilTests::MapUtilTests()
+{
+ add(&MapUtilTests::success, "success");
+ add(&MapUtilTests::error, "error").expect_throw<key_error>();
+}
+
+void MapUtilTests::success()
+{
+ map<int, string> m;
+ m[1] = "foo";
+ m[3] = "bar";
+ EXPECT_EQUAL(get_item(m, 1), "foo");
+ EXPECT_EQUAL(get_item(m, 3), "bar");
+}
+
+void MapUtilTests::error()
+{
+ map<int, string> m;
+ get_item(m, 0);
+}
--- /dev/null
+#include <msp/io/memory.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class MemoryTests: public Test::RegisteredTest<MemoryTests>
+{
+public:
+ MemoryTests();
+
+ static const char *get_name() { return "Memory"; }
+
+private:
+ void write();
+ void read();
+ void getline();
+ void invalid_access();
+};
+
+
+MemoryTests::MemoryTests()
+{
+ add(&MemoryTests::write, "write");
+ add(&MemoryTests::read, "read");
+ add(&MemoryTests::getline, "getline");
+ add(&MemoryTests::invalid_access, "invalid_access").expect_throw<IO::invalid_access>();
+}
+
+void MemoryTests::write()
+{
+ char buf[64] = { };
+ IO::Memory mem(buf, sizeof(buf));
+ mem.write("foobar");
+ EXPECT(equal(buf, buf+6, "foobar"));
+ for(unsigned i=6; i<sizeof(buf); ++i)
+ if(buf[i]!=0)
+ fail("Garbage in buffer");
+}
+
+void MemoryTests::read()
+{
+ static const char buf[] = "foobar";
+
+ IO::Memory mem(buf, 6);
+ char rbuf[16];
+ unsigned len = mem.read(rbuf, sizeof(rbuf));
+ EXPECT_EQUAL(len, 6);
+ EXPECT(equal(rbuf, rbuf+6, buf));
+}
+
+void MemoryTests::getline()
+{
+ static const char buf[] = "foobar\n\nquux\n";
+
+ IO::Memory mem(buf, sizeof(buf)-1);
+ string line;
+ EXPECT(mem.getline(line));
+ EXPECT_EQUAL(line, "foobar");
+ EXPECT(mem.getline(line));
+ EXPECT_EQUAL(line, "");
+ EXPECT(mem.getline(line));
+ EXPECT_EQUAL(line, "quux");
+ EXPECT(!mem.getline(line));
+}
+
+void MemoryTests::invalid_access()
+{
+ static const char buf[] = "foobar";
+
+ IO::Memory mem(buf, sizeof(buf));
+ mem.write("quux", 4);
+}
--- /dev/null
+#include <msp/core/thread.h>
+#include <msp/io/pipe.h>
+#include <msp/io/poll.h>
+#include <msp/time/units.h>
+#include <msp/test/test.h>
+
+using namespace Msp;
+
+class PipeTests: public Test::RegisteredTest<PipeTests>
+{
+public:
+ PipeTests();
+
+ static const char *get_name() { return "Pipe"; }
+
+private:
+ void readwrite();
+ void poll();
+};
+
+
+class PipeWriter: public Thread
+{
+private:
+ IO::Pipe &pipe;
+
+public:
+ PipeWriter(IO::Pipe &);
+
+private:
+ virtual void main();
+};
+
+
+PipeTests::PipeTests()
+{
+ add(&PipeTests::readwrite, "Read/write");
+ add(&PipeTests::poll, "Poll");
+}
+
+void PipeTests::readwrite()
+{
+ IO::Pipe pipe;
+ PipeWriter writer(pipe);
+
+ for(unsigned i=0; i<256; ++i)
+ {
+ unsigned char c = pipe.get();
+ if(c!=i)
+ fail("Invalid data");
+ }
+
+ writer.join();
+}
+
+void PipeTests::poll()
+{
+ IO::Pipe pipe;
+
+ pipe.put(1);
+ IO::PollEvent ev = IO::poll(pipe, IO::P_INPUT);
+ EXPECT_EQUAL(ev, IO::P_INPUT);
+
+ pipe.get();
+
+ ev = IO::poll(pipe, IO::P_INPUT, 100*Time::msec);
+ EXPECT_EQUAL(ev, IO::P_NONE);
+}
+
+
+PipeWriter::PipeWriter(IO::Pipe &p):
+ pipe(p)
+{
+ launch();
+}
+
+void PipeWriter::main()
+{
+ for(unsigned i=0; i<256; ++i)
+ pipe.put(i);
+}
--- /dev/null
+#include <list>
+#include <vector>
+#include <msp/core/thread.h>
+#include <msp/time/units.h>
+#include <msp/time/utils.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class ThreadTests: public Test::RegisteredTest<ThreadTests>
+{
+private:
+ std::vector<int> data;
+
+public:
+ ThreadTests();
+
+ static const char *get_name() { return "Thread"; }
+
+private:
+ void single();
+ void multiple();
+};
+
+
+class TestThread: public Thread
+{
+private:
+ int *start;
+ unsigned count;
+ unsigned step;
+ int value;
+ bool done;
+
+public:
+ TestThread(int *, unsigned, unsigned, int);
+
+private:
+ virtual void main();
+
+public:
+ bool is_done() const { return done; }
+};
+
+
+ThreadTests::ThreadTests():
+ data(1000000)
+{
+ add(&ThreadTests::single, "Single thread");
+ add(&ThreadTests::multiple, "Multiple threads");
+}
+
+void ThreadTests::single()
+{
+ fill(data.begin(), data.end(), -1);
+
+ TestThread thread(&data[0], data.size(), 1, 1);
+ unsigned wait = 100;
+ while(wait && !thread.is_done())
+ {
+ Time::sleep(100*Time::msec);
+ --wait;
+ }
+
+ if(!wait)
+ fail("Thread did not finish");
+
+ thread.join();
+
+ for(vector<int>::iterator i=data.begin(); i!=data.end(); ++i)
+ if(*i!=1)
+ fail("Invalid data");
+}
+
+void ThreadTests::multiple()
+{
+ fill(data.begin(), data.end(), -1);
+
+ list<TestThread *> threads;
+ for(unsigned i=0; i<10; ++i)
+ threads.push_back(new TestThread(&data[i], data.size()/10, 10, i+1));
+ unsigned wait = 100;
+ while(wait && !threads.empty())
+ {
+ Time::sleep(100*Time::msec);
+ for(list<TestThread *>::iterator i=threads.begin(); i!=threads.end();)
+ {
+ if((*i)->is_done())
+ {
+ (*i)->join();
+ delete *i;
+ threads.erase(i++);
+ }
+ else
+ ++i;
+ }
+ --wait;
+ }
+
+ if(!wait)
+ fail("Threads did not finish");
+
+ for(unsigned i=0; i<data.size(); ++i)
+ if(data[i]!=static_cast<int>(i%10+1))
+ fail("Invalid data");
+}
+
+
+TestThread::TestThread(int *s, unsigned c, unsigned t, int v):
+ start(s),
+ count(c),
+ step(t),
+ value(v),
+ done(false)
+{
+ launch();
+}
+
+void TestThread::main()
+{
+ int *ptr = start;
+ for(unsigned i=0; i<count; ++i)
+ {
+ *ptr = value;
+ ptr += step;
+ }
+ done = true;
+}
--- /dev/null
+#include <msp/time/units.h>
+#include <msp/time/timezone.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class TimeZoneTests: public Test::RegisteredTest<TimeZoneTests>
+{
+public:
+ TimeZoneTests();
+
+ static const char *get_name() { return "TimeZone"; }
+
+private:
+ void utc();
+ void local();
+ void custom();
+};
+
+
+TimeZoneTests::TimeZoneTests()
+{
+ add(&TimeZoneTests::utc, "UTC");
+ add(&TimeZoneTests::local, "Local");
+ add(&TimeZoneTests::custom, "Custom");
+}
+
+void TimeZoneTests::utc()
+{
+ Time::TimeZone tz = Time::TimeZone::utc();
+ EXPECT_EQUAL(tz.get_name(), "UTC");
+ EXPECT_EQUAL(tz.get_offset(), Time::zero);
+}
+
+void TimeZoneTests::local()
+{
+ Time::TimeZone tz = Time::TimeZone::local();
+ info(format("'%s' %s", tz.get_name(), tz.get_offset()));
+}
+
+void TimeZoneTests::custom()
+{
+ Time::TimeZone tz1(120);
+ EXPECT_EQUAL(tz1.get_name(), "UTC+2");
+ Time::TimeZone tz2(345);
+ EXPECT_EQUAL(tz2.get_name(), "UTC+5:45");
+}
--- /dev/null
+#include <msp/core/variant.h>
+#include <msp/test/test.h>
+
+using namespace std;
+using namespace Msp;
+
+class VariantTests: public Test::RegisteredTest<VariantTests>
+{
+public:
+ VariantTests();
+
+ static const char *get_name() { return "Variant"; }
+
+private:
+ void integer();
+ void stdstring();
+ void pointer();
+ void ref_into();
+ void copying();
+ void destruction();
+ void types();
+ void mismatch();
+};
+
+class Counter
+{
+private:
+ int &count;
+
+public:
+ Counter(int &c): count(c) { ++count; }
+ Counter(const Counter &c): count(c.count) { ++count; }
+ ~Counter() { --count; }
+};
+
+VariantTests::VariantTests()
+{
+ add(&VariantTests::integer, "Integer");
+ add(&VariantTests::stdstring, "std::string");
+ add(&VariantTests::pointer, "Pointer");
+ add(&VariantTests::ref_into, "Reference into");
+ add(&VariantTests::copying, "Copying");
+ add(&VariantTests::destruction, "Destruction");
+ add(&VariantTests::types, "Type checks");
+ add(&VariantTests::mismatch, "Mismatch").expect_throw<type_mismatch>();
+}
+
+void VariantTests::integer()
+{
+ Variant var = 42;
+ EXPECT_EQUAL(var.value<int>(), 42);
+}
+
+void VariantTests::stdstring()
+{
+ Variant var = string("foobar");
+ EXPECT_EQUAL(var.value<string>(), "foobar");
+}
+
+void VariantTests::pointer()
+{
+ int i = 7;
+ Variant var = &i;
+ *var.value<int *>() = 42;
+ EXPECT_EQUAL(i, 42);
+}
+
+void VariantTests::ref_into()
+{
+ Variant var = 7;
+ int &r = var.value<int>();
+ r = 42;
+ EXPECT_EQUAL(var.value<int>(), 42);
+}
+
+void VariantTests::copying()
+{
+ Variant var = 42;
+ Variant var2 = var;
+ EXPECT_EQUAL(var2.value<int>(), 42);
+}
+
+void VariantTests::destruction()
+{
+ int count = 0;
+ {
+ Variant var = Counter(count);
+ Variant var2 = var;
+ EXPECT_EQUAL(count, 2);
+ Variant var3;
+ var3 = var;
+ EXPECT_EQUAL(count, 3);
+ var2 = Variant();
+ EXPECT_EQUAL(count, 2);
+ }
+ EXPECT_EQUAL(count, 0);
+}
+
+void VariantTests::types()
+{
+ Variant var = 42U;
+ EXPECT(!var.check_type<int>());
+ EXPECT(var.check_type<unsigned>());
+ EXPECT(!var.check_type<float>());
+ EXPECT(!var.check_type<bool>());
+ EXPECT(!var.check_type<string>());
+}
+
+void VariantTests::mismatch()
+{
+ Variant var = 1;
+ var.value<string>();
+}