1 /** 2 * Authors: Pedro Tacla Yamada 3 * Date: August 21, 2014 4 * License: Licensed under the GPLv3 license. See LICENSE for more information. 5 */ 6 module pyjamas; 7 8 import std.algorithm : canFind, isSorted; 9 import std.conv : to; 10 import std.range : isInputRange, isForwardRange, hasLength, ElementEncodingType, 11 isAssociativeArray, empty; 12 import std.regex : Regex, StaticRegex;// & std.regex.match 13 import std.string : format; 14 import std.traits : hasMember, isSomeString, isCallable, 15 isImplicitlyConvertible, Unqual, std; 16 17 Assertion!T should(T)(T context) 18 { 19 return new Assertion!T(context); 20 } 21 22 class Assertion(T) 23 { 24 static bool callable = isCallable!T; 25 bool negated = false; 26 string operator = "be"; 27 T context; 28 29 this() {}; 30 this(T _context) 31 { 32 context = _context; 33 } 34 35 alias id be; 36 alias id as; 37 alias id of; 38 alias id a; 39 alias id and; 40 alias id have; 41 alias id which; 42 43 Assertion id() 44 { 45 return this; 46 } 47 48 Assertion not() 49 { 50 negated = !negated; 51 return this; 52 } 53 54 U ok(U)(U expr, 55 lazy string message, 56 string file = __FILE__, 57 size_t line = __LINE__) 58 { 59 if(negated ? !expr : expr) return expr; 60 throw new Exception(message, file, line); 61 } 62 63 T equal(U)(U other, 64 string file = __FILE__, 65 size_t line = __LINE__) 66 { 67 auto t_other = other.to!T; 68 ok(context == other, message(other), file, line); 69 return context; 70 } 71 72 T exist(string file = __FILE__, size_t line = __LINE__) 73 { 74 static if(isImplicitlyConvertible!(T, typeof(null))) 75 { 76 operator = "exist"; 77 if(context == null) 78 { 79 ok(false, message, file, line); 80 } 81 } 82 return context; 83 } 84 85 string message(U)(U other) 86 { 87 return format("expected %s to %s%s%s", context.to!string, 88 (negated ? "not " : ""), 89 operator, 90 (" " ~ other.to!string)); 91 } 92 93 string message() 94 { 95 return format("expected %s to %s%s", context.to!string, 96 (negated ? "not " : ""), 97 operator); 98 } 99 100 bool biggerThan(U)(U other, string file = __FILE__, size_t line = __LINE__) 101 { 102 operator = "be bigger than"; 103 return ok(context > other, message(other), file, line); 104 } 105 106 bool smallerThan(U)(U other, string file = __FILE__, size_t line = __LINE__) 107 { 108 operator = "be smaller than"; 109 return ok(context < other, message(other), file, line); 110 } 111 112 static if(isForwardRange!T) 113 { 114 bool sorted(string file = __FILE__, size_t line = __LINE__) 115 { 116 operator = "be sorted"; 117 return ok(context.isSorted, message, file, line); 118 } 119 } 120 121 static if(isAssociativeArray!T) { 122 void key(U)(U other, string file = __FILE__, size_t line = __LINE__) 123 { 124 operator = "have key"; 125 ok(!(other !in context), message(other), file, line); 126 } 127 } 128 129 static if(isInputRange!T || isAssociativeArray!T) 130 { 131 U value(U)(U other, string file = __FILE__, size_t line = __LINE__) 132 { 133 static if(isAssociativeArray!T) auto pool = context.values; 134 else auto pool = context; 135 136 operator = "contain value"; 137 ok(canFind(pool, other), message(other), file, line); 138 return other; 139 } 140 141 alias value include; 142 alias value contain; 143 } 144 145 static if(hasLength!T || hasMember!(T, "string") || isSomeString!T) 146 { 147 U length(U)(U len, string file = __FILE__, size_t line = __LINE__) 148 { 149 operator = "have length of"; 150 ok(context.length == len, message(len), file, line); 151 return len; 152 } 153 } 154 155 static if(isSomeString!T) 156 { 157 private alias BasicElementOfT = Unqual!(ElementEncodingType!T); 158 private alias RegexOfT = Regex!(BasicElementOfT); 159 private alias StaticRegexOfT = StaticRegex!(BasicElementOfT); 160 161 auto match(RegEx)(RegEx re, string file = __FILE__, size_t line = __LINE__) 162 if(is(RegEx == RegexOfT) || 163 is(RegEx == StaticRegexOfT) || 164 isSomeString!RegEx) 165 { 166 auto m = std.regex.match(context, re); 167 operator = "match"; 168 ok(!m.empty, message(re), file, line); 169 return m; 170 } 171 } 172 173 static if(is(T == bool)) 174 { 175 bool True(string file = __FILE__, size_t line = __LINE__) 176 { 177 return ok(context == true, message(true), file, line); 178 } 179 180 bool False(string file = __FILE__, size_t line = __LINE__) 181 { 182 return !ok(context == false, message(false), file, line); 183 } 184 } 185 186 static if(isCallable!T) 187 { 188 void Throw(T : Throwable = Exception)(string file = __FILE__, 189 size_t line = __LINE__) 190 { 191 operator = "throw"; 192 bool thrown = false; 193 try context(); 194 catch(T) thrown = true; 195 ok(thrown, message(), file, line); 196 } 197 } 198 199 }