1 // Integration tests for the binary backend 2 module tests.it.backend.binary; 3 4 import reggae; 5 import unit_threaded; 6 import std.file; 7 import std.string; 8 9 10 enum origFileName = "original.txt"; 11 enum copyFileName = "copy.txt"; 12 13 14 private Build binaryBuild() { 15 version(Windows) 16 enum cmd = `copy $in $out`; 17 else 18 enum cmd = `cp $in $out`; 19 20 mixin build!(Target(copyFileName, cmd, Target(origFileName)), 21 optional(Target.phony(`opt`, `echo Optional!`))); 22 23 return buildFunc(); 24 } 25 26 private void writeOrigFile() { 27 import std.stdio: File; 28 auto file = File(origFileName, "w"); 29 file.writeln("See the little goblin"); 30 } 31 32 private struct FakeFile { 33 string[] lines; 34 void writeln(T...)(T args) { 35 import std.conv; 36 lines ~= text(args); 37 } 38 } 39 40 41 @("Do nothing after build") unittest { 42 scope(exit) { 43 remove(copyFileName); 44 remove(origFileName); 45 } 46 47 writeOrigFile; 48 49 auto file = FakeFile(); 50 auto binary = Binary(binaryBuild, getOptions(["./reggae", "-b", "binary"]), file); 51 auto args = ["./build", "--norerun"]; 52 binary.run(args); 53 54 copyFileName.exists.shouldBeTrue; 55 56 file.lines = []; 57 binary.run(args); 58 file.lines.shouldEqual(["[build] Nothing to do"]); 59 } 60 61 62 @("Targets should only be built once") unittest { 63 import std.process; 64 import std.stdio: File; 65 import std.range; 66 import std.algorithm: map; 67 import std.conv: to; 68 import std.string: splitLines, stripRight; 69 70 enum fooSrcName = "foo.txt"; 71 enum barSrcName = "bar.txt"; 72 73 scope(exit) { 74 foreach(name; [fooSrcName, barSrcName, "foo", "bar"]) 75 remove(name); 76 executeShell("rm -rf objs"); 77 } 78 79 { 80 // create the src files so the rule fires 81 auto fooSrc = File(fooSrcName, "w"); 82 auto barSrc = File(barSrcName, "w"); 83 } 84 85 auto foo = Target("$project/foo", "echo foo >> $out", [], [Target(fooSrcName)]); 86 auto bar = Target("$project/bar", "echo bar >> $out", [], [Target(barSrcName)]); 87 auto mids = 10.iota 88 .map!(a => Target.phony("$project/" ~a.to!string, "echo " ~ a.to!string, [foo, bar])) 89 .array 90 ; 91 auto top = Target.phony("top", "echo top", mids); 92 93 auto binary = Binary(Build(top), getOptions(["reggae", "--export", "-b", "binary"])); 94 binary.run(["./build"]); 95 96 // only one line -> rule only called once 97 readText("foo").splitLines.map!stripRight.shouldEqual(["foo"]); 98 readText("bar").splitLines.map!stripRight.shouldEqual(["bar"]); 99 } 100 101 102 @("List of targets") unittest { 103 auto file = FakeFile(); 104 auto binary = Binary(binaryBuild, getOptions(["reggae", "-b", "binary"]), file); 105 binary.run(["./build", "-l"]); 106 file.lines.shouldEqual( 107 ["List of available top-level targets:", 108 "- copy.txt", 109 "- opt (optional)"]); 110 } 111 112 @("List of targets with $project in the name") unittest { 113 import std.path; 114 115 version(Windows) 116 enum cmd = `copy $in $out`; 117 else 118 enum cmd = `cp $in $out`; 119 120 auto build = Build(optional(Target(buildPath("$project", "..", "druntime", copyFileName), cmd, Target(origFileName))), 121 Target.phony(`opt`, `echo Optional!`)); 122 auto file = FakeFile(); 123 auto binary = Binary(build, getOptions(["reggae", "-b", "binary"]), file); 124 binary.run(["./build", "-l"]); 125 file.lines.shouldEqual( 126 [ 127 "List of available top-level targets:", 128 "- opt", 129 "- " ~ buildPath(getcwd(), "..", "druntime", "copy.txt") ~ " (optional)", 130 ] 131 ); 132 }