changeset 27:fc315d786f24 experimental

Added unit testing.
author Jacob Carlborg <doob@me.com>
date Fri, 19 Nov 2010 11:14:55 +0100
parents 78e5fef4bbf2
children bffcbc8c392b
files .hgignore dsss.conf orange/_.d orange/core/string.d orange/serialization/Serializer orange/serialization/Serializer.d orange/test/UnitTester.d orange/util/Traits.d orange/util/collection/Array.d tests/Serializer.d tests/all.d
diffstat 11 files changed, 1249 insertions(+), 291 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue Oct 19 10:22:10 2010 +0200
+++ b/.hgignore	Fri Nov 19 11:14:55 2010 +0100
@@ -16,4 +16,5 @@
 *.framework
 kandil
 lib
-import
\ No newline at end of file
+import
+unittest
\ No newline at end of file
--- a/dsss.conf	Tue Oct 19 10:22:10 2010 +0200
+++ b/dsss.conf	Fri Nov 19 11:14:55 2010 +0100
@@ -1,3 +1,11 @@
 #[orange/serialization/Serializer.d]
-[main.d]
-#[orange]
\ No newline at end of file
+
+#[main.d]
+
+
+#[orange]
+
+[tests/all.d]
+buildflags += -unittest
+target = unittest
+version += OrangeUnitTest
\ No newline at end of file
--- a/orange/_.d	Tue Oct 19 10:22:10 2010 +0200
+++ b/orange/_.d	Fri Nov 19 11:14:55 2010 +0100
@@ -8,6 +8,7 @@
 
 public:
 
+import orange.core._;
 import orange.serialization._;
 import orange.serialization.archives._;
 import orange.util._;
\ No newline at end of file
--- a/orange/core/string.d	Tue Oct 19 10:22:10 2010 +0200
+++ b/orange/core/string.d	Fri Nov 19 11:14:55 2010 +0100
@@ -48,6 +48,8 @@
 	alias std.string.toString fromStringz;
 }
 
+import orange.util.Traits;
+
 version (Tango)
 {
 	/**
@@ -885,4 +887,54 @@
 		
 		return i;
 	}
+}
+
+T[] replace (T) (T[] source, dchar match, dchar replacement)
+{
+	static assert(isChar!(T), `The type "` ~ T.stringof ~ `" is not a valid type for this function only strings are accepted`);
+	
+	dchar endOfCodeRange;
+	
+	static if (is(T == wchar))
+	{
+		const encodedLength = 2;
+		endOfCodeRange = wchar.init;
+	}
+	
+	else static if (is(T == char))
+	{
+		const encodedLength = 4;
+		endOfCodeRange = '\x7F';
+	}
+	
+	if (replacement <= endOfCodeRange && match <= endOfCodeRange)
+	{
+		foreach (ref c ; source)
+			if (c == match)
+				c = replacement;
+		
+		return source;
+	}
+	
+	else
+	{
+		static if (!is(T == dchar))
+		{
+			T[encodedLength] encodedMatch;
+			T[encodedLength] encodedReplacement;
+			
+			version (Tango)
+				return source.substitute(encode(encodedMatch, match), encode(encodedReplacement, replacement));
+			
+			else
+			{
+				auto matchLength = encode(encodedMatch, match);
+				auto replacementLength = encode(encodedReplacement, replacement);
+				
+				return std.string.replace(source, encodedMatch[0 .. matchLength], encodedReplacement[0 .. replacementLength]);
+			}
+		}
+	}
+	
+	return source;
 }
\ No newline at end of file
Binary file orange/serialization/Serializer has changed
--- a/orange/serialization/Serializer.d	Tue Oct 19 10:22:10 2010 +0200
+++ b/orange/serialization/Serializer.d	Fri Nov 19 11:14:55 2010 +0100
@@ -956,103 +956,20 @@
 		return annotations;
 	}
 }
-
-
-
-debug (OrangeUnitTest)
-{
-	import orange.serialization.archives.XMLArchive;
-
-	enum Foo { a, b, c }
-	typedef int Int;
-	
-	class A {}
-	struct B {}
-	class C { string str; }
-	class D { int[] arr; }
-	class E { int[int] aa; }
-	class F { int value; int* ptr; }
-	class G { Foo foo; }
-	
-	class H
-	{
-		bool bool_;
-		byte byte_;
-		//cdouble cdouble_; // currently not suppported by to!()
-		//cent cent_; // currently not implemented but a reserved keyword
-		//cfloat cfloat_; // currently not suppported by to!()
-		char char_;
-		//creal creal_; // currently not suppported by to!()
-		dchar dchar_;
-		double double_;
-		float float_;
-		//idouble idouble_; // currently not suppported by to!()
-		//ifloat ifloat_; // currently not suppported by to!()
-		int int_;
-		//ireal ireal_;  // currently not suppported by to!()
-		long long_;
-		real real_;
-		short short_;
-		ubyte ubyte_;
-		//ucent ucent_; // currently not implemented but a reserved keyword
-		uint uint_;
-		ulong ulong_;
-		ushort ushort_;
-		wchar wchar_;
-		
-		equals_t opEquals (Object other)
-		{
-			if (auto o =  cast(H) other)
-			{
-				return bool_ == o.bool_ &&
-					   byte_ == o.byte_ &&
-					   //cdouble_ == o.cdouble_ && // currently not suppported by to!()
-					   //cent_ == o.cent_ && // currently not implemented but a reserved keyword
-					   //cfloat_ == o.cfloat_ && // currently not suppported by to!()
-					   char_ == o.char_ &&
-					   //creal_ == o.creal_ && // currently not suppported by to!()
-					   dchar_ == o.dchar_ &&
-					   double_ == o.double_ &&
-					   float_ == o.float_ &&
-					   //idouble_ == o.idouble_ && // currently not suppported by to!()
-					   //ifloat_ == o.ifloat_ && // currently not suppported by to!()
-					   int_ == o.int_ &&
-					   //ireal_ == o.ireal_ &&  // currently not suppported by to!()
-					   long_ == o.long_ &&
-					   real_ == o.real_ &&
-					   short_ == o.short_ &&
-					   ubyte_ == o.ubyte_ &&
-					   //ucent_ == o.ucent_ && // currently not implemented but a reserved keyword
-					   uint_ == o.uint_ &&
-					   ulong_ == o.ulong_ &&
-					   ushort_ == o.ushort_ &&
-					   wchar_ == o.wchar_;
-			}
-			
-			return false;
-		}
-	}
-	
-	class I
-	{
-		Int a;
-	}
-	
+version (none):
 	void main ()
 	{
-		auto archive = new XMLArchive!(char);
-		auto serializer = new Serializer(archive);
-		string data;
+
 		
 		void serializeObject ()
 		{
 			serializer.reset;
 			data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <struct type="B" key="0"/>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <struct type="B" key="0"/>
+	  </data>
+	</archive>`;
 				
 			serializer.serialize(B());
 			assert(archive.data == data);
@@ -1062,11 +979,11 @@
 		{
 			serializer.reset;
 			data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <struct type="B" key="0"/>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <struct type="tests.Serializer.B" key="0"/>
+	  </data>
+	</archive>`;
 				
 			serializer.serialize(B());
 			assert(archive.data == data);
@@ -1080,13 +997,13 @@
 		
 		serializer.reset;
 		data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <object runtimeType="orange.serialization.Serializer.C" type="C" key="0" id="0">
-            <string type="char" length="3" key="str" id="1">foo</string>
-        </object>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <object runtimeType="orange.serialization.Serializer.C" type="C" key="0" id="0">
+	          <string type="char" length="3" key="str" id="1">foo</string>
+	      </object>
+	  </data>
+	</archive>`;
 		
 		auto c = new C;
 		c.str = "foo";
@@ -1099,23 +1016,23 @@
 		assert(c.str == cDeserialized.str);
 			
 		// Array
-	
+
 		serializer.reset;
 		data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <object runtimeType="orange.serialization.Serializer.D" type="D" key="0" id="0">
-            <array type="int" length="6" key="arr" id="1">
-                <int key="0">27</int>
-                <int key="1">382</int>
-                <int key="2">283</int>
-                <int key="3">3820</int>
-                <int key="4">32</int>
-                <int key="5">832</int>
-            </array>
-        </object>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <object runtimeType="orange.serialization.Serializer.D" type="D" key="0" id="0">
+	          <array type="int" length="6" key="arr" id="1">
+	              <int key="0">27</int>
+	              <int key="1">382</int>
+	              <int key="2">283</int>
+	              <int key="3">3820</int>
+	              <int key="4">32</int>
+	              <int key="5">832</int>
+	          </array>
+	      </object>
+	  </data>
+	</archive>`;
 		
 		auto d = new D;
 		d.arr = [27, 382, 283, 3820, 32, 832];
@@ -1131,38 +1048,38 @@
 		
 		serializer.reset();
 		data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <object runtimeType="orange.serialization.Serializer.E" type="E" key="0" id="0">
-            <associativeArray keyType="int" valueType="int" length="4" key="aa">
-                <key key="0">
-                    <int key="0">1</int>
-                </key>
-                <value key="0">
-                    <int key="0">2</int>
-                </value>
-                <key key="1">
-                    <int key="1">3</int>
-                </key>
-                <value key="1">
-                    <int key="1">4</int>
-                </value>
-                <key key="2">
-                    <int key="2">6</int>
-                </key>
-                <value key="2">
-                    <int key="2">7</int>
-                </value>
-                <key key="3">
-                    <int key="3">39</int>
-                </key>
-                <value key="3">
-                    <int key="3">472</int>
-                </value>
-            </associativeArray>
-        </object>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <object runtimeType="orange.serialization.Serializer.E" type="E" key="0" id="0">
+	          <associativeArray keyType="int" valueType="int" length="4" key="aa">
+	              <key key="0">
+	                  <int key="0">1</int>
+	              </key>
+	              <value key="0">
+	                  <int key="0">2</int>
+	              </value>
+	              <key key="1">
+	                  <int key="1">3</int>
+	              </key>
+	              <value key="1">
+	                  <int key="1">4</int>
+	              </value>
+	              <key key="2">
+	                  <int key="2">6</int>
+	              </key>
+	              <value key="2">
+	                  <int key="2">7</int>
+	              </value>
+	              <key key="3">
+	                  <int key="3">39</int>
+	              </key>
+	              <value key="3">
+	                  <int key="3">472</int>
+	              </value>
+	          </associativeArray>
+	      </object>
+	  </data>
+	</archive>`;
 		
 		auto e = new E;
 		e.aa = [3 : 4, 1 : 2, 39 : 472, 6 : 7];
@@ -1178,16 +1095,16 @@
 		
 		serializer.reset();
 		data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <object runtimeType="orange.serialization.Serializer.F" type="F" key="0" id="0">
-            <pointer key="ptr" id="2">
-                <int key="1">9</int>
-            </pointer>
-            <int key="value">9</int>
-        </object>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <object runtimeType="orange.serialization.Serializer.F" type="F" key="0" id="0">
+	          <pointer key="ptr" id="2">
+	              <int key="1">9</int>
+	          </pointer>
+	          <int key="value">9</int>
+	      </object>
+	  </data>
+	</archive>`;
 		
 		auto f = new F;
 		f.value = 9;
@@ -1204,13 +1121,13 @@
 		
 		serializer.reset();
 		data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <object runtimeType="orange.serialization.Serializer.G" type="G" key="0" id="0">
-            <enum type="Foo" baseType="int" key="foo">1</enum>
-        </object>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <object runtimeType="orange.serialization.Serializer.G" type="G" key="0" id="0">
+	          <enum type="Foo" baseType="int" key="foo">1</enum>
+	      </object>
+	  </data>
+	</archive>`;
 		
 		auto g = new G;
 		g.foo = Foo.b;
@@ -1226,27 +1143,27 @@
 		
 		serializer.reset;
 		data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <object runtimeType="orange.serialization.Serializer.H" type="H" key="0" id="0">
-            <byte key="byte_">1</byte>
-            <char key="char_">a</char>
-            <dchar key="dchar_">b</dchar>
-            <double key="double_">0</double>
-            <float key="float_">0</float>
-            <int key="int_">1</int>
-            <long key="long_">1</long>
-            <real key="real_">0</real>
-            <short key="short_">1</short>
-            <ubyte key="ubyte_">1</ubyte>
-            <uint key="uint_">1</uint>
-            <ulong key="ulong_">1</ulong>
-            <ushort key="ushort_">1</ushort>
-            <wchar key="wchar_">c</wchar>
-            <bool key="bool_">true</bool>
-        </object>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <object runtimeType="orange.serialization.Serializer.H" type="H" key="0" id="0">
+	          <byte key="byte_">1</byte>
+	          <char key="char_">a</char>
+	          <dchar key="dchar_">b</dchar>
+	          <double key="double_">0</double>
+	          <float key="float_">0</float>
+	          <int key="int_">1</int>
+	          <long key="long_">1</long>
+	          <real key="real_">0</real>
+	          <short key="short_">1</short>
+	          <ubyte key="ubyte_">1</ubyte>
+	          <uint key="uint_">1</uint>
+	          <ulong key="ulong_">1</ulong>
+	          <ushort key="ushort_">1</ushort>
+	          <wchar key="wchar_">c</wchar>
+	          <bool key="bool_">true</bool>
+	      </object>
+	  </data>
+	</archive>`;
 		
 		auto h = new H;
 		
@@ -1284,15 +1201,15 @@
 		
 		serializer.reset();
 		data = `<?xml version="1.0" encoding="UTF-8"?>
-<archive type="org.dsource.orange.xml" version="1.0.0">
-    <data>
-        <object runtimeType="orange.serialization.Serializer.I" type="I" key="0" id="0">
-            <typedef type="Int" key="a">
-                <int key="1">1</int>
-            </typedef>
-        </object>
-    </data>
-</archive>`;
+	<archive type="org.dsource.orange.xml" version="1.0.0">
+	  <data>
+	      <object runtimeType="orange.serialization.Serializer.I" type="I" key="0" id="0">
+	          <typedef type="Int" key="a">
+	              <int key="1">1</int>
+	          </typedef>
+	      </object>
+	  </data>
+	</archive>`;
 		
 		auto i = new I;
 		i.a = 1;
@@ -1306,4 +1223,3 @@
 
 		println("unit tests successful");
 	}
-}
\ No newline at end of file
--- a/orange/test/UnitTester.d	Tue Oct 19 10:22:10 2010 +0200
+++ b/orange/test/UnitTester.d	Fri Nov 19 11:14:55 2010 +0100
@@ -6,56 +6,215 @@
  */
 module orange.test.UnitTester;
 
+version (Tango)
+{
+	import tango.io.device.File;
+	import tango.io.stream.Lines;
+	import tango.util.Convert;
+	import tango.sys.Environment;
+}
+	
+
+else
+	import std.conv;
+
 import tango.core.Exception;
+import tango.io.FilePath;
 import orange.core._;
 import orange.util._;
 
+Use!(void delegate (), string) describe (string message)
+{
+	return UnitTester.instance.describe(message);
+}
+
+Use!(void delegate (), string) it (string message)
+{
+	return UnitTester.instance.test(message);
+}
+
+void delegate () before ()
+{
+	return UnitTester.instance.before;
+}
+
+void delegate () before (void delegate () before)
+{
+	return UnitTester.instance.before = before;
+}
+
+void delegate () after ()
+{
+	return UnitTester.instance.after;
+}
+
+void delegate () after (void delegate () after)
+{
+	return UnitTester.instance.after = after;
+}
+
+void run ()
+{
+	UnitTester.instance.run;
+}
+
+private:
+
 class UnitTester
 {	
-	private
+	private:
+		
+	struct DescriptionManager
 	{
-		struct Test
+		Description[] descriptions;
+		size_t lastIndex = size_t.max;
+		
+		void opCatAssign (Description description)
+		{
+			descriptions ~= description;
+			lastIndex++;
+		}
+		
+		void opCatAssign (Test test)
 		{
-			void delegate () test;
-			string message;
-			AssertException exception;
+			last.tests ~= test;
+		}
+		
+		Description opIndex (size_t i)
+		{
+			return descriptions[i];
+		}
+		
+		Description last ()
+		{
+			return descriptions[$ - 1];
+		}
+		
+		Description first ()
+		{
+			return descriptions[0];
+		}
+		
+		int opApply (int delegate(ref Description) dg)
+		{
+			int result = 0;
 			
-			bool failed ()
+			foreach (desc ; descriptions)
 			{
-				return !succeeded;
-			}
-			
-			bool succeeded ()
-			{
-				return !exception;
+				result = dg(desc);
+				
+				if (result)
+					return result;
 			}
 			
-			void run ()
-			{
-				if (!isPending)
-					test();
-			}
-			
-			bool isPending ()
-			{
-				return test is null;
-			}
+			return result;
+		}
+		
+		size_t length ()
+		{
+			return descriptions.length;
+		}
+	}
+	
+	class Description
+	{
+		private
+		{
+			DescriptionManager descriptions;
+			Test[] tests;
+			Test[] failures;
+			Test[] pending;
+			size_t lastIndex = size_t.max;
+			string message;
+			void delegate () description;
+		}
+		
+		this (string message)
+		{
+			this.message = message;
+		}
+		
+		void run ()
+		{
+			if (shouldRun)
+				description();
+		}
+		
+		bool shouldRun ()
+		{
+			return description !is null;
+		}
+	}
+	
+	struct Test
+	{
+		void delegate () test;
+		string message;
+		AssertException exception;
+		
+		bool failed ()
+		{
+			return !succeeded;
 		}
 		
-		Test[] tests;
-		AssertException[] exceptions;
-		void delegate () pre_;
-		void delegate () post_;
-		size_t failures;
-		size_t pending;
-		size_t lastIndex = size_t.max;
-	}	
+		bool succeeded ()
+		{
+			if (exception is null)
+				return true;
+			
+			return false;
+		}
+		
+		void run ()
+		{
+			if (!isPending)
+				test();
+		}
+		
+		bool isPending ()
+		{
+			return test is null;
+		}
+	}
+	
+	static UnitTester instance_;
+	
+	DescriptionManager descriptions;
+	Description currentDescription;
+	
+	void delegate () before_;
+	void delegate () after_;
+	
+	size_t numberOfFailures;
+	size_t numberOfPending;
+	size_t numberOfTests;
+	size_t failureId;
+	
+	string defaultIndentation = "    ";
+	string indentation;
+	
+	static UnitTester instance ()
+	{
+		if (instance_)
+			return instance_;
+		
+		return instance_ = new UnitTester;
+	}
+	
+	Use!(void delegate (), string) describe (string message)
+	{
+		addDescription(message);		
+		Use!(void delegate (), string) use;
+		
+		use.args[0] = &internalDescribe;
+		use.args[1] = message;
+		
+		return use;
+	}
 	
 	Use!(void delegate (), string) test (string message)
 	{
-		tests ~= Test(null, message);
-		lastIndex++;
-		
+		addTest(message);		
 		Use!(void delegate (), string) use;
 		
 		use.args[0] = &internalTest;		
@@ -65,101 +224,298 @@
 	}
 	
 	void run ()
-	{
-		foreach (test ; tests)
-		{
-			if (test.isPending)
-				pending++;
-			
-			try
-			{
-				execute in {
-					test.run();
-				};				
-			}				
-			
-			catch (AssertException e)
-			{
-				exceptions ~= e;
-				failures++;
-			}				
-		}
-		
+	{		
+		foreach (description ; descriptions)
+			runDescription(description);
+
 		printResult;
 	}
 	
-	void delegate () pre ()
+	void runDescription (Description description)
 	{
-		return pre_;
+		restore(currentDescription) in {
+			currentDescription = description;
+			description.run;
+
+			foreach (desc ; description.descriptions)
+				runDescription(desc);
+			
+			foreach (ref test ; description.tests)
+			{
+				if (test.isPending)
+					addPendingTest(description, test);
+
+				try
+				{
+					execute in {
+						test.run();
+					};				
+				}				
+				
+				catch (AssertException e)
+					handleFailure(description, test, e);
+			}
+		};
 	}
 	
-	void delegate () pre (void delegate () pre)
+	void delegate () before ()
 	{
-		return pre_ = pre;
+		return before_;
+	}
+	
+	void delegate () before (void delegate () before)
+	{
+		return before_ = before;
 	}
 	
-	void delegate () post ()
+	void delegate () after ()
 	{
-		return post_;
+		return after_;
 	}
 
-	void delegate () post (void delegate () post)
+	void delegate () after (void delegate () after)
+	{
+		return after_ = after;
+	}
+	
+	void addTest (string message)
 	{
-		return post_ = post;
+		numberOfTests++;
+		currentDescription.tests ~= Test(null, message);
+	}
+	
+	void addDescription (string message)
+	{
+		if (currentDescription)
+			currentDescription.descriptions ~= new Description(message);
+		
+		else
+			descriptions ~= new Description(message);
 	}
 	
-	private void internalTest (void delegate () dg, string message)
+	void addPendingTest (Description description, ref Test test)
 	{
-		tests[lastIndex] = Test(dg, message);
+		numberOfPending++;
+		description.pending ~= test;
+	}
+	
+	void handleFailure (Description description, ref Test test, AssertException exception)
+	{
+		numberOfFailures++;
+		test.exception = exception;
+		description.failures ~= test;
 	}
 	
-	private void printResult ()
+	void internalDescribe (void delegate () dg, string message)
+	{
+		if (currentDescription)
+			currentDescription.descriptions.last.description = dg;
+		
+		else
+			descriptions.last.description = dg;
+	}
+	
+	void internalTest (void delegate () dg, string message)
+	{
+		currentDescription.tests[$ - 1] = Test(dg, message);
+	}
+	
+	void printResult ()
 	{	
 		if (isAllTestsSuccessful)
 			return printSuccess();
 		
-		foreach (test ; tests)
+		foreach (description ; descriptions)
 		{
-			print("- ", test.message);
-			
-			if (test.isPending)
-				print(" ", "(PENDING: Not Yet Implemented)");
-			
-			println();
+			printDescription(description);
+			printResultImpl(description.descriptions);
 		}
 		
-		print("\n", tests.length, " test, ", failures, " failures");
-		printPending();	
+		failureId = 0;
+		
+		printPending;		
+		printFailures;
+
+		print("\n", numberOfTests, " ", "test".pluralize(numberOfTests),", ", numberOfFailures, " ", "failure".pluralize(numberOfFailures));
+		printNumberOfPending;
 		println();
 	}
 	
-	private void printPending ()
+	void printResultImpl (DescriptionManager descriptions)
+	{
+		restore(indentation) in {
+			indentation ~= defaultIndentation;
+			
+			foreach (description ; descriptions)
+			{
+				printDescription(description);
+				printResultImpl(description.descriptions);
+			}
+		};
+	}
+	
+	void printDescription (Description description)
 	{
-		if (hasPending)
-			print(", ", pending, " pending");
+		println(indentation, description.message);
+		
+		restore(indentation) in {
+			indentation ~= defaultIndentation;
+
+			foreach (i, ref test ; description.tests)
+			{
+				print(indentation, "- ", test.message);
+				
+				if (test.isPending)
+					print(" (PENDING: Not Yet Implemented)");
+				
+				if (test.failed)
+					print(" (FAILED - ", ++failureId, ')');
+				
+				println();
+			}
+		};
+	}
+	
+	void printPending ()
+	{
+		if (!hasPending)
+			return;
+		
+		println("\nPending:");
+		
+		restore(indentation) in {
+			indentation ~= defaultIndentation;
+			
+			foreach (description ; descriptions)
+			{
+				printPendingDescription(description);
+				printPendingImpl(description.descriptions);
+			}
+		};
+	}
+	
+	void printPendingImpl (DescriptionManager descriptions)
+	{
+		foreach (description ; descriptions)
+		{
+			printPendingDescription(description);
+			printPendingImpl(description.descriptions);
+		}
+	}
+	
+	void printPendingDescription (Description description)
+	{
+		foreach (test ; description.pending)
+			println(indentation, description.message, " ", test.message, "\n", indentation, indentation, "# Not Yet Implemented");
 	}
 	
-	private void printSuccess ()
+	void printFailures ()
+	{
+		if (!hasFailures)
+			return;
+		
+		println("\nFailures:");
+		
+		restore(indentation) in {
+			indentation ~= defaultIndentation;
+			
+			foreach (description ; descriptions)
+			{
+				printFailuresDescription(description);
+				printFailuresImpl(description.descriptions);
+			}
+		};
+	}
+	
+	void printFailuresImpl (DescriptionManager descriptions)
 	{
-		println("All ", tests.length, " tests passed successfully.");
+		foreach (description ; descriptions)
+		{
+			printFailuresDescription(description);
+			printFailuresImpl(description.descriptions);
+		}
+	}
+	
+	void printFailuresDescription (Description description)
+	{
+		foreach (test ; description.failures)
+		{
+			auto str = indentation ~ to!(string)(++failureId) ~ ") ";
+			auto whitespace = toWhitespace(str.length);
+			
+			println(str, description.message, " ", test.message);			
+			println(whitespace, "# ", test.exception.file, ".d:", test.exception.line);
+			println(whitespace, "Stack trace:");
+			print(whitespace);
+			test.exception.writeOut(&printStackTrace);
+			println();
+			//println(readFailedTest(test, 0));
+		}
 	}
 	
-	private bool isAllTestsSuccessful ()
+	void printStackTrace (string str)
+	{
+		return print(str);
+		
+		/*if (str.find("start") < size_t.max ||
+		    str.find("main") < size_t.max ||
+		    str.find("rt.compiler.") < size_t.max ||
+		    str.find("orange.") ||
+		    str.find(":0") ||
+		    str.find("_d_assert") ||
+		    str.find("onAssertError") ||
+		    str.find("tango.core.Exception.AssertException._ctor ") ||
+		    str.find("object.") ||
+		    str.find("tango.core.tools."))
+				return;*/
+	}
+	
+	string readFailedTest (ref Test test, int numberOfSurroundingLines = 3)
+	{		
+		auto filename = test.exception.file.dup.replace('.', '/');
+		
+		filename ~= ".d";
+		filename = Environment.toAbsolute(filename);
+		auto lineNumber = test.exception.line;
+		string str;
+		auto file = new File(filename);		
+		
+		foreach (i, line ; new Lines!(char)(file))			
+			if (i >= (lineNumber - 1) - numberOfSurroundingLines && i <= (lineNumber - 1) + numberOfSurroundingLines)
+				str ~= line ~ '\n';
+		
+		file.close;
+		
+		return str;
+	}
+	
+	void printNumberOfPending ()
+	{
+		if (hasPending)
+			print(", ", numberOfPending, " pending");
+	}
+	
+	void printSuccess ()
+	{
+		println("All ", numberOfTests, " test".pluralize(numberOfTests), " passed successfully.");
+	}
+	
+	bool isAllTestsSuccessful ()
 	{
 		return !hasPending && !hasFailures;
 	}
 	
-	private bool hasPending ()
+	bool hasPending ()
 	{
-		return pending > 0;
+		return numberOfPending > 0;
 	}
 	
-	private bool hasFailures ()
+	bool hasFailures ()
 	{
-		return failures > 0;
+		return numberOfFailures > 0;
 	}
 	
-	private Use!(void delegate ()) execute ()
+	Use!(void delegate ()) execute ()
 	{
 		Use!(void delegate ()) use;
 		
@@ -168,10 +524,31 @@
 		return use;
 	}
 	
-	private void executeImpl (void delegate () dg)
+	void executeImpl (void delegate () dg)
+	{
+		auto before = this.before;
+		auto after = this.after;
+		
+		if (before) before();
+		if (dg) dg();
+		if (after) after();
+	}
+	
+	string toWhitespace (size_t value)
 	{
-		if (pre) pre();
-		if (dg) dg();
-		if (post) post();
+		string str;
+		
+		for (size_t i = 0; i < value; i++)
+			str ~= ' ';
+		
+		return str;
+	}
+	
+	string pluralize (string str, int value)
+	{
+		if (value == 1)
+			return str;
+		
+		return str ~ "s";
 	}
 }
\ No newline at end of file
--- a/orange/util/Traits.d	Tue Oct 19 10:22:10 2010 +0200
+++ b/orange/util/Traits.d	Fri Nov 19 11:14:55 2010 +0100
@@ -28,6 +28,8 @@
 	version = Phobos;
 }
 
+import orange.core.string;
+
 template isPrimitive (T)
 {
 	const bool isPrimitive = is(T == bool) ||
@@ -91,7 +93,7 @@
 
 template isString (T)
 {
-	const bool isString = is(T : char[]) || is(T : wchar[]) || is(T : dchar[]);
+	const bool isString = is(T : string) || is(T : wstring) || is(T : dstring);
 }
 
 template isAssociativeArray (T)
--- a/orange/util/collection/Array.d	Tue Oct 19 10:22:10 2010 +0200
+++ b/orange/util/collection/Array.d	Fri Nov 19 11:14:55 2010 +0100
@@ -19,7 +19,10 @@
 	version = Phobos;
 	
 	import std.c.string : memmove;
-}	
+}
+
+import orange.core.string;
+import orange.util.Traits;
 
 /**
  * Inserts the specified element at the specified position in the array. Shifts the
@@ -276,6 +279,36 @@
 }
 
 /**
+ * Returns $(D_KEYWORD true) if the array contains the given pattern.
+ * 
+ * Params:
+ *     arr = the array to check if it contains the element
+ *     pattern = the pattern whose presence in the array is to be tested
+ *     
+ * Returns: $(D_KEYWORD true) if the array contains the given pattern
+ */
+bool contains (T) (T[] arr, T[] pattern)
+{
+	static if (isChar!(T))
+	{
+		version (Tango)
+			return tango.text.Util.containsPattern(arr, pattern);
+		
+		else
+			return stdString.indexOf(arr, element) != -1;
+	}
+	
+	else
+	{
+		version (Tango)
+			return tango.core.Array.contains(arr, pattern);
+		
+		else
+			return !algorithm.find(arr, pattern).empty;
+	}
+}
+
+/**
  * Returns $(D_KEYWORD true) if this array contains no elements.
  * 
  * Params:
@@ -433,7 +466,7 @@
  * 
  * Returns: the array
  */
-T[] replace (T, U = size_t) (ref T[] arr, U pos, U n, T[] elements)
+/*T[] replace (T, U = size_t) (ref T[] arr, U pos, U n, T[] elements)
 in
 {
 	assert(pos <= arr.length, "mambo.collection.Array.replace: The position was greter than the length of the array");
@@ -491,9 +524,54 @@
 	}
 	
 	return arr;
+}*/
+
+/**
+ * Replaces all the occurences of $(D_PARAM pattern) with $(D_PARAM replacement)
+ * 
+ * Params:
+ *     arr = the array to do the raplce in
+ *     pattern = the pattern to match
+ *     replacement = the values to subsitute
+ *     
+ * Returns: the passed in array with all the patterns subsituted
+ */
+T[] replace (T : wchar) (T[] arr, dchar pattern, dchar replacement)
+{
+	foreach (i, dchar e ; arr)
+		if (e == pattern)
+			arr[i] = replacement;
+	
+	return arr;
 }
 
 /**
+ * Replaces all the occurences of $(D_PARAM pattern) with $(D_PARAM replacement)
+ * 
+ * Params:
+ *     arr = the array to do the raplce in
+ *     pattern = the pattern to match
+ *     replacement = the values to subsitute
+ *     
+ * Returns: the passed in array with all the patterns subsituted
+ */
+/*T[] replace (T) (T[] arr, T pattern, T replacement)
+{
+	version (Tango)
+		tango.core.Array.replace(arr, pattern, replacement);
+	
+	
+	else
+	{
+		foreach (ref e ; arr)
+			if (e == pattern)
+				e = replacement;
+	}
+	
+	return arr;
+}*/
+
+/**
  * Erases a part of the array content, shortening the length of the array.
  * 
  * Params:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/Serializer.d	Fri Nov 19 11:14:55 2010 +0100
@@ -0,0 +1,508 @@
+
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Nov 5, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module tests.Serializer;
+
+private:
+
+import orange.serialization.Serializer;
+import orange.serialization.archives.XMLArchive;
+import orange.core.io;
+import orange.core.string;
+
+bool containsDefaultXmlContent (string source)
+{
+	return source.containsXmlHeader() &&
+		   source.containsArchive() &&
+		   source.containsXmlTag("data");
+}
+
+bool containsXmlHeader (string source)
+{
+	return source.contains(`<?xml version="1.0" encoding="UTF-8"?>`);
+}
+
+bool containsArchive (string source)
+{
+	return source.containsArchiveHeader() && source.contains("</archive>");
+}
+
+bool containsArchiveHeader (string source)
+{
+	return source.contains(`<archive type="org.dsource.orange.xml" version="1.0.0">`);
+}
+
+bool containsXmlTag (string source, string tag, bool simple = false)
+{
+	return source.containsXmlTag(tag, null, null, simple);
+}
+
+bool containsXmlTag (string source, string tag, string attributes, bool simple = false)
+{
+	return source.containsXmlTag(tag, attributes, null, simple);
+}
+
+bool containsXmlTag (string source, string tag, string attributes, string content, bool simple = false)
+{
+	string pattern = '<' ~ tag;
+		
+	if (attributes.length > 0)
+		pattern ~= ' ' ~ attributes;
+	
+	if (simple)
+		return source.contains(pattern ~ "/>");
+	
+	if (content.length > 0)
+		return source.contains(pattern ~ '>' ~ content ~ "</" ~ tag ~ '>');
+	
+	return source.contains(pattern ~ '>') && source.contains("</" ~ tag ~ '>');
+}
+
+enum Foo { a, b, c }
+typedef int Int;
+
+class A
+{
+	equals_t opEquals (Object other)
+	{
+		if (auto o = cast(A) other)
+			return true;
+		
+		return false;
+	}
+}
+
+struct B
+{
+	equals_t opEquals (B b)
+	{
+		return true;
+	}
+}
+
+class C { string str; }
+class D { int[] arr; }
+class E { int[int] aa; }
+class F { int value; int* ptr; }
+class G { Foo foo; }
+
+class H
+{
+	bool bool_;
+	byte byte_;
+	//cdouble cdouble_; // currently not suppported by to!()
+	//cent cent_; // currently not implemented but a reserved keyword
+	//cfloat cfloat_; // currently not suppported by to!()
+	char char_;
+	//creal creal_; // currently not suppported by to!()
+	dchar dchar_;
+	double double_;
+	float float_;
+	//idouble idouble_; // currently not suppported by to!()
+	//ifloat ifloat_; // currently not suppported by to!()
+	int int_;
+	//ireal ireal_;  // currently not suppported by to!()
+	long long_;
+	real real_;
+	short short_;
+	ubyte ubyte_;
+	//ucent ucent_; // currently not implemented but a reserved keyword
+	uint uint_;
+	ulong ulong_;
+	ushort ushort_;
+	wchar wchar_;
+	
+	equals_t opEquals (Object other)
+	{
+		if (auto o =  cast(H) other)
+		{
+			return bool_ == o.bool_ &&
+				   byte_ == o.byte_ &&
+				   //cdouble_ == o.cdouble_ && // currently not suppported by to!()
+				   //cent_ == o.cent_ && // currently not implemented but a reserved keyword
+				   //cfloat_ == o.cfloat_ && // currently not suppported by to!()
+				   char_ == o.char_ &&
+				   //creal_ == o.creal_ && // currently not suppported by to!()
+				   dchar_ == o.dchar_ &&
+				   double_ == o.double_ &&
+				   float_ == o.float_ &&
+				   //idouble_ == o.idouble_ && // currently not suppported by to!()
+				   //ifloat_ == o.ifloat_ && // currently not suppported by to!()
+				   int_ == o.int_ &&
+				   //ireal_ == o.ireal_ &&  // currently not suppported by to!()
+				   long_ == o.long_ &&
+				   real_ == o.real_ &&
+				   short_ == o.short_ &&
+				   ubyte_ == o.ubyte_ &&
+				   //ucent_ == o.ucent_ && // currently not implemented but a reserved keyword
+				   uint_ == o.uint_ &&
+				   ulong_ == o.ulong_ &&
+				   ushort_ == o.ushort_ &&
+				   wchar_ == o.wchar_;
+		}
+		
+		return false;
+	}
+}
+
+class I
+{
+	Int a;
+}
+
+class J
+{
+	string firstSource;
+	string firstSlice;
+	
+	string secondSlice;
+	string secondSource;
+}
+
+class K
+{
+	int[int] a;
+	int[int] b;
+}
+
+import orange.test.UnitTester;
+Serializer serializer;
+XMLArchive!(char) archive;
+
+A a;
+B b;
+C c;
+D d;
+E e;
+F f;
+G g;
+H h;
+I i;
+J j;
+J jDeserialized;
+K k;
+
+string data;
+
+unittest
+{
+	archive = new XMLArchive!(char);
+	serializer = new Serializer(archive);
+	
+	a = new A;
+	
+	c = new C;
+	c.str = "foo";
+	
+	d = new D;
+	d.arr = [27, 382, 283, 3820, 32, 832].dup;
+	
+	e = new E;
+	e.aa = [3 : 4, 1 : 2, 39 : 472, 6 : 7];
+	
+	f = new F;
+	f.value = 9;
+	f.ptr = &f.value;
+	
+	g = new G;
+	g.foo = Foo.b;
+	
+	h = new H;	
+	h.bool_ = true;
+	h.byte_ = 1;
+	h.char_ = 'a';
+	//h.cdouble_ = 0.0 + 0.0 * 1.0i; // currently not supported by to!() 
+	//h.cfloat_ = 0.0f + 0.0f * 1.0i; // currently not supported by to!() 
+	//h.creal_ = 0.0 + 0.0 * 1.0i; // currently not supported by to!() 
+	h.dchar_ = 'b';
+	h.double_ = 0.0;
+	h.float_ = 0.0f;
+	//h.idouble_ = 0.0 * 1.0i; // currently not supported by to!() 
+	//h.ifloat_ = 0.0f * 1.0i; // currently not supported by to!()
+	h.int_ = 1;
+	//h.ireal_ = 0.0 * 1.0i; // currently not supported by to!()
+	h.long_ = 1L;
+	h.real_ = 0.0;
+	h.short_ = 1;
+	h.ubyte_ = 1U;
+	h.uint_ = 1U;
+	h.ulong_ = 1LU;
+	h.ushort_ = 1U;
+	h.wchar_ = 'c';
+	
+	i = new I;
+	i.a = 1;
+	
+	j = new J;
+	j.firstSource = "0123456789";
+	j.firstSlice = j.firstSource[3 .. 7];
+	j.secondSource = "abcdefg";
+	j.secondSlice = j.secondSource[1 .. 4];
+	
+	k = new K;
+	k.a = [3 : 4, 1 : 2, 39 : 472, 6 : 7];
+	k.b = k.a;
+
+	describe("Serializer") in {
+		describe("serialize object") in {
+			it("should return a serialized object") in {
+				serializer.reset;
+				serializer.serialize(a);
+				
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().contains(`<object runtimeType="tests.Serializer.A" type="A" key="0" id="0"/>`));
+			};
+		};
+		
+		describe("deserialize object") in {
+			it("should return a deserialized object equal to the original object") in {
+				auto aDeserialized = serializer.deserialize!(A)(archive.data);
+				assert(a == aDeserialized);
+			};
+		};
+		
+		describe("serialize struct") in {
+			it("should return a serialized struct") in {
+				serializer.reset;
+				serializer.serialize(B());
+				
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().contains(`<struct type="B" key="0"/>`));
+			};
+		};
+		
+		describe("deserialize struct") in {
+			it("should return a deserialized struct equal to the original struct") in {
+				auto bDeserialized = serializer.deserialize!(B)(archive.data);
+				assert(b == bDeserialized);
+			};
+		};
+		
+		describe("serialize string") in {
+			it("should return a serialized string") in {
+				serializer.reset;
+
+				serializer.serialize(c);
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.C" type="C" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("string", `type="char" length="3" key="str" id="1"`, "foo"));
+			};
+		};
+		
+		describe("deserialize string") in {
+			it("should return a deserialized string equal to the original string") in {
+				auto cDeserialized = serializer.deserialize!(C)(archive.data);
+				assert(c.str == cDeserialized.str);
+			};
+		};
+		
+		describe("serialize array") in {
+			it("should return a serialized array") in {
+				serializer.reset;
+				serializer.serialize(d);
+				
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.D" type="D" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("int", `key="0"`, "27"));
+				assert(archive.data().containsXmlTag("int", `key="1"`, "382"));
+				assert(archive.data().containsXmlTag("int", `key="2"`, "283"));
+				assert(archive.data().containsXmlTag("int", `key="3"`, "3820"));
+				assert(archive.data().containsXmlTag("int", `key="4"`, "32"));
+				assert(archive.data().containsXmlTag("int", `key="5"`, "832"));
+			};
+		};
+		
+		describe("deserialize array") in {
+			it("should return a deserialize array equal to the original array") in {
+				auto dDeserialized = serializer.deserialize!(D)(archive.data);
+				assert(d.arr == dDeserialized.arr);
+			};
+		};
+		
+		describe("serialize associative array") in {
+			it("should return a serialized associative array") in {
+				serializer.reset();
+				serializer.serialize(e);
+				
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.E" type="E" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("associativeArray", `keyType="int" valueType="int" length="4" key="aa"`));
+				
+				assert(archive.data().containsXmlTag("key", `key="0"`));
+				assert(archive.data().containsXmlTag("int", `key="0"`, "1"));
+				assert(archive.data().containsXmlTag("value", `key="0"`));
+				assert(archive.data().containsXmlTag("int", `key="0"`, "2"));
+				
+				assert(archive.data().containsXmlTag("key", `key="1"`));
+				assert(archive.data().containsXmlTag("int", `key="1"`, "3"));
+				assert(archive.data().containsXmlTag("value", `key="1"`));
+				assert(archive.data().containsXmlTag("int", `key="1"`, "4"));
+				
+				assert(archive.data().containsXmlTag("key", `key="2"`));
+				assert(archive.data().containsXmlTag("int", `key="2"`, "6"));
+				assert(archive.data().containsXmlTag("value", `key="2"`));
+				assert(archive.data().containsXmlTag("int", `key="2"`, "7"));
+				
+				assert(archive.data().containsXmlTag("key", `key="3"`));
+				assert(archive.data().containsXmlTag("int", `key="3"`, "39"));
+				assert(archive.data().containsXmlTag("value", `key="3"`));
+				assert(archive.data().containsXmlTag("int", `key="3"`, "472"));
+			};
+		};
+		
+		describe("deserialize associative array") in {
+			it("should return an associative array equal to the original associative array") in {
+				auto eDeserialized = serializer.deserialize!(E)(archive.data);
+				
+				foreach (k, v ; eDeserialized.aa)
+					assert(e.aa[k] == v);
+				
+				//assert(e.aa == eDeserialized.aa); // cannot compare associative array
+			};
+		};
+		
+		describe("serialize pointer") in {
+			it("should return a serialized pointer") in {
+				serializer.reset();
+				
+				serializer.serialize(f);
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.F" type="F" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("pointer", `key="ptr" id="2"`));
+				assert(archive.data().containsXmlTag("int", `key="1"`, "9"));
+				assert(archive.data().containsXmlTag("int", `key="value"`, "9"));
+			};
+		};
+		
+		describe("deserialize pointer") in {
+			it("should return a deserialized pointer equal to the original pointer") in {
+				auto fDeserialized = serializer.deserialize!(F)(archive.data);
+				assert(*f.ptr == *fDeserialized.ptr);
+			};
+		};
+		
+		describe("serialize enum") in {
+			it("should return a serialized enum") in {
+				serializer.reset();
+				serializer.serialize(g);
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.G" type="G" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("enum", `type="Foo" baseType="int" key="foo"`, "1"));
+			};
+		};
+
+		
+		describe("deserialize enum") in {
+			it("should return an enum equal to the original enum") in {
+				auto gDeserialized = serializer.deserialize!(G)(archive.data);
+				assert(g.foo == gDeserialized.foo);
+			};
+		};
+		
+		describe("serialize primitives") in {
+			it("should return serialized primitives") in {
+				serializer.reset;
+				
+				serializer.serialize(h);
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.H" type="H" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("byte", `key="byte_"`, "1"));
+				assert(archive.data().containsXmlTag("char", `key="char_"`, "a"));
+				assert(archive.data().containsXmlTag("dchar", `key="dchar_"`, "b"));
+				assert(archive.data().containsXmlTag("double", `key="double_"`, "0"));
+				assert(archive.data().containsXmlTag("float", `key="float_"`, "0"));
+				assert(archive.data().containsXmlTag("int", `key="int_"`, "1"));
+				assert(archive.data().containsXmlTag("long", `key="long_"`, "1"));
+				assert(archive.data().containsXmlTag("real", `key="real_"`, "0"));
+				assert(archive.data().containsXmlTag("short", `key="short_"`, "1"));
+				assert(archive.data().containsXmlTag("ubyte", `key="ubyte_"`, "1"));
+				assert(archive.data().containsXmlTag("uint", `key="uint_"`, "1"));
+				assert(archive.data().containsXmlTag("ulong", `key="ulong_"`, "1"));
+				assert(archive.data().containsXmlTag("ushort", `key="ushort_"`, "1"));
+				assert(archive.data().containsXmlTag("wchar", `key="wchar_"`, "c"));
+				assert(archive.data().containsXmlTag("bool", `key="bool_"`, "true"));
+			};
+		};
+		
+		describe("deserialize primitives") in {
+			it("should return deserialized primitives equal to the original primitives") in {
+				auto hDeserialized = serializer.deserialize!(H)(archive.data);
+				assert(h == hDeserialized);
+			};
+		};
+		
+		describe("serialize typedef") in {
+			it("should return a serialized typedef") in {
+				serializer.reset();
+				serializer.serialize(i);
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.I" type="I" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("typedef", `type="Int" key="a"`));
+				assert(archive.data().containsXmlTag("int", `key="1"`, "1"));
+			};
+		};
+		
+		describe("deserialize typedef") in {
+			it("should return a deserialized typedef equal to the original typedef") in {
+				auto iDeserialized = serializer.deserialize!(I)(archive.data);
+				assert(i.a == iDeserialized.a);
+			};
+		};
+		
+		describe("serialize slices") in {
+			it("should return serialized slices") in {
+				serializer.reset();
+				serializer.serialize(j);
+
+				assert(archive.data().containsDefaultXmlContent());
+				assert(archive.data().containsXmlTag("object", `runtimeType="tests.Serializer.J" type="J" key="0" id="0"`));
+				assert(archive.data().containsXmlTag("string", `type="char" length="10" key="firstSource" id="1"`, "0123456789"));
+				assert(archive.data().containsXmlTag("slice", `key="firstSlice" offset="3" length="4"`, "1"));
+				assert(archive.data().containsXmlTag("slice", `key="secondSlice" offset="1" length="3"`, "4"));
+				assert(archive.data().containsXmlTag("string", `type="char" length="7" key="secondSource" id="4"`, "abcdefg"));
+			};
+		};
+		
+		describe("deserialize slices") in {
+			jDeserialized = serializer.deserialize!(J)(archive.data);
+			
+			it("should return deserialized strings equal to the original strings") in {
+				assert(j.firstSource == jDeserialized.firstSource);
+				assert(j.secondSource == jDeserialized.secondSource);
+			};
+			
+			it("should return deserialized slices equal to the original slices") in {
+				assert(j.firstSlice == jDeserialized.firstSlice);
+				assert(j.secondSlice == jDeserialized.secondSlice);
+			};
+			
+			it("the slices should be equal to a slice of the original sources") in {
+				assert(jDeserialized.firstSource[3 .. 7] == jDeserialized.firstSlice);
+				assert(jDeserialized.secondSource[1 .. 4] == jDeserialized.secondSlice);
+				
+				assert(j.firstSource[3 .. 7] == jDeserialized.firstSlice);
+				assert(j.secondSource[1 .. 4] == jDeserialized.secondSlice);
+			};
+			
+			it("the slices should be able to modify the sources") in {
+				jDeserialized.firstSlice[0] = 'a';
+				jDeserialized.secondSlice[0] = '0';
+
+				assert(jDeserialized.firstSource == "012a456789");
+				assert(jDeserialized.secondSource == "a0cdefg");
+			};
+		};
+		
+		describe("associative array references") in {
+			it("should return ") in {
+				serializer.reset();
+				serializer.serialize(k);
+				println(archive.data);
+			};
+		};
+	};
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/all.d	Fri Nov 19 11:14:55 2010 +0100
@@ -0,0 +1,15 @@
+/**
+ * Copyright: Copyright (c) 2010 Jacob Carlborg. All rights reserved.
+ * Authors: Jacob Carlborg
+ * Version: Initial created: Nov 5, 2010
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
+ */
+module tests.all;
+
+import orange.test.UnitTester;
+import tests.Serializer;
+
+void main ()
+{
+	run;
+}
\ No newline at end of file