1 module fluentasserts.core.operations.contain; 2 3 import std.algorithm; 4 import std.array; 5 import std.conv; 6 7 import fluentasserts.core.array; 8 import fluentasserts.core.results; 9 import fluentasserts.core.evaluation; 10 import fluentasserts.core.serializers; 11 12 import fluentasserts.core.lifecycle; 13 14 version(unittest) { 15 import fluentasserts.core.expect; 16 } 17 18 /// 19 IResult[] contain(ref Evaluation evaluation) @safe nothrow { 20 evaluation.message.addText("."); 21 22 IResult[] results = []; 23 24 auto expectedPieces = evaluation.expectedValue.strValue.parseList.cleanString; 25 auto testData = evaluation.currentValue.strValue.cleanString; 26 27 if(!evaluation.isNegated) { 28 auto missingValues = expectedPieces.filter!(a => !testData.canFind(a)).array; 29 30 if(missingValues.length > 0) { 31 addLifecycleMessage(evaluation, missingValues); 32 try results ~= new ExpectedActualResult(createResultMessage(evaluation.expectedValue, expectedPieces), testData); 33 catch(Exception e) { 34 results ~= e.toResults; 35 return results; 36 } 37 } 38 } else { 39 auto presentValues = expectedPieces.filter!(a => testData.canFind(a)).array; 40 41 if(presentValues.length > 0) { 42 string message = "to not contain "; 43 44 if(presentValues.length > 1) { 45 message ~= "any "; 46 } 47 48 message ~= evaluation.expectedValue.strValue; 49 50 evaluation.message.addText(" "); 51 52 if(presentValues.length == 1) { 53 try evaluation.message.addValue(presentValues[0]); catch(Exception e) { 54 evaluation.message.addText(" some value "); 55 } 56 57 evaluation.message.addText(" is present in "); 58 } else { 59 try evaluation.message.addValue(presentValues.to!string); catch(Exception e) { 60 evaluation.message.addText(" some values "); 61 } 62 63 evaluation.message.addText(" are present in "); 64 } 65 66 evaluation.message.addValue(evaluation.currentValue.strValue); 67 evaluation.message.addText("."); 68 69 try results ~= new ExpectedActualResult(message, testData); 70 catch(Exception e) { 71 results ~= e.toResults; 72 return results; 73 } 74 } 75 } 76 77 return results; 78 } 79 80 /// 81 IResult[] arrayContain(ref Evaluation evaluation) @trusted nothrow { 82 evaluation.message.addText("."); 83 84 IResult[] results = []; 85 86 auto expectedPieces = evaluation.expectedValue.proxyValue.toArray; 87 auto testData = evaluation.currentValue.proxyValue.toArray; 88 89 if(!evaluation.isNegated) { 90 auto missingValues = expectedPieces.filter!(a => testData.filter!(b => b.isEqualTo(a)).empty).array; 91 92 if(missingValues.length > 0) { 93 addLifecycleMessage(evaluation, missingValues); 94 try results ~= new ExpectedActualResult(createResultMessage(evaluation.expectedValue, expectedPieces), evaluation.currentValue.strValue); 95 catch(Exception e) { 96 results ~= e.toResults; 97 return results; 98 } 99 } 100 } else { 101 auto presentValues = expectedPieces.filter!(a => !testData.filter!(b => b.isEqualTo(a)).empty).array; 102 103 if(presentValues.length > 0) { 104 addNegatedLifecycleMessage(evaluation, presentValues); 105 try results ~= new ExpectedActualResult(createNegatedResultMessage(evaluation.expectedValue, expectedPieces), evaluation.currentValue.strValue); 106 catch(Exception e) { 107 results ~= e.toResults; 108 return results; 109 } 110 } 111 } 112 113 return results; 114 } 115 116 /// 117 IResult[] arrayContainOnly(ref Evaluation evaluation) @safe nothrow { 118 evaluation.message.addText("."); 119 120 IResult[] results = []; 121 122 auto expectedPieces = evaluation.expectedValue.proxyValue.toArray; 123 auto testData = evaluation.currentValue.proxyValue.toArray; 124 125 auto comparison = ListComparison!EquableValue(testData, expectedPieces); 126 127 EquableValue[] missing; 128 EquableValue[] extra; 129 EquableValue[] common; 130 131 try { 132 missing = comparison.missing; 133 extra = comparison.extra; 134 common = comparison.common; 135 } catch(Exception e) { 136 results ~= e.toResults; 137 138 return results; 139 } 140 141 string strExtra = ""; 142 string strMissing = ""; 143 144 if(extra.length > 0) { 145 strExtra = extra.niceJoin(evaluation.currentValue.typeName); 146 } 147 148 if(missing.length > 0) { 149 strMissing = missing.niceJoin(evaluation.currentValue.typeName); 150 } 151 152 if(!evaluation.isNegated) { 153 auto isSuccess = missing.length == 0 && extra.length == 0 && common.length == testData.length; 154 155 if(!isSuccess) { 156 try results ~= new ExpectedActualResult("", testData.niceJoin(evaluation.currentValue.typeName)); 157 catch(Exception e) { 158 results ~= e.toResults; 159 return results; 160 } 161 162 try results ~= new ExtraMissingResult(strExtra, strMissing); 163 catch(Exception e) { 164 results ~= e.toResults; 165 return results; 166 } 167 } 168 } else { 169 auto isSuccess = (missing.length != 0 || extra.length != 0) || common.length != testData.length; 170 171 if(!isSuccess) { 172 try results ~= new ExpectedActualResult("to not contain " ~ expectedPieces.niceJoin(evaluation.currentValue.typeName), testData.niceJoin(evaluation.currentValue.typeName)); 173 catch(Exception e) { 174 results ~= e.toResults; 175 return results; 176 } 177 } 178 } 179 180 return results; 181 } 182 183 /// 184 void addLifecycleMessage(ref Evaluation evaluation, string[] missingValues) @safe nothrow { 185 evaluation.message.addText(" "); 186 187 if(missingValues.length == 1) { 188 try evaluation.message.addValue(missingValues[0]); catch(Exception) { 189 evaluation.message.addText(" some value "); 190 } 191 192 evaluation.message.addText(" is missing from "); 193 } else { 194 try { 195 evaluation.message.addValue(missingValues.niceJoin(evaluation.currentValue.typeName)); 196 } catch(Exception) { 197 evaluation.message.addText(" some values "); 198 } 199 200 evaluation.message.addText(" are missing from "); 201 } 202 203 evaluation.message.addValue(evaluation.currentValue.strValue); 204 evaluation.message.addText("."); 205 } 206 207 /// 208 void addLifecycleMessage(ref Evaluation evaluation, EquableValue[] missingValues) @safe nothrow { 209 auto missing = missingValues.map!(a => a.getSerialized.cleanString).array; 210 211 addLifecycleMessage(evaluation, missing); 212 } 213 214 /// 215 void addNegatedLifecycleMessage(ref Evaluation evaluation, string[] presentValues) @safe nothrow { 216 evaluation.message.addText(" "); 217 218 if(presentValues.length == 1) { 219 try evaluation.message.addValue(presentValues[0]); catch(Exception e) { 220 evaluation.message.addText(" some value "); 221 } 222 223 evaluation.message.addText(" is present in "); 224 } else { 225 try evaluation.message.addValue(presentValues.niceJoin(evaluation.currentValue.typeName)); 226 catch(Exception e) { 227 evaluation.message.addText(" some values "); 228 } 229 230 evaluation.message.addText(" are present in "); 231 } 232 233 evaluation.message.addValue(evaluation.currentValue.strValue); 234 evaluation.message.addText("."); 235 } 236 237 /// 238 void addNegatedLifecycleMessage(ref Evaluation evaluation, EquableValue[] missingValues) @safe nothrow { 239 auto missing = missingValues.map!(a => a.getSerialized).array; 240 241 addNegatedLifecycleMessage(evaluation, missing); 242 } 243 244 string createResultMessage(ValueEvaluation expectedValue, string[] expectedPieces) @safe nothrow { 245 string message = "to contain "; 246 247 if(expectedPieces.length > 1) { 248 message ~= "all "; 249 } 250 251 message ~= expectedValue.strValue; 252 253 return message; 254 } 255 256 /// 257 string createResultMessage(ValueEvaluation expectedValue, EquableValue[] missingValues) @safe nothrow { 258 auto missing = missingValues.map!(a => a.getSerialized).array; 259 260 return createResultMessage(expectedValue, missing); 261 } 262 263 string createNegatedResultMessage(ValueEvaluation expectedValue, string[] expectedPieces) @safe nothrow { 264 string message = "to not contain "; 265 266 if(expectedPieces.length > 1) { 267 message ~= "any "; 268 } 269 270 message ~= expectedValue.strValue; 271 272 return message; 273 } 274 275 /// 276 string createNegatedResultMessage(ValueEvaluation expectedValue, EquableValue[] missingValues) @safe nothrow { 277 auto missing = missingValues.map!(a => a.getSerialized).array; 278 279 return createNegatedResultMessage(expectedValue, missing); 280 } 281 282 string niceJoin(string[] values, string typeName = "") @safe nothrow { 283 string result = ""; 284 285 try { 286 result = values.to!string; 287 288 if(!typeName.canFind("string")) { 289 result = result.replace(`"`, ""); 290 } 291 } catch(Exception) {} 292 293 return result; 294 } 295 296 string niceJoin(EquableValue[] values, string typeName = "") @safe nothrow { 297 return values.map!(a => a.getSerialized.cleanString).array.niceJoin(typeName); 298 } 299