1 module dshould.contain; 2 3 import dshould.ShouldType; 4 import dshould.basic : not, should; 5 6 /** 7 * The word `.contain` takes one value, expected to appear in the range on the left hand side. 8 */ 9 public void contain(Should, T)(Should should, T expected, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__) 10 if (isInstanceOf!(ShouldType, Should)) 11 { 12 should.allowOnlyWords!("not", "only").before!"contain"; 13 14 should.addWord!"contain".checkContain(expected, file, line); 15 } 16 17 /// 18 unittest 19 { 20 [2, 3, 4].should.contain(3); 21 [2, 3, 4].should.not.contain(5); 22 } 23 24 public auto contain(Should)(Should should) 25 if (isInstanceOf!(ShouldType, Should)) 26 { 27 should.allowOnlyWords!("not").before!"contain"; 28 29 return should.addWord!"contain"; 30 } 31 32 /** 33 * The phrase `.contain.only` or `.only.contain` takes a range, the elements of which are expected to be the only 34 * elements appearing in the range on the left hand side. 35 */ 36 public void only(Should, T)(Should should, T expected, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__) 37 if (isInstanceOf!(ShouldType, Should)) 38 { 39 should.requireWord!"contain".before!"only"; 40 should.allowOnlyWords!("not", "contain").before!"only"; 41 42 should.addWord!"only".checkContain(expected, file, line); 43 } 44 45 /// 46 unittest 47 { 48 [3, 4].should.only.contain([4, 3]); 49 [3, 4].should.only.contain([1, 2, 3, 4]); 50 [3, 4].should.contain.only([4, 3]); 51 [2, 3, 4].should.not.only.contain([4, 3]); 52 } 53 54 public auto only(Should)(Should should) 55 if (isInstanceOf!(ShouldType, Should)) 56 { 57 should.allowOnlyWords!("not").before!"only"; 58 59 return should.addWord!"only"; 60 } 61 62 /** 63 * The phrase `.contain.all` takes a range, all elements of which are expected to appear 64 * in the range on the left hand side. 65 */ 66 public void all(Should, T)(Should should, T expected, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__) 67 if (isInstanceOf!(ShouldType, Should)) 68 { 69 should.requireWord!"contain".before!"all"; 70 should.allowOnlyWords!("not", "contain").before!"all"; 71 72 should.addWord!"all".checkContain(expected, file, line); 73 } 74 75 /// 76 unittest 77 { 78 [2, 3, 4].should.contain.all([3]); 79 [2, 3, 4].should.contain.all([4, 3]); 80 [2, 3, 4].should.not.contain.all([3, 4, 5]); 81 } 82 83 /** 84 * The phrase `.contain.any` takes a range, at least one element of which is expected to appear 85 * in the range on the left hand side. 86 */ 87 public void any(Should, T)(Should should, T expected, Fence _ = Fence(), string file = __FILE__, size_t line = __LINE__) 88 if (isInstanceOf!(ShouldType, Should)) 89 { 90 should.requireWord!"contain".before!"any"; 91 should.allowOnlyWords!("not", "contain").before!"any"; 92 93 should.addWord!"any".checkContain(expected, file, line); 94 } 95 96 /// 97 unittest 98 { 99 [2, 3, 4].should.contain.any([4, 5]); 100 [2, 3, 4].should.not.contain.any([5, 6]); 101 } 102 103 unittest 104 { 105 const int[] constArray = [2, 3, 4]; 106 107 constArray.should.contain(4); 108 } 109 110 private void checkContain(Should, T)(Should should, T expected, string file, size_t line) 111 if (isInstanceOf!(ShouldType, Should)) 112 { 113 import std.algorithm : any, all, canFind; 114 import std.format : format; 115 import std.range : ElementType, save; 116 117 with (should) 118 { 119 auto got = should.got(); 120 121 enum rhsIsValue = is(const T == const ElementType!(typeof(got))); 122 123 static if (rhsIsValue) 124 { 125 allowOnlyWords!("not", "only", "contain").before!"contain"; 126 127 static if (hasWord!"only") 128 { 129 static if (hasWord!"not") 130 { 131 check( 132 got.any!(a => a != expected), 133 format("array containing values other than %s", expected), 134 format("%s", got), 135 file, line); 136 } 137 else 138 { 139 check( 140 got.all!(a => a == expected), 141 format("array containing only the value %s", expected), 142 format("%s", got), 143 file, line); 144 } 145 } 146 else 147 { 148 static if (hasWord!"not") 149 { 150 check( 151 !got.save.canFind(expected), 152 format("array not containing %s", expected), 153 format("%s", got), 154 file, line); 155 } 156 else 157 { 158 check( 159 got.save.canFind(expected), 160 format("array containing %s", expected), 161 format("%s", got), 162 file, line); 163 } 164 } 165 } 166 else 167 { 168 static if (hasWord!"only") 169 { 170 static if (hasWord!"not") 171 { 172 check( 173 !got.all!(a => expected.save.canFind(a)), 174 format("array containing values other than %s", expected), 175 format("%s", got), 176 file, line); 177 } 178 else 179 { 180 check( 181 got.all!(a => expected.save.canFind(a)), 182 format("array containing only the values %s", expected), 183 format("%s", got), 184 file, line); 185 } 186 } 187 else static if (hasWord!"all") 188 { 189 static if (hasWord!"not") 190 { 191 check( 192 !expected.all!(a => got.save.canFind(a)), 193 format("array not containing every value in %s", expected), 194 format("%s", got), 195 file, line); 196 } 197 else 198 { 199 check( 200 expected.all!(a => got.save.canFind(a)), 201 format("array containing every value in %s", expected), 202 format("%s", got), 203 file, line); 204 } 205 } 206 else static if (hasWord!"any") 207 { 208 static if (hasWord!"not") 209 { 210 check( 211 !expected.any!(a => got.save.canFind(a)), 212 format("array not containing any value in %s", expected), 213 format("%s", got), 214 file, line); 215 } 216 else 217 { 218 check( 219 expected.any!(a => got.save.canFind(a)), 220 format("array containing any value of %s", expected), 221 format("%s", got), 222 file, line); 223 } 224 } 225 else 226 { 227 static assert(false, 228 `bad grammar: expected "contain all", "contain any", "contain only" (or "only contain")`); 229 } 230 } 231 } 232 }