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