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 private void checkContain(Should, T)(Should should, T expected, string file, size_t line) 104 if (isInstanceOf!(ShouldType, Should)) 105 { 106 import std.algorithm : any, all, canFind; 107 import std.format : format; 108 import std.range : ElementType, save; 109 110 with (should) 111 { 112 auto got = should.got(); 113 114 enum rhsIsValue = is(T == ElementType!(typeof(got))); 115 116 static if (rhsIsValue) 117 { 118 allowOnlyWords!("not", "only", "contain").before!"contain"; 119 120 static if (hasWord!"only") 121 { 122 static if (hasWord!"not") 123 { 124 check( 125 got.any!(a => a != expected), 126 format("array containing values other than %s", expected), 127 format("%s", got), 128 file, line); 129 } 130 else 131 { 132 check( 133 got.all!(a => a == expected), 134 format("array containing only the value %s", expected), 135 format("%s", got), 136 file, line); 137 } 138 } 139 else 140 { 141 static if (hasWord!"not") 142 { 143 check( 144 !got.save.canFind(expected), 145 format("array not containing %s", expected), 146 format("%s", got), 147 file, line); 148 } 149 else 150 { 151 check( 152 got.save.canFind(expected), 153 format("array containing %s", expected), 154 format("%s", got), 155 file, line); 156 } 157 } 158 } 159 else 160 { 161 static if (hasWord!"only") 162 { 163 static if (hasWord!"not") 164 { 165 check( 166 !got.all!(a => expected.save.canFind(a)), 167 format("array containing values other than %s", expected), 168 format("%s", got), 169 file, line); 170 } 171 else 172 { 173 check( 174 got.all!(a => expected.save.canFind(a)), 175 format("array containing only the values %s", expected), 176 format("%s", got), 177 file, line); 178 } 179 } 180 else static if (hasWord!"all") 181 { 182 static if (hasWord!"not") 183 { 184 check( 185 !expected.all!(a => got.save.canFind(a)), 186 format("array not containing every value in %s", expected), 187 format("%s", got), 188 file, line); 189 } 190 else 191 { 192 check( 193 expected.all!(a => got.save.canFind(a)), 194 format("array containing every value in %s", expected), 195 format("%s", got), 196 file, line); 197 } 198 } 199 else static if (hasWord!"any") 200 { 201 static if (hasWord!"not") 202 { 203 check( 204 !expected.any!(a => got.save.canFind(a)), 205 format("array not containing any value in %s", expected), 206 format("%s", got), 207 file, line); 208 } 209 else 210 { 211 check( 212 expected.any!(a => got.save.canFind(a)), 213 format("array containing any value of %s", expected), 214 format("%s", got), 215 file, line); 216 } 217 } 218 else 219 { 220 static assert(false, 221 `bad grammar: expected "contain all", "contain any", "contain only" (or "only contain")`); 222 } 223 } 224 } 225 }