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