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