Artifact Content
Not logged in

Artifact 3ba75b9c3bef69b27186722d7d7d466f20801a2a


     1  /**
     2   * Authors: k.inaba
     3   * License: NYSL 0.9982 http://www.kmonos.net/nysl/
     4   *
     5   * Hepler routines for unittesting.
     6   * TODO: Is there any clean way to implement "assert_compiles" and "assert_not_compile"?
     7   */
     8  module tricks.test;
     9  import std.conv : text;
    10  import core.exception;
    11  
    12  version(unittest)
    13  {
    14  	import std.cstream;
    15  	import core.runtime;
    16  
    17  	static this()
    18  	{
    19  		installCustomTestRunner();
    20  	}
    21  
    22  	private void installCustomTestRunner()
    23  	{
    24  		Runtime.moduleUnitTester = function()
    25  		{
    26  			Throwable firstError = null;
    27  
    28  			void logError(Throwable e)
    29  			{
    30  				if(firstError is null)
    31  					firstError = e;
    32  				derr.writefln("  !! %s(%d): %s", e.file, e.line, e.msg);
    33  			}
    34  
    35  			void testModule(ModuleInfo* m, void function() test)
    36  			{
    37  				derr.writefln("[TEST] %s", m.name);
    38  				try { test(); } catch( Throwable e ) { logError(e); }
    39  			}
    40  
    41  			bool report()
    42  			{
    43  				if(firstError is null)
    44  					return true;
    45  				derr.writefln("[TEST] The first error was:\n%s", firstError);
    46  				derr.writeString("[TEST] press enter to exit.");
    47  				din.readLine();
    48  				return false;
    49  			}
    50  
    51  			foreach(m; ModuleInfo)
    52  				if(m && m.unitTest)
    53  					testModule(m, m.unitTest);
    54  			return report();
    55  		};
    56  	}
    57  }
    58  
    59  /// Unittest helper that asserts an expression must throw something
    60  
    61  void assert_throw(ExcT=Throwable, T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="")
    62  {
    63  	static if( is(ExcT == Throwable) )
    64  		try
    65  			{ t(); }
    66  		catch(ExcT)
    67  			{ return; }
    68  	else
    69  		try
    70  			{ t(); }
    71  		catch(ExcT)
    72  			{ return; }
    73  		catch(Throwable e)
    74  			{ onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n  >> "~e.toString()); }
    75  	onAssertErrorMsg(fn, ln, msg.length ? msg : "not thrown");
    76  }
    77  
    78  /// Unittest helper that asserts an expression must not throw anything
    79  
    80  T assert_nothrow(T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="")
    81  {
    82  	try
    83  		{ return t(); }
    84  	catch(Throwable e)
    85  		{ onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n  >> "~e.toString()); }
    86  	assert(false);
    87  }
    88  
    89  unittest
    90  {
    91  	auto error = {throw new Error("hello");};
    92  	auto nothing = (){};
    93  	auto assertError = {assert(0);};
    94  
    95  	assert_nothrow          ( assert_nothrow(nothing()) );
    96  	assert_throw!AssertError( assert_nothrow(error()) );
    97  	assert_throw!AssertError( assert_nothrow(assertError()) );
    98  
    99  	assert_nothrow          ( assert_throw!Error(error()) );
   100  	assert_throw!AssertError( assert_throw!Error(nothing()) );
   101  	assert_nothrow          ( assert_throw!Error(assertError()) );
   102  	assert_throw!AssertError( assert_throw!AssertError(error()) );
   103  }
   104  
   105  template assertOp(string op)
   106  {
   107  	void assertOp(A, B, string fn=__FILE__, size_t ln=__LINE__)(lazy A a_, lazy B b_, string msg="")
   108  	{
   109  		try
   110  			{ A a=a_(); B b=b_(); if( mixin("a"~op~"b") ) return;
   111  			  onAssertErrorMsg(fn, ln, msg.length ? msg : text(a, " !", op, " ", b)); }
   112  		catch(Throwable e)
   113  			{ onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n  >> "~e.toString()); }
   114  		assert(false);
   115  	}
   116  }
   117  
   118  alias assertOp!(`==`) assert_eq; /// asserts two operands are ==
   119  alias assertOp!(`!=`) assert_ne; /// asserts two operands are !=
   120  alias assertOp!(`<`)  assert_lt; /// asserts two operands are <
   121  alias assertOp!(`<=`) assert_le; /// asserts two operands are <=
   122  alias assertOp!(`>`)  assert_gt; /// asserts two operands are >
   123  alias assertOp!(`>=`) assert_ge; /// asserts two operands are >=
   124  
   125  unittest
   126  {
   127  	assert_nothrow( assert_eq(1, 1) );
   128  	assert_nothrow( assert_ne(1, 0) );
   129  	assert_nothrow( assert_lt(0, 1) );
   130  	assert_nothrow( assert_le(0, 1) );
   131  	assert_nothrow( assert_le(0, 0) );
   132  	assert_nothrow( assert_gt(1, 0) );
   133  	assert_nothrow( assert_ge(1, 0) );
   134  	assert_nothrow( assert_ge(0, 0) );
   135  
   136  	assert_throw!AssertError( assert_eq(1, 0) );
   137  	assert_throw!AssertError( assert_ne(1, 1) );
   138  	assert_throw!AssertError( assert_lt(1, 1) );
   139  	assert_throw!AssertError( assert_lt(1, 0) );
   140  	assert_throw!AssertError( assert_le(1, 0) );
   141  	assert_throw!AssertError( assert_gt(0, 0) );
   142  	assert_throw!AssertError( assert_gt(0, 1) );
   143  	assert_throw!AssertError( assert_ge(0, 1) );
   144  
   145  	class Temp { bool opEquals(int x){return x/x==x;} }
   146  	assert_throw!AssertError( assert_eq(new Temp, 0) );
   147  	assert_nothrow          ( assert_eq(new Temp, 1) );
   148  	assert_throw!AssertError( assert_eq(new Temp, 2) );
   149  }