Artifact Content
Not logged in

Artifact 3ff977492e8e9816400570f84c67074ded34c853


     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.writeString("[TEST] press enter to exit.");
    46  				din.readLine();
    47  				return false;
    48  			}
    49  
    50  			foreach(m; ModuleInfo)
    51  				if(m && m.unitTest)
    52  					testModule(m, m.unitTest);
    53  			return report();
    54  		};
    55  	}
    56  }
    57  
    58  /// Unittest helper that asserts an expression must throw something
    59  
    60  void assert_throw(ExcT=Throwable, T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="")
    61  {
    62  	static if( is(ExcT == Throwable) )
    63  		try
    64  			{ t(); }
    65  		catch(ExcT)
    66  			{ return; }
    67  	else
    68  		try
    69  			{ t(); }
    70  		catch(ExcT)
    71  			{ return; }
    72  		catch(Throwable e)
    73  			{ onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n  >> "~e.toString()); }
    74  	onAssertErrorMsg(fn, ln, msg.length ? msg : "not thrown");
    75  }
    76  
    77  /// Unittest helper that asserts an expression must not throw anything
    78  
    79  T assert_nothrow(T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string msg="")
    80  {
    81  	try
    82  		{ return t(); }
    83  	catch(Throwable e)
    84  		{ onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n  >> "~e.toString()); }
    85  	assert(false);
    86  }
    87  
    88  unittest
    89  {
    90  	auto error = {throw new Error("hello");};
    91  	auto nothing = (){};
    92  	auto assertError = {assert(0);};
    93  
    94  	assert_nothrow          ( assert_nothrow(nothing()) );
    95  	assert_throw!AssertError( assert_nothrow(error()) );
    96  	assert_throw!AssertError( assert_nothrow(assertError()) );
    97  
    98  	assert_nothrow          ( assert_throw!Error(error()) );
    99  	assert_throw!AssertError( assert_throw!Error(nothing()) );
   100  	assert_nothrow          ( assert_throw!Error(assertError()) );
   101  	assert_throw!AssertError( assert_throw!AssertError(error()) );
   102  }
   103  
   104  template assertOp(string op)
   105  {
   106  	void assertOp(A, B, string fn=__FILE__, size_t ln=__LINE__)(lazy A a_, lazy B b_, string msg="")
   107  	{
   108  		try
   109  			{ A a=a_(); B b=b_(); if( mixin("a"~op~"b") ) return;
   110  			  onAssertErrorMsg(fn, ln, msg.length ? msg : text(a, " !", op, " ", b)); }
   111  		catch(Throwable e)
   112  			{ onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception \n  >> "~e.toString()); }
   113  		assert(false);
   114  	}
   115  }
   116  
   117  alias assertOp!(`==`) assert_eq; /// asserts two operands are ==
   118  alias assertOp!(`!=`) assert_ne; /// asserts two operands are !=
   119  alias assertOp!(`<`)  assert_lt; /// asserts two operands are <
   120  alias assertOp!(`<=`) assert_le; /// asserts two operands are <=
   121  alias assertOp!(`>`)  assert_gt; /// asserts two operands are >
   122  alias assertOp!(`>=`) assert_ge; /// asserts two operands are >=
   123  
   124  unittest
   125  {
   126  	assert_nothrow( assert_eq(1, 1) );
   127  	assert_nothrow( assert_ne(1, 0) );
   128  	assert_nothrow( assert_lt(0, 1) );
   129  	assert_nothrow( assert_le(0, 1) );
   130  	assert_nothrow( assert_le(0, 0) );
   131  	assert_nothrow( assert_gt(1, 0) );
   132  	assert_nothrow( assert_ge(1, 0) );
   133  	assert_nothrow( assert_ge(0, 0) );
   134  
   135  	assert_throw!AssertError( assert_eq(1, 0) );
   136  	assert_throw!AssertError( assert_ne(1, 1) );
   137  	assert_throw!AssertError( assert_lt(1, 1) );
   138  	assert_throw!AssertError( assert_lt(1, 0) );
   139  	assert_throw!AssertError( assert_le(1, 0) );
   140  	assert_throw!AssertError( assert_gt(0, 0) );
   141  	assert_throw!AssertError( assert_gt(0, 1) );
   142  	assert_throw!AssertError( assert_ge(0, 1) );
   143  
   144  	class Temp { bool opEquals(int x){return x/x==x;} }
   145  	assert_throw!AssertError( assert_eq(new Temp, 0) );
   146  	assert_nothrow          ( assert_eq(new Temp, 1) );
   147  	assert_throw!AssertError( assert_eq(new Temp, 2) );
   148  }