1 module tests.it.runtime.dub; 2 3 4 import tests.it.runtime; 5 import reggae.reggae; 6 import reggae.path: buildPath, deabsolutePath, dubPackagesDir; 7 8 9 @("noreggaefile.ninja") 10 @Tags(["dub", "ninja"]) 11 unittest { 12 13 import std..string: join; 14 import std.algorithm: filter; 15 16 with(immutable ReggaeSandbox("dub")) { 17 shouldNotExist("reggaefile.d"); 18 writelnUt("\n\nReggae output:\n\n", runReggae("-b", "ninja").lines.join("\n"), "-----\n"); 19 shouldExist("reggaefile.d"); 20 auto output = ninja(["-v"]).shouldExecuteOk; 21 22 version(Windows) { 23 // args in response file 24 } else { 25 output.shouldContain("-debug -g"); 26 } 27 28 shouldSucceed("atest").filter!(a => a != "").should == 29 [ 30 "Why hello!", 31 "I'm immortal!" 32 ]; 33 34 // there's only one UT in main.d which always fails 35 ninja(["ut"]).shouldExecuteOk; 36 shouldFail("ut"); 37 } 38 } 39 40 @("noreggaefile.tup") 41 @Tags(["dub", "tup"]) 42 unittest { 43 with(immutable ReggaeSandbox("dub")) { 44 runReggae("-b", "tup"). 45 shouldThrowWithMessage("dub integration not supported with the tup backend"); 46 } 47 } 48 49 50 @("prebuild") 51 @Tags(["dub", "ninja"]) 52 unittest { 53 with(immutable ReggaeSandbox("dub_prebuild")) { 54 runReggae("-b", "ninja"); 55 ninja(["default", "ut"]).shouldExecuteOk; 56 shouldSucceed("ut"); 57 } 58 } 59 60 61 @("postbuild") 62 @Tags(["dub", "ninja", "posix"]) 63 unittest { 64 with(immutable ReggaeSandbox("dub_postbuild")) { 65 runReggae("-b", "ninja"); 66 ninja.shouldExecuteOk; 67 shouldExist("foo.txt"); 68 shouldSucceed("postbuild"); 69 } 70 } 71 72 73 @("dependencies not on file system already no dub.selections.json") 74 @Tags(["dub", "ninja"]) 75 unittest { 76 77 import std.file: exists, rmdirRecurse; 78 import std.process: environment; 79 80 const cerealedDir = buildPath(dubPackagesDir(), "cerealed-0.6.8"); 81 if(cerealedDir.exists) 82 rmdirRecurse(cerealedDir); 83 84 with(immutable ReggaeSandbox()) { 85 writeFile("dub.json", ` 86 { 87 "name": "depends_on_cerealed", 88 "license": "MIT", 89 "targetType": "executable", 90 "dependencies": { "cerealed": "==0.6.8" } 91 }`); 92 writeFile("source/app.d", "void main() {}"); 93 94 runReggae("-b", "ninja"); 95 } 96 } 97 98 99 @("no main function but with unit tests") 100 @Tags(["dub", "ninja"]) 101 unittest { 102 import std.file: mkdirRecurse; 103 104 with(immutable ReggaeSandbox()) { 105 writeFile("dub.json", ` 106 { 107 "name": "depends_on_cerealed", 108 "license": "MIT", 109 "targetType": "executable", 110 "dependencies": { "cerealed": "==0.6.8" } 111 }`); 112 113 writeFile("reggaefile.d", q{ 114 import reggae; 115 mixin build!(dubTestTarget!()); 116 }); 117 118 mkdirRecurse(buildPath(testPath, "source")); 119 writeFile("source/foo.d", `unittest { assert(false); }`); 120 runReggae("-b", "ninja"); 121 ninja.shouldExecuteOk; 122 123 shouldFail("ut"); 124 } 125 } 126 127 128 @("reggae/dub build should rebuild if dub.selections.json changes") 129 @Tags(["dub", "make"]) 130 unittest { 131 132 import std.process: execute; 133 134 with(immutable ReggaeSandbox("dub")) { 135 runReggae("-b", "make"); 136 make(["VERBOSE=1"]).shouldExecuteOk.shouldContain("-debug -g"); 137 { 138 const ret = execute(["touch", buildPath(testPath, "dub.selections.json")]); 139 ret.status.shouldEqual(0); 140 } 141 { 142 const ret = execute(["make", "-C", testPath]); 143 ret.output.shouldContain("eggae"); 144 } 145 } 146 } 147 148 @("version from main package is used in dependent packages") 149 @Tags(["dub", "ninja"]) 150 unittest { 151 with(immutable ReggaeSandbox()) { 152 writeFile("dub.sdl", ` 153 name "foo" 154 versions "lefoo" 155 targetType "executable" 156 dependency "bar" path="bar" 157 `); 158 writeFile("source/app.d", q{ 159 void main() { 160 import bar; 161 import std.stdio; 162 writeln(lebar); 163 } 164 }); 165 writeFile("bar/dub.sdl", ` 166 name "bar" 167 `); 168 writeFile("bar/source/bar.d", q{ 169 module bar; 170 version(lefoo) 171 int lebar() { return 3; } 172 else 173 int lebar() { return 42; } 174 }); 175 runReggae("-b", "ninja"); 176 ninja.shouldExecuteOk; 177 shouldSucceed("foo").shouldEqual( 178 [ 179 "3", 180 ] 181 ); 182 } 183 } 184 185 186 @("sourceLibrary dependency") 187 @Tags(["dub", "ninja"]) 188 unittest { 189 with(immutable ReggaeSandbox()) { 190 writeFile("dub.sdl", ` 191 name "foo" 192 targetType "executable" 193 dependency "bar" path="bar" 194 `); 195 writeFile("source/app.d", q{ 196 void main() { 197 import bar; 198 import std.stdio; 199 writeln(lebar); 200 } 201 }); 202 writeFile("bar/dub.sdl", ` 203 name "bar" 204 targetType "sourceLibrary" 205 `); 206 writeFile("bar/source/bar.d", q{ 207 module bar; 208 int lebar() { return 3; } 209 }); 210 runReggae("-b", "ninja"); 211 ninja.shouldExecuteOk; 212 } 213 } 214 215 version(Windows) version(DigitalMars) version = Windows_DMD; 216 217 version(Windows_DMD) { 218 /** 219 * On Windows, DMD defaults to -m32, reggae to -m32mscoff (for DMD), and 220 * dub to -m64 (if run on a 64-bit Windows host, otherwise -m32mscoff) for 221 * compilers with DMD CLI (dmd, gdmd, ldmd2). ;) 222 * Windows_DMD assumes a 32-bit MSVC environment (cl.exe etc.) for the 223 * tests, so specify the corresponding dub architecture in the reggae 224 * cmdline. 225 */ 226 enum dubArch = "--dub-arch=x86_mscoff"; 227 } else { 228 enum string dubArch = null; 229 } 230 231 version(DigitalMars) { 232 @("object source files.simple") 233 @Tags(["dub", "ninja"]) 234 unittest { 235 with(immutable ReggaeSandbox()) { 236 writeFile("dub.sdl", ` 237 name "foo" 238 targetType "executable" 239 dependency "bar" path="bar" 240 `); 241 writeFile("source/app.d", q{ 242 extern(C) int lebaz(); 243 void main() { 244 import bar; 245 import std.stdio; 246 writeln(lebar); 247 writeln(lebaz); 248 } 249 }); 250 writeFile("bar/dub.sdl", ` 251 name "bar" 252 sourceFiles "../baz.o" platform="posix" 253 sourceFiles "../baz.obj" platform="windows" 254 `); 255 writeFile("bar/source/bar.d", q{ 256 module bar; 257 int lebar() { return 3; } 258 }); 259 writeFile("baz.d", q{ 260 module baz; 261 extern(C) int lebaz() { return 42; } 262 }); 263 264 version(Windows_DMD) 265 ["dmd", "-m32mscoff", "-c", "baz.d"].shouldExecuteOk; 266 else 267 ["dmd", "-c", "baz.d"].shouldExecuteOk; 268 269 runReggae("-b", "ninja", dubArch); 270 ninja.shouldExecuteOk; 271 } 272 } 273 } 274 275 276 @("dub objs option path dependency") 277 @Tags("dub", "ninja", "dubObjsDir") 278 unittest { 279 280 with(immutable ReggaeSandbox()) { 281 282 writeFile("reggaefile.d", q{ 283 import reggae; 284 mixin build!(dubDefaultTarget!()); 285 }); 286 287 writeFile("dub.sdl",` 288 name "foo" 289 targetType "executable" 290 dependency "bar" path="bar" 291 `); 292 293 writeFile("source/app.d", q{ 294 import bar; 295 void main() { add(2, 3); } 296 }); 297 298 writeFile("bar/dub.sdl", ` 299 name "bar" 300 `); 301 302 writeFile("bar/source/bar.d", q{ 303 module bar; 304 int add(int i, int j) { return i + j; } 305 }); 306 307 const dubObjsDir = buildPath(testPath, "objsdir"); 308 const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ dubObjsDir, "--dub-deps-objs"); 309 writelnUt(output); 310 ninja.shouldExecuteOk; 311 312 shouldExist(buildPath("objsdir", 313 testPath.deabsolutePath, 314 "foo" ~ exeExt ~ ".objs", 315 testPath.deabsolutePath, 316 "bar", 317 "source_bar" ~ objExt)); 318 } 319 } 320 321 322 @("dub objs option registry dependency") 323 @Tags("dub", "ninja", "dubObjsDir") 324 unittest { 325 326 import reggae.path: dubPackagesDir, deabsolutePath; 327 328 with(immutable ReggaeSandbox()) { 329 330 writeFile("reggaefile.d", q{ 331 import reggae; 332 mixin build!(dubDefaultTarget!()); 333 }); 334 335 writeFile("dub.sdl",` 336 name "foo" 337 targetType "executable" 338 dependency "dubnull" version="==0.0.1" 339 `); 340 341 writeFile("source/app.d", q{ 342 import dubnull; 343 void main() { dummy(); } 344 }); 345 346 const dubObjsDir = buildPath(testPath, "objsdir"); 347 const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ dubObjsDir, "--dub-deps-objs"); 348 writelnUt(output); 349 350 ninja.shouldExecuteOk; 351 352 const dubNullDir = buildPath(dubPackagesDir, "dubnull-0.0.1/dubnull").deabsolutePath; 353 shouldExist(buildPath("objsdir", 354 testPath.deabsolutePath, 355 "foo" ~ exeExt ~ ".objs", 356 dubNullDir, 357 "source_dubnull" ~ objExt)); 358 } 359 } 360 361 version(DigitalMars) { 362 @("object source files.with dub objs option") 363 @Tags("dub", "ninja", "dubObjsDir") 364 unittest { 365 with(immutable ReggaeSandbox()) { 366 writeFile("dub.sdl", ` 367 name "foo" 368 targetType "executable" 369 dependency "bar" path="bar" 370 `); 371 writeFile("source/app.d", q{ 372 extern(C) int lebaz(); 373 void main() { 374 import bar; 375 import std.stdio; 376 writeln(lebar); 377 writeln(lebaz); 378 } 379 }); 380 writeFile("bar/dub.sdl", ` 381 name "bar" 382 sourceFiles "../baz.o" platform="posix" 383 sourceFiles "../baz.obj" platform="windows" 384 `); 385 writeFile("bar/source/bar.d", q{ 386 module bar; 387 int lebar() { return 3; } 388 }); 389 writeFile("baz.d", q{ 390 module baz; 391 extern(C) int lebaz() { return 42; } 392 }); 393 394 version(Windows_DMD) { 395 ["dmd", "-m32mscoff", "-c", "baz.d"].shouldExecuteOk; 396 } else { 397 ["dmd", "-c", "baz.d"].shouldExecuteOk; 398 } 399 400 const output = runReggae("-b", "ninja", "--dub-objs-dir=" ~ testPath, dubArch); 401 writelnUt(output); 402 403 ninja.shouldExecuteOk; 404 } 405 } 406 } 407 408 409 @("dub with spaces") 410 @Tags("dub", "ninja") 411 unittest { 412 /* Use Ninja to build a tiny dub project with spaces in: 413 * - source directory 414 * - source filename 415 * - import directory 416 * - compiler flags 417 * - linker flags 418 * - output filename 419 */ 420 with(immutable ReggaeSandbox()) { 421 writeFile("dub.sdl", ` 422 name "dub_with_spaces" 423 targetName "dub with spaces" 424 targetType "executable" 425 426 sourcePaths "my source" 427 importPaths "my source" 428 mainSourceFile "my source/my module.d" 429 430 dflags "-L-Lmy libs" platform="posix" 431 dflags "-L/LIBPATH:my libs" platform="windows" 432 433 lflags "-Lmy other libs" platform="posix" 434 lflags "/LIBPATH:my other libs" platform="windows" 435 `); 436 437 writeFile("my source/my module.d", q{ 438 module my_module; 439 import other_module; 440 void main() { foo(); } 441 }); 442 443 writeFile("my source/other_module.d", q{ 444 void foo() {} 445 }); 446 447 // use --per-module to test that Ninja accepts the .dep files 448 // generated for both modules/objects 449 const output = runReggae("-b", "ninja", "--per-module"); 450 writelnUt(output); 451 452 ninja.shouldExecuteOk; 453 454 shouldExist("dub with spaces" ~ exeExt); 455 } 456 } 457 458 459 @("depends on package with prebuild") 460 @Tags(["dub", "ninja"]) 461 unittest { 462 463 with(immutable ReggaeSandbox("dub_depends_on_prebuild")) { 464 465 copyProject("dub_prebuild", buildPath("../dub_prebuild")); 466 467 runReggae("-b", "ninja"); 468 ninja.shouldExecuteOk; 469 shouldSucceed("app"); 470 shouldExist(inSandboxPath("../dub_prebuild/el_prebuildo.txt")); 471 } 472 } 473 474 475 @("staticLibrary.implicit") 476 @Tags(["dub", "ninja"]) 477 unittest { 478 479 with(immutable ReggaeSandbox()) { 480 writeFile("dub.sdl", ` 481 name "foo" 482 targetType "executable" 483 targetName "d++" 484 485 configuration "executable" { 486 } 487 488 configuration "library" { 489 targetType "library" 490 targetName "dpp" 491 excludedSourceFiles "source/main.d" 492 } 493 `); 494 495 writeFile("reggaefile.d", 496 q{ 497 import reggae; 498 alias lib = dubConfigurationTarget!(Configuration("library")); 499 enum mainObj = objectFile(SourceFile("source/main.d")); 500 alias exe = link!(ExeName("d++"), targetConcat!(lib, mainObj)); 501 mixin build!(exe); 502 }); 503 504 writeFile("source/main.d", "void main() {}"); 505 writeFile("source/foo/bar/mod.d", "module foo.bar.mod; int add1(int i, int j) { return i + j + 1; }"); 506 507 runReggae("-b", "ninja"); 508 ninja.shouldExecuteOk; 509 shouldSucceed("d++"); 510 } 511 } 512 513 514 @("staticLibrary.explicit") 515 @Tags(["dub", "ninja"]) 516 unittest { 517 518 with(immutable ReggaeSandbox()) { 519 writeFile("dub.sdl", ` 520 name "foo" 521 targetType "executable" 522 targetName "d++" 523 524 configuration "executable" { 525 } 526 527 configuration "library" { 528 targetType "staticLibrary" 529 targetName "dpp" 530 excludedSourceFiles "source/main.d" 531 } 532 `); 533 534 writeFile("reggaefile.d", 535 q{ 536 import reggae; 537 alias lib = dubConfigurationTarget!(Configuration("library")); 538 enum mainObj = objectFile(SourceFile("source/main.d")); 539 alias exe = link!(ExeName("d++"), targetConcat!(lib, mainObj)); 540 mixin build!(exe); 541 }); 542 543 writeFile("source/main.d", "void main() {}"); 544 writeFile("source/foo/bar/mod.d", "module foo.bar.mod; int add1(int i, int j) { return i + j + 1; }"); 545 546 runReggae("-b", "ninja"); 547 ninja.shouldExecuteOk; 548 shouldSucceed("d++"); 549 } 550 } 551 552 553 @("failing prebuild command") 554 @Tags(["dub", "ninja"]) 555 unittest { 556 with(immutable ReggaeSandbox("dub_prebuild_oops")) { 557 auto thrownInfo = runReggae("-b", "ninja").shouldThrow; 558 "Error calling foo bar baz quux:".should.be in thrownInfo.msg; 559 version(Windows) { 560 enum expectedDetail = "'foo' is not recognized as an internal or external command"; 561 } else { 562 enum expectedDetail = "not found"; 563 } 564 expectedDetail.should.be in thrownInfo.msg; 565 } 566 } 567 568 569 @("libs.plain") 570 @Tags(["dub", "ninja"]) 571 unittest { 572 with(immutable ReggaeSandbox()) { 573 writeFile("dub.sdl", ` 574 name "foo" 575 targetType "executable" 576 libs "utils" 577 lflags "-L$PACKAGE_DIR" platform="posix" 578 lflags "/LIBPATH:$PACKAGE_DIR" platform="windows" 579 580 configuration "executable" { 581 } 582 583 configuration "library" { 584 targetType "library" 585 targetName "dpp" 586 excludedSourceFiles "source/main.d" 587 } 588 `); 589 590 writeFile("reggaefile.d", 591 q{ 592 import reggae; 593 alias exe = dubDefaultTarget!( 594 ); 595 mixin build!(exe); 596 }); 597 598 writeFile("source/main.d", 599 q{ 600 extern(C) int twice(int); 601 void main() { 602 assert(twice(2) == 4); 603 assert(twice(3) == 6); 604 } 605 }); 606 607 writeFile("utils.c", "int twice(int i) { return i * 2; }"); 608 version(Windows) { 609 shouldExecuteOk(["cl.exe", "/Fo" ~ inSandboxPath("utils.obj"), "/c", inSandboxPath("utils.c")]); 610 shouldExecuteOk(["lib.exe", "/OUT:" ~ inSandboxPath("utils.lib"), inSandboxPath("utils.obj")]); 611 } else { 612 shouldExecuteOk(["gcc", "-o", inSandboxPath("utils.o"), "-c", inSandboxPath("utils.c")]); 613 shouldExecuteOk(["ar", "rcs", inSandboxPath("libutils.a"), inSandboxPath("utils.o")]); 614 } 615 616 runReggae("-b", "ninja", dubArch); 617 ninja.shouldExecuteOk; 618 shouldSucceed("foo"); 619 } 620 } 621 622 623 @("libs.posix") 624 @Tags(["dub", "ninja"]) 625 unittest { 626 with(immutable ReggaeSandbox()) { 627 writeFile("dub.sdl", ` 628 name "foo" 629 targetType "executable" 630 libs "utils" 631 lflags "-L$PACKAGE_DIR" platform="posix" 632 lflags "/LIBPATH:$PACKAGE_DIR" platform="windows" 633 634 configuration "executable" { 635 } 636 637 configuration "library" { 638 targetType "library" 639 targetName "dpp" 640 excludedSourceFiles "source/main.d" 641 } 642 `); 643 644 writeFile("reggaefile.d", 645 q{ 646 import reggae; 647 alias exe = dubDefaultTarget!( 648 ); 649 mixin build!(exe); 650 }); 651 652 writeFile("source/main.d", 653 q{ 654 extern(C) int twice(int); 655 void main() { 656 assert(twice(2) == 4); 657 assert(twice(3) == 6); 658 } 659 }); 660 661 writeFile("utils.c", "int twice(int i) { return i * 2; }"); 662 version(Windows) { 663 shouldExecuteOk(["cl.exe", "/Fo" ~ inSandboxPath("utils.obj"), "/c", inSandboxPath("utils.c")]); 664 shouldExecuteOk(["lib.exe", "/OUT:" ~ inSandboxPath("utils.lib"), inSandboxPath("utils.obj")]); 665 } else { 666 shouldExecuteOk(["gcc", "-o", inSandboxPath("utils.o"), "-c", inSandboxPath("utils.c")]); 667 shouldExecuteOk(["ar", "rcs", inSandboxPath("libutils.a"), inSandboxPath("utils.o")]); 668 } 669 670 runReggae("-b", "ninja", dubArch); 671 ninja.shouldExecuteOk; 672 shouldSucceed("foo"); 673 } 674 } 675 676 677 @("libs.dependency") 678 @Tags(["dub", "ninja"]) 679 unittest { 680 with(immutable ReggaeSandbox()) { 681 writeFile("dub.sdl", ` 682 name "foo" 683 targetType "executable" 684 dependency "bar" path="bar" 685 `); 686 687 writeFile("reggaefile.d", 688 q{ 689 import reggae; 690 mixin build!(dubDefaultTarget!()); 691 }); 692 693 writeFile("source/main.d", 694 q{ 695 import bar; 696 void main() { 697 assert(times4(2) == 8); 698 assert(times4(3) == 12); 699 } 700 }); 701 702 writeFile("bar/dub.sdl", ` 703 name "bar" 704 targetType "library" 705 lflags "-L$PACKAGE_DIR" platform="posix" 706 lflags "/LIBPATH:$PACKAGE_DIR" platform="windows" 707 libs "utils" 708 `); 709 710 writeFile("bar/source/bar.d", q{ 711 module bar; 712 extern(C) int twice(int); 713 int times4(int i) { return 2 * twice(i); } 714 } 715 ); 716 717 writeFile("bar/utils.c", "int twice(int i) { return i * 2; }"); 718 version(Windows) { 719 shouldExecuteOk(["cl.exe", "/Fo" ~ inSandboxPath("bar/utils.obj"), "/c", inSandboxPath("bar/utils.c")]); 720 shouldExecuteOk(["lib.exe", "/OUT:" ~ inSandboxPath("bar/utils.lib"), inSandboxPath("bar/utils.obj")]); 721 } else { 722 shouldExecuteOk(["gcc", "-o", inSandboxPath("bar/utils.o"), "-c", inSandboxPath("bar/utils.c")]); 723 shouldExecuteOk(["ar", "rcs", inSandboxPath("bar/libutils.a"), inSandboxPath("bar/utils.o")]); 724 } 725 726 runReggae("-b", "ninja", dubArch); 727 ninja.shouldExecuteOk; 728 shouldSucceed("foo"); 729 } 730 } 731 732 733 @("dflags.debug") 734 @Tags("dub", "ninja") 735 unittest { 736 with(immutable ReggaeSandbox()) { 737 writeFile("dub.sdl", ` 738 name "foo" 739 targetType "executable" 740 `); 741 742 writeFile("source/main.d", 743 q{ 744 void main() { 745 debug assert(false); 746 } 747 }); 748 749 runReggae("-b", "ninja"); 750 ninja.shouldExecuteOk; 751 shouldFail("foo"); 752 } 753 } 754 755 756 @("unittest.dependency") 757 @Tags(["dub", "ninja"]) 758 unittest { 759 with(immutable ReggaeSandbox()) { 760 writeFile("dub.sdl", ` 761 name "foo" 762 targetType "executable" 763 dependency "bar" path="bar" 764 `); 765 writeFile("source/app.d", q{ 766 void main() { 767 } 768 }); 769 writeFile("bar/dub.sdl", ` 770 name "bar" 771 `); 772 writeFile("bar/source/bar.d", q{ 773 module bar; 774 unittest { 775 assert(1 == 2); 776 } 777 }); 778 runReggae("-b", "ninja"); 779 ninja(["default", "ut"]).shouldExecuteOk; 780 shouldSucceed("ut"); 781 } 782 } 783 784 785 @("unittest.self") 786 @Tags(["dub", "ninja"]) 787 unittest { 788 with(immutable ReggaeSandbox()) { 789 writeFile("dub.sdl", ` 790 name "foo" 791 targetType "executable" 792 `); 793 writeFile("source/app.d", q{ 794 void main() { 795 } 796 797 unittest { assert(1 == 2); } 798 }); 799 runReggae("-b", "ninja"); 800 ninja(["default", "ut"]).shouldExecuteOk; 801 shouldFail("ut"); 802 } 803 } 804 805 806 @("subpackages") 807 @Tags(["dub", "ninja"]) 808 unittest { 809 with(immutable ReggaeSandbox()) { 810 writeFile("dub.json", ` 811 { 812 "name": "oops", 813 "targetType": "none", 814 "subPackages": [ 815 { 816 "name": "pkg1", 817 "targetType": "staticLibrary" 818 }, 819 { 820 "name": "pkg2", 821 "targetType": "executable", 822 "sourceFiles": ["main.d"], 823 "dependencies": { 824 "oops:pkg1": "*" 825 } 826 } 827 ], 828 "dependencies": { 829 "oops:pkg1": "*", 830 "oops:pkg2": "*" 831 } 832 } 833 `); 834 writeFile("main.d", q{ 835 void main() { 836 import oops; 837 import std.stdio; 838 writeln(3.twice); 839 } 840 }); 841 writeFile("source/oops.d", q{ 842 module oops; 843 int twice(int i) { return i * 2; } 844 }); 845 846 runReggae("-b", "ninja"); 847 ninja(["default", "ut"]).shouldExecuteOk; 848 shouldFail("ut"); 849 } 850 } 851 852 853 @("buildtype.release") 854 @Tags("dub", "ninja") 855 unittest { 856 857 import std..string: splitLines; 858 859 with(immutable ReggaeSandbox()) { 860 writeFile( 861 "dub.sdl", 862 [ 863 `name "foo"`, 864 `targetType "executable"`, 865 ], 866 ); 867 writeFile( 868 "source/app.d", 869 [ 870 q{void main() {}}, 871 ], 872 ); 873 874 runReggae("-b", "ninja", "--dub-build-type=release"); 875 const buildLines = ninja(["-v"]).shouldExecuteOk; 876 877 version(Windows) { 878 // args in response file 879 } else { 880 const firstLine = buildLines[0]; 881 "-release ".should.be in firstLine; 882 "-O".should.be in firstLine; 883 } 884 } 885 886 }