1 /** 2 Copyright: Copyright (c) 2016, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module test.extra_should; 11 12 import std.ascii : newline; 13 import std.traits : isSomeString; 14 15 /** Verify in lockstep that the two values are the same. 16 * 17 * Useful when the values can be treated as ranges. 18 * The lockstep comparison then results in a more comprehensible failure 19 * message. 20 * 21 * trusted: it only affects unittesting. 22 * 23 * Throws: UnitTestException on failure 24 * Params: 25 * value = actual value. 26 * expected = expected value. 27 * file = file check is in. 28 * line = line check is on. 29 */ 30 void shouldEqualPretty(V, E)(lazy V value, lazy E expected, string file = __FILE__, 31 size_t line = __LINE__) @trusted if (!isAllSomeString!(V, E)) { 32 import std.algorithm : count; 33 import std.range : lockstep; 34 import unit_threaded : shouldEqual, UnitTestException; 35 import std.conv : text; 36 37 size_t idx; 38 39 try { 40 foreach (index, val, exp; lockstep(value, expected)) { 41 idx = index; 42 shouldEqual(val, exp, file, line); 43 } 44 } 45 catch (UnitTestException ex) { 46 string[] lines = ["Chunk:" ~ idx.text, ex.toString()]; 47 throw new UnitTestException(lines, file, line); 48 } 49 50 shouldEqual(count(value), count(expected), file, line); 51 } 52 53 unittest { 54 // @Name("shouldEqualPretty should throw the first value that is different") 55 import unit_threaded : UnitTestException; 56 57 string msg; 58 try { 59 auto value = [0, 2, 1]; 60 auto expected = [0, 1, 2]; 61 shouldEqualPretty!(typeof(value), typeof(expected))(value, expected, "file.d", 123); 62 63 assert(false, "Didn't throw exception"); 64 } 65 catch (UnitTestException ex) { 66 msg = ex.toString; 67 } 68 69 msg = "foo"; 70 shouldEqualPretty(msg, "foo"); 71 assert(msg, "foo"); 72 } 73 74 /** Split with sep and verify in lockstep that the two values are the same. 75 * 76 * Throws: UnitTestException on failure. 77 * Params: 78 * value = actual value. 79 * expected = expected value. 80 * sep = separator to split value and expected on. 81 * file = file check is in. 82 * line = line check is on. 83 */ 84 void shouldEqualPretty(V, E, Separator)(lazy V value, lazy E expected, 85 lazy Separator sep, string file = __FILE__, size_t line = __LINE__) @safe 86 if (!isAllSomeString!(V, E)) { 87 import std.algorithm : splitter; 88 89 auto rValue = value.splitter(sep); 90 auto rExpected = expected.splitter(sep); 91 92 shouldEqualPretty!(typeof(rValue), typeof(rExpected))(rValue, rExpected, file, line); 93 } 94 95 /** Verify that two strings are the same. 96 * 97 * Performs tests per line to better isolate when a difference is found. 98 * 99 * Throws: UnitTestException on failure 100 * Params: 101 * value = actual value. 102 * expected = expected value. 103 * file = file check is in. 104 * line = line check is on. 105 */ 106 void shouldEqualPretty(V, E)(lazy V value, lazy E expected, lazy string sep = newline, 107 string file = __FILE__, size_t line = __LINE__) @safe 108 if (isAllSomeString!(V, E)) { 109 import std.algorithm : splitter; 110 111 auto rValue = value.splitter(sep); 112 auto rExpected = expected.splitter(sep); 113 114 shouldEqualPretty!(typeof(rValue), typeof(rExpected))(rValue, rExpected, file, line); 115 } 116 117 private enum isAllSomeString(T0, T1) = isSomeString!T0 && isSomeString!T1;