1 module test.utils; 2 3 import std.algorithm: map; 4 import std.array: join; 5 import std.format: format; 6 import std..string: splitLines; 7 import std.range: zip, enumerate; 8 import std..string: toUpper; 9 import std.traits: EnumMembers; 10 import std.conv: to; 11 12 import capstone.api; 13 14 /** Most relevant disassembly options 15 16 Used for concise configuration of the big regression tests 17 */ 18 struct Platform{ 19 Arch arch; 20 Mode mode; 21 ubyte[] code; 22 string comment; 23 Syntax syntax; 24 string skipdataMnemonic; 25 Callback callback; 26 } 27 28 /// Pretty printing of bytes as in original regression tests 29 auto bytesToHex(in ubyte[] code, bool xPrefix = true, bool upperCase = false, bool spaced = true){ 30 auto fmt = (xPrefix ? "0x" : "") // Hex prefix 31 ~ "%02" ~ (upperCase ? "X" : "x") // Hex formatting (with chosen case) 32 ~ (spaced ? " " : ""); // Terminal space needed to match original 33 return code.map!(i => fmt.format(i)).join; 34 } 35 /// 36 unittest{ 37 const CODE = cast(ubyte[])"\xDE\xAD\xBE\xEF"; 38 assert(CODE.bytesToHex == "0xde 0xad 0xbe 0xef "); 39 } 40 41 /// Pretty printing of mismatches in regression tests 42 string expectationMismatch(in string expected, in string actual) 43 in{ 44 assert(expected != actual); 45 } 46 body{ 47 auto expectedLines = expected.splitLines(); 48 auto actualLines = actual.splitLines(); 49 50 foreach(i, e, a; zip(expectedLines, actualLines).enumerate(1)){ 51 if(e != a) 52 return "Mismatch in line %d\nExpected: %s\n Actual: %s".format(i,e,a); 53 } 54 55 return "Expected %d lines (got %d)".format(expectedLines.length, actualLines.length); 56 } 57 /// 58 unittest{ 59 string expected = "line1\nline2\nline3"; 60 {// Mismatch in line 2 } 61 string actual = "line1\nlin2\nline3"; 62 auto res = expectationMismatch(expected, actual); 63 assert("Mismatch in line 2\nExpected: line2\n Actual: lin2" == res); 64 } 65 {// Too short 66 string actual = "line1"; 67 auto res = expectationMismatch(expected, actual); 68 assert("Expected 3 lines (got 1)" == res); 69 } 70 {// Too long 71 string actual = "line1\nline2\nline3\nline4"; 72 auto res = expectationMismatch(expected, actual); 73 assert("Expected 3 lines (got 4)" == res); 74 } 75 } 76 77 string accessToString(AccessFlags access) { 78 string[] accessStrs; 79 foreach(accessType; EnumMembers!AccessType[1..$]) // Skip AccessType.invalid 80 if(access & accessType) 81 accessStrs ~= accessType.to!string.toUpper; 82 return accessStrs.join(" | "); 83 } 84 /// 85 unittest{ 86 AccessFlags inv; 87 assert("", inv.accessToString); 88 auto rw = AccessFlags(AccessType.read | AccessType.write); 89 assert("READ | WRITE", rw.accessToString); 90 }