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 version(Windows) {} 63 else { 64 @("Targets should only be built once") unittest { 65 import std.process; 66 import std.stdio: File; 67 import std.range; 68 import std.algorithm: map; 69 import std.conv: to; 70 import std..string: splitLines, stripRight; 71 72 enum fooSrcName = "foo.txt"; 73 enum barSrcName = "bar.txt"; 74 75 scope(exit) { 76 foreach(name; [fooSrcName, barSrcName, "foo", "bar"]) 77 remove(name); 78 executeShell("rm -rf objs"); 79 } 80 81 { 82 // create the src files so the rule fires 83 auto fooSrc = File(fooSrcName, "w"); 84 auto barSrc = File(barSrcName, "w"); 85 } 86 87 auto foo = Target("$project/foo", "echo foo >> $out", [], [Target(fooSrcName)]); 88 auto bar = Target("$project/bar", "echo bar >> $out", [], [Target(barSrcName)]); 89 auto mids = 10.iota 90 .map!(a => Target.phony("$project/" ~a.to!string, "echo " ~ a.to!string, [foo, bar])) 91 .array 92 ; 93 auto top = Target.phony("top", "echo top", mids); 94 95 auto binary = Binary(Build(top), getOptions(["reggae", "--export", "-b", "binary"])); 96 binary.run(["./build"]); 97 98 // only one line -> rule only called once 99 readText("foo").splitLines.map!stripRight.shouldEqual(["foo"]); 100 readText("bar").splitLines.map!stripRight.shouldEqual(["bar"]); 101 } 102 } 103 104 @("List of targets") unittest { 105 auto file = FakeFile(); 106 auto binary = Binary(binaryBuild, getOptions(["reggae", "-b", "binary"]), file); 107 binary.run(["./build", "-l"]); 108 file.lines.shouldEqual( 109 ["List of available top-level targets:", 110 "- copy.txt", 111 "- opt (optional)"]); 112 } 113 114 @("List of targets with $project in the name") unittest { 115 import reggae.path: buildPath; 116 117 version(Windows) 118 enum cmd = `copy $in $out`; 119 else 120 enum cmd = `cp $in $out`; 121 122 auto build = Build(optional(Target(buildPath("$project/../druntime", copyFileName), cmd, Target(origFileName))), 123 Target.phony(`opt`, `echo Optional!`)); 124 auto file = FakeFile(); 125 auto binary = Binary(build, getOptions(["reggae", "-b", "binary"]), file); 126 binary.run(["./build", "-l"]); 127 file.lines.shouldEqual( 128 [ 129 "List of available top-level targets:", 130 "- opt", 131 "- " ~ buildPath(getcwd(), "../druntime/copy.txt") ~ " (optional)", 132 ] 133 ); 134 }