1Code.require_file("../../test_helper.exs", __DIR__) 2 3defmodule Mix.Tasks.DepsTest do 4 use MixTest.Case 5 6 defmodule DepsApp do 7 def project do 8 [ 9 app: :deps, 10 version: "0.1.0", 11 deps: [ 12 {:ok, "0.1.0", github: "elixir-lang/ok"}, 13 {:invalidvsn, "0.2.0", path: "deps/invalidvsn"}, 14 {:invalidapp, "0.1.0", path: "deps/invalidapp"}, 15 {:noappfile, "0.1.0", path: "deps/noappfile"}, 16 {:nosemver, "~> 0.1", path: "deps/nosemver"} 17 ] 18 ] 19 end 20 end 21 22 defmodule SuccessfulDepsApp do 23 def project do 24 [ 25 app: :sample, 26 version: "0.1.0", 27 deps: [ 28 {:ok, "0.1.0", path: "deps/ok"} 29 ] 30 ] 31 end 32 end 33 34 defmodule ReqDepsApp do 35 def project do 36 [ 37 app: :req_deps, 38 version: "0.1.0", 39 deps: [ 40 {:ok, ">= 2.0.0", path: "deps/ok"}, 41 {:noappfile, path: "deps/noappfile", app: false}, 42 {:apppath, path: "deps/noappfile", app: "../deps/ok/ebin/ok.app"} 43 ] 44 ] 45 end 46 end 47 48 defmodule MissingLocalDepsApp do 49 def project do 50 [ 51 app: :missing_local_deps, 52 version: "0.1.0", 53 deps: [ 54 {:ok, path: "missing/dep"} 55 ] 56 ] 57 end 58 end 59 60 ## deps 61 62 test "prints list of dependencies and their status" do 63 in_fixture("deps_status", fn -> 64 Mix.Project.push(DepsApp) 65 66 Mix.Tasks.Deps.run([]) 67 68 assert_received {:mix_shell, :info, ["* ok (https://github.com/elixir-lang/ok.git) (mix)"]} 69 msg = " the dependency is not available, run \"mix deps.get\"" 70 assert_received {:mix_shell, :info, [^msg]} 71 72 assert_received {:mix_shell, :info, ["* invalidvsn (deps/invalidvsn)"]} 73 assert_received {:mix_shell, :info, [" the app file contains an invalid version: :ok"]} 74 75 assert_received {:mix_shell, :info, ["* invalidapp (deps/invalidapp) (mix)"]} 76 msg = " the app file at \"_build/dev/lib/invalidapp/ebin/invalidapp.app\" is invalid" 77 assert_received {:mix_shell, :info, [^msg]} 78 79 assert_received {:mix_shell, :info, ["* noappfile (deps/noappfile)"]} 80 assert_received {:mix_shell, :info, [" could not find an app file at" <> _]} 81 82 assert_received {:mix_shell, :info, ["* nosemver (deps/nosemver)"]} 83 assert_received {:mix_shell, :info, [" the app file specified a non-Semantic" <> _]} 84 end) 85 end 86 87 test "prints list of dependencies and their status, including req mismatches and custom apps" do 88 in_fixture("deps_status", fn -> 89 Mix.Project.push(ReqDepsApp) 90 91 Mix.Tasks.Deps.run([]) 92 93 assert_received {:mix_shell, :info, ["* ok (deps/ok) (mix)"]} 94 msg = " the dependency does not match the requirement \">= 2.0.0\", got \"0.1.0\"" 95 assert_received {:mix_shell, :info, [^msg]} 96 97 assert_received {:mix_shell, :info, ["* apppath (deps/noappfile)"]} 98 refute_received {:mix_shell, :info, [" could not find app file at " <> _]} 99 100 assert_received {:mix_shell, :info, ["* noappfile (deps/noappfile)"]} 101 refute_received {:mix_shell, :info, [" could not find app file at " <> _]} 102 end) 103 end 104 105 test "prints misspelled dependency name hint" do 106 in_fixture("deps_status", fn -> 107 Mix.Project.push(DepsApp) 108 109 other_app_path = Path.join(Mix.Project.build_path(), "lib/noappfile/ebin/other_app.app") 110 File.mkdir_p!(Path.dirname(other_app_path)) 111 File.write!(other_app_path, "") 112 113 Mix.Tasks.Deps.run([]) 114 115 message = 116 " could not find an app file at \"_build/dev/lib/noappfile/ebin/noappfile.app\". " <> 117 "Another app file was found in the same directory " <> 118 "\"_build/dev/lib/noappfile/ebin/other_app.app\", " <> 119 "try changing the dependency name to :other_app" 120 121 assert_received {:mix_shell, :info, ["* noappfile (deps/noappfile)"]} 122 assert_received {:mix_shell, :info, [^message]} 123 end) 124 end 125 126 test "prints Elixir req mismatches" do 127 in_fixture("deps_status", fn -> 128 Mix.Project.push(ReqDepsApp) 129 130 File.write!("deps/ok/mix.exs", """ 131 defmodule Deps.OkApp do 132 use Mix.Project 133 134 def project do 135 [elixir: "~> 0.1.0", app: :ok, version: "2.0.0"] 136 end 137 end 138 """) 139 140 Mix.Tasks.Deps.Compile.run([:ok]) 141 142 msg = 143 "warning: the dependency :ok requires Elixir \"~> 0.1.0\" " <> 144 "but you are running on v#{System.version()}" 145 146 assert_received {:mix_shell, :error, [^msg]} 147 148 Mix.Tasks.Deps.Compile.run([]) 149 end) 150 end 151 152 test "prints list of dependencies and their lock status" do 153 in_fixture("deps_status", fn -> 154 Mix.Project.push(DepsApp) 155 156 File.cd!("deps/ok", fn -> 157 System.cmd("git", ~w[-c core.hooksPath='' init]) 158 end) 159 160 Mix.Tasks.Deps.run([]) 161 assert_received {:mix_shell, :info, ["* ok (https://github.com/elixir-lang/ok.git) (mix)"]} 162 163 msg = 164 " the dependency is not locked. To generate the \"mix.lock\" file run \"mix deps.get\"" 165 166 assert_received {:mix_shell, :info, [^msg]} 167 168 Mix.Dep.Lock.write(%{ok: {:git, "https://github.com/elixir-lang/ok.git", "abcdefghi", []}}) 169 Mix.Tasks.Deps.run([]) 170 171 assert_received {:mix_shell, :info, ["* ok (https://github.com/elixir-lang/ok.git) (mix)"]} 172 assert_received {:mix_shell, :info, [" locked at abcdefg"]} 173 174 msg = 175 " lock mismatch: the dependency is out of date. To fetch locked version run \"mix deps.get\"" 176 177 assert_received {:mix_shell, :info, [^msg]} 178 179 Mix.Dep.Lock.write(%{ 180 ok: {:git, "git://github.com/elixir-lang/another.git", "abcdefghi", []} 181 }) 182 183 Mix.Tasks.Deps.run([]) 184 185 assert_received {:mix_shell, :info, ["* ok (https://github.com/elixir-lang/ok.git) (mix)"]} 186 187 msg = 188 " lock outdated: the lock is outdated compared to the options in your mix.exs. To fetch locked version run \"mix deps.get\"" 189 190 assert_received {:mix_shell, :info, [^msg]} 191 end) 192 end 193 194 test "cleans and recompiles artifacts if --force is given" do 195 in_fixture("deps_status", fn -> 196 Mix.Project.push(SuccessfulDepsApp) 197 198 Mix.Tasks.Deps.Compile.run([]) 199 File.touch!("_build/dev/lib/ok/clean-me") 200 201 Mix.Tasks.Deps.Compile.run(["--force"]) 202 refute File.exists?("_build/dev/lib/ok/clean-me") 203 end) 204 end 205 206 test "doesn't compile any umbrella apps if --skip-umbrella-children is given" do 207 in_fixture("umbrella_dep/deps/umbrella", fn -> 208 Mix.Project.in_project(:umbrella, ".", fn _ -> 209 Mix.Tasks.Deps.Compile.run(["--skip-umbrella-children"]) 210 refute File.exists?("_build/dev/lib/foo/ebin") 211 refute File.exists?("_build/dev/lib/bar/ebin") 212 end) 213 end) 214 end 215 216 test "doesn't compile any path deps if --skip-local-deps is given" do 217 in_fixture("deps_status", fn -> 218 Mix.Project.push(SuccessfulDepsApp) 219 220 File.rm_rf!("_build/dev/lib/ok/ebin") 221 Mix.Tasks.Deps.Compile.run(["--skip-local-deps"]) 222 refute File.exists?("_build/dev/lib/ok/ebin") 223 end) 224 end 225 226 test "checks if local dependencies are available before compiling" do 227 Mix.Project.push(MissingLocalDepsApp) 228 229 error_message = 230 "Cannot compile dependency :ok because it isn't available, please ensure the dependency " <> 231 "is at \"missing/dep\"" 232 233 assert_raise Mix.Error, error_message, fn -> 234 Mix.Tasks.Deps.Compile.run([]) 235 end 236 end 237 238 ## deps.loadpaths 239 240 test "checks list of dependencies and their status with success" do 241 in_fixture("deps_status", fn -> 242 Mix.Project.push(SuccessfulDepsApp) 243 244 Mix.Tasks.Deps.Loadpaths.run([]) 245 end) 246 end 247 248 test "checks list of dependencies and their status on failure" do 249 in_fixture("deps_status", fn -> 250 Mix.Project.push(DepsApp) 251 252 assert_raise Mix.Error, fn -> 253 Mix.Tasks.Deps.Loadpaths.run([]) 254 end 255 256 assert_received {:mix_shell, :error, ["* ok (https://github.com/elixir-lang/ok.git)"]} 257 msg = " the dependency is not available, run \"mix deps.get\"" 258 assert_received {:mix_shell, :error, [^msg]} 259 260 assert_received {:mix_shell, :error, ["* invalidvsn (deps/invalidvsn)"]} 261 assert_received {:mix_shell, :error, [" the app file contains an invalid version: :ok"]} 262 263 assert_received {:mix_shell, :error, ["* invalidapp (deps/invalidapp)"]} 264 msg = " the app file at \"_build/dev/lib/invalidapp/ebin/invalidapp.app\" is invalid" 265 assert_received {:mix_shell, :error, [^msg]} 266 267 # This one is compiled automatically 268 refute_received {:mix_shell, :error, ["* noappfile (deps/noappfile)"]} 269 refute_received {:mix_shell, :error, [" could not find an app file at " <> _]} 270 end) 271 end 272 273 test "does not load deps with --no-load-deps" do 274 in_fixture("deps_status", fn -> 275 Mix.Project.push(SuccessfulDepsApp) 276 277 # Start from scratch! 278 File.rm_rf("_build") 279 280 Mix.Tasks.Deps.Compile.run([]) 281 Mix.Tasks.Deps.Loadpaths.run([]) 282 assert File.exists?("_build/dev/lib/ok/ebin/ok.app") 283 assert File.exists?("_build/dev/lib/ok/priv/sample") 284 285 Mix.Tasks.Compile.run([]) 286 assert to_charlist(Path.expand("_build/dev/lib/ok/ebin/")) in :code.get_path() 287 assert File.exists?("_build/dev/lib/sample/ebin/sample.app") 288 289 # Remove the deps without build_path 290 Mix.ProjectStack.post_config(deps: []) 291 Mix.State.clear_cache() 292 Mix.Project.pop() 293 Mix.Project.push(SuccessfulDepsApp) 294 Code.delete_path("_build/dev/lib/ok/ebin") 295 296 Mix.Tasks.Deps.Loadpaths.run(["--no-load-deps"]) 297 refute to_charlist(Path.expand("_build/dev/lib/ok/ebin/")) in :code.get_path() 298 assert File.exists?("_build/dev/lib/ok/ebin/ok.app") 299 assert File.exists?("_build/dev/lib/sample/ebin/sample.app") 300 end) 301 end 302 303 ## deps.unlock 304 305 test "unlocks all deps", context do 306 in_tmp(context.test, fn -> 307 Mix.Project.push(DepsApp) 308 309 Mix.Dep.Lock.write(%{git_repo: "abcdef"}) 310 assert Mix.Dep.Lock.read() == %{git_repo: "abcdef"} 311 Mix.Tasks.Deps.Unlock.run(["--all"]) 312 assert Mix.Dep.Lock.read() == %{} 313 end) 314 end 315 316 test "checks lock file has unused deps with --check-unused", context do 317 in_tmp(context.test, fn -> 318 Mix.Project.push(DepsApp) 319 320 Mix.Dep.Lock.write(%{whatever: "0.2.0", something_else: "1.2.3", ok: "0.1.0"}) 321 assert Mix.Dep.Lock.read() == %{whatever: "0.2.0", something_else: "1.2.3", ok: "0.1.0"} 322 323 error = """ 324 Unused dependencies in mix.lock file: 325 326 * :something_else 327 * :whatever 328 """ 329 330 assert_raise Mix.Error, error, fn -> 331 Mix.Tasks.Deps.Unlock.run(["--check-unused"]) 332 end 333 334 assert Mix.Dep.Lock.read() == %{whatever: "0.2.0", something_else: "1.2.3", ok: "0.1.0"} 335 336 Mix.Tasks.Deps.Unlock.run(["--unused"]) 337 Mix.Tasks.Deps.Unlock.run(["--check-unused"]) 338 assert Mix.Dep.Lock.read() == %{ok: "0.1.0"} 339 end) 340 end 341 342 test "unlocks unused deps", context do 343 in_tmp(context.test, fn -> 344 Mix.Project.push(DepsApp) 345 346 Mix.Dep.Lock.write(%{whatever: "abcdef", ok: "abcdef"}) 347 assert Mix.Dep.Lock.read() == %{whatever: "abcdef", ok: "abcdef"} 348 Mix.Tasks.Deps.Unlock.run(["--unused"]) 349 assert Mix.Dep.Lock.read() == %{ok: "abcdef"} 350 351 output = """ 352 Unlocked deps: 353 * whatever 354 """ 355 356 assert_received {:mix_shell, :info, [^output]} 357 end) 358 end 359 360 test "unlocking a dep that is not locked is a no-op", context do 361 in_tmp(context.test, fn -> 362 Mix.Project.push(DepsApp) 363 Mix.Tasks.Deps.Unlock.run(["unlocked_dep"]) 364 365 assert_received {:mix_shell, :error, ["warning: unlocked_dep dependency is not locked"]} 366 refute_received {:mix_shell, :info, [_]} 367 end) 368 end 369 370 test "unlocks specific deps", context do 371 in_tmp(context.test, fn -> 372 Mix.Project.push(DepsApp) 373 374 Mix.Dep.Lock.write(%{git_repo: "abcdef", another: "hash"}) 375 Mix.Tasks.Deps.Unlock.run(["git_repo", "unknown"]) 376 assert Mix.Dep.Lock.read() == %{another: "hash"} 377 error = "warning: unknown dependency is not locked" 378 assert_received {:mix_shell, :error, [^error]} 379 380 output = """ 381 Unlocked deps: 382 * git_repo 383 """ 384 385 assert_received {:mix_shell, :info, [^output]} 386 end) 387 end 388 389 test "unlocks filtered deps", context do 390 in_tmp(context.test, fn -> 391 Mix.Project.push(DepsApp) 392 393 Mix.Dep.Lock.write(%{git_repo: "abcdef", another: "hash", another_one: "hash"}) 394 Mix.Tasks.Deps.Unlock.run(["--filter", "another"]) 395 assert Mix.Dep.Lock.read() == %{git_repo: "abcdef"} 396 397 output = """ 398 Unlocked deps: 399 * another 400 * another_one 401 """ 402 403 assert_received {:mix_shell, :info, [^output]} 404 end) 405 end 406 407 test "fails with message on missing dependencies" do 408 Mix.Project.push(DepsApp) 409 410 assert_raise Mix.Error, ~r/"mix deps\.unlock" expects dependencies as arguments/, fn -> 411 Mix.Tasks.Deps.Unlock.run([]) 412 end 413 end 414 415 ## Deps environment 416 417 defmodule DepsEnvApp do 418 def project do 419 [ 420 app: :raw_sample, 421 version: "0.1.0", 422 deps: [ 423 {:raw_repo, "0.1.0", path: "custom/raw_repo"} 424 ] 425 ] 426 end 427 end 428 429 defmodule CustomDepsEnvApp do 430 def project do 431 [ 432 app: :raw_sample, 433 version: "0.1.0", 434 deps: [ 435 {:raw_repo, "0.1.0", path: "custom/raw_repo", env: :dev} 436 ] 437 ] 438 end 439 end 440 441 test "sets deps env to prod by default" do 442 in_fixture("deps_status", fn -> 443 Mix.Project.push(DepsEnvApp) 444 445 Mix.Tasks.Deps.Update.run(["--all"]) 446 assert_received {:mix_shell, :info, [":raw_repo env is prod"]} 447 end) 448 end 449 450 test "can customize environment" do 451 in_fixture("deps_status", fn -> 452 Mix.Project.push(CustomDepsEnvApp) 453 454 Mix.Tasks.Deps.Update.run(["--all"]) 455 assert_received {:mix_shell, :info, [":raw_repo env is dev"]} 456 end) 457 end 458 459 ## Nested dependencies 460 461 defmodule ConflictDepsApp do 462 def project do 463 [ 464 app: :raw_sample, 465 version: "0.1.0", 466 deps: [ 467 {:git_repo, "0.1.0", path: "custom/raw_repo"}, 468 {:bad_deps_repo, "0.1.0", path: "custom/bad_deps_repo"} 469 ] 470 ] 471 end 472 end 473 474 defmodule DivergedDepsApp do 475 def project do 476 [ 477 app: :raw_sample, 478 version: "0.1.0", 479 deps: [ 480 {:deps_repo, "0.1.0", path: "custom/deps_repo"}, 481 {:bad_deps_repo, "0.1.0", path: "custom/bad_deps_repo"} 482 ] 483 ] 484 end 485 end 486 487 defmodule ConvergedDepsApp do 488 def project do 489 [ 490 app: :raw_sample, 491 version: "0.1.0", 492 deps: [ 493 {:deps_repo, "0.1.0", path: "custom/deps_repo"}, 494 {:git_repo, ">= 0.1.0", git: MixTest.Case.fixture_path("git_repo")} 495 ] 496 ] 497 end 498 end 499 500 defmodule OverriddenDepsApp do 501 def project do 502 [ 503 app: :raw_sample, 504 version: "0.1.0", 505 deps: [ 506 {:bad_deps_repo, "0.1.0", path: "custom/bad_deps_repo"}, 507 {:git_repo, "0.1.0", git: MixTest.Case.fixture_path("git_repo"), override: true} 508 ] 509 ] 510 end 511 end 512 513 defmodule NonOverriddenDepsApp do 514 def project do 515 [ 516 app: :raw_sample, 517 version: "0.1.0", 518 deps: [ 519 {:bad_deps_repo, "0.1.0", path: "custom/bad_deps_repo"}, 520 {:git_repo, "0.1.0", git: MixTest.Case.fixture_path("git_repo")} 521 ] 522 ] 523 end 524 end 525 526 test "fails on missing dependencies" do 527 in_fixture("deps_status", fn -> 528 Mix.Project.push(SuccessfulDepsApp) 529 530 assert_raise Mix.Error, ~r/Unknown dependency invalid for environment dev/, fn -> 531 Mix.Tasks.Deps.Update.run(["invalid"]) 532 end 533 end) 534 end 535 536 @overriding_msg " the dependency git_repo in mix.exs is overriding a child dependency" 537 538 test "fails on diverged dependencies on get/update" do 539 in_fixture("deps_status", fn -> 540 Mix.Project.push(ConflictDepsApp) 541 542 assert_raise Mix.Error, fn -> 543 Mix.Tasks.Deps.Loadpaths.run([]) 544 end 545 546 assert_received {:mix_shell, :error, [@overriding_msg <> _]} 547 548 assert_raise Mix.Error, fn -> 549 Mix.Tasks.Deps.Get.run([]) 550 end 551 552 assert_received {:mix_shell, :error, [@overriding_msg <> _]} 553 554 assert_raise Mix.Error, fn -> 555 Mix.Tasks.Deps.Update.run(["--all"]) 556 end 557 558 assert_received {:mix_shell, :error, [@overriding_msg <> _]} 559 end) 560 end 561 562 test "fails on diverged dependencies on check" do 563 in_fixture("deps_status", fn -> 564 Mix.Project.push(DivergedDepsApp) 565 566 assert_raise Mix.Error, fn -> 567 Mix.Tasks.Deps.Loadpaths.run([]) 568 end 569 570 assert_received {:mix_shell, :error, [" different specs were given" <> _ = received_msg]} 571 assert received_msg =~ "In custom/deps_repo/mix.exs:" 572 573 assert received_msg =~ 574 "{:git_repo, \"0.1.0\", [env: :prod, git: #{inspect(fixture_path("git_repo"))}]}" 575 end) 576 end 577 578 test "fails on diverged dependencies by requirement" do 579 in_fixture("deps_status", fn -> 580 Mix.Project.push(ConvergedDepsApp) 581 582 File.write!("custom/deps_repo/mix.exs", """ 583 defmodule DepsRepo do 584 use Mix.Project 585 586 def project do 587 [ 588 app: :deps_repo, 589 version: "0.1.0", 590 deps: [ 591 {:git_repo, "0.2.0", git: MixTest.Case.fixture_path("git_repo")} 592 ] 593 ] 594 end 595 end 596 """) 597 598 assert_raise Mix.Error, fn -> 599 Mix.Tasks.Deps.Get.run([]) 600 Mix.Tasks.Deps.Loadpaths.run([]) 601 end 602 603 assert_received {:mix_shell, :error, [" the dependency git_repo 0.1.0" <> _ = msg]} 604 assert msg =~ "In custom/deps_repo/mix.exs:" 605 606 assert msg =~ 607 "{:git_repo, \"0.2.0\", [env: :prod, git: #{inspect(fixture_path("git_repo"))}]}" 608 end) 609 end 610 611 @overriding_msg " the dependency git_repo in mix.exs is overriding" 612 613 test "fails on diverged dependencies even when optional" do 614 in_fixture("deps_status", fn -> 615 Mix.Project.push(ConvergedDepsApp) 616 617 File.write!("custom/deps_repo/mix.exs", """ 618 defmodule DepsRepo do 619 use Mix.Project 620 621 def project do 622 [ 623 app: :deps_repo, 624 version: "0.1.0", 625 deps: [ 626 {:git_repo, git: MixTest.Case.fixture_path("bad_git_repo"), branch: "omg"} 627 ] 628 ] 629 end 630 end 631 """) 632 633 assert_raise Mix.Error, fn -> 634 Mix.Tasks.Deps.Get.run([]) 635 Mix.Tasks.Deps.Loadpaths.run([]) 636 end 637 638 assert_received {:mix_shell, :error, [@overriding_msg <> _]} 639 end) 640 end 641 642 test "works with converged dependencies" do 643 in_fixture("deps_status", fn -> 644 Mix.Project.push(ConvergedDepsApp) 645 646 Mix.Tasks.Deps.Get.run([]) 647 message = "* Getting git_repo (#{fixture_path("git_repo")})" 648 assert_received {:mix_shell, :info, [^message]} 649 650 # Make sure retriever uses converger, 651 # so the message appears just once 652 refute_received {:mix_shell, :info, [^message]} 653 654 Mix.Task.clear() 655 Mix.Tasks.Deps.Update.run(["--all"]) 656 657 message = "* Updating git_repo (#{fixture_path("git_repo")})" 658 assert_received {:mix_shell, :info, [^message]} 659 end) 660 after 661 purge([GitRepo, GitRepo.MixProject]) 662 end 663 664 test "does not check dependencies if --no-deps-check is provided" do 665 in_fixture("deps_status", fn -> 666 Mix.Project.push(SuccessfulDepsApp) 667 668 Mix.Tasks.Deps.Get.run([]) 669 File.rm_rf!("deps/ok") 670 671 assert_raise Mix.Error, fn -> 672 Mix.Tasks.Compile.run([]) 673 end 674 675 Mix.Tasks.Compile.run(["--no-deps-check"]) 676 end) 677 end 678 679 test "works with overridden dependencies" do 680 in_fixture("deps_status", fn -> 681 Mix.Project.push(OverriddenDepsApp) 682 683 Mix.Tasks.Deps.Get.run([]) 684 message = "* Getting git_repo (#{fixture_path("git_repo")})" 685 assert_received {:mix_shell, :info, [^message]} 686 687 # Make sure retriever uses converger, 688 # so the message appears just once 689 refute_received {:mix_shell, :info, [^message]} 690 691 Mix.Task.clear() 692 Mix.Tasks.Deps.Update.run(["--all"]) 693 694 message = "* Updating git_repo (#{fixture_path("git_repo")})" 695 assert_received {:mix_shell, :info, [^message]} 696 end) 697 after 698 purge([GitRepo, GitRepo.MixProject]) 699 end 700 701 test "converged dependencies errors if not overriding" do 702 in_fixture("deps_status", fn -> 703 Mix.Project.push(NonOverriddenDepsApp) 704 705 assert_raise Mix.Error, fn -> 706 Mix.Tasks.Deps.Loadpaths.run([]) 707 end 708 709 receive do 710 {:mix_shell, :error, [" the dependency git_repo in mix.exs" <> _ = msg]} -> 711 assert msg =~ "In mix.exs:" 712 713 assert msg =~ 714 "{:git_repo, \"0.1.0\", [env: :prod, git: #{inspect(fixture_path("git_repo"))}]}" 715 after 716 0 -> flunk("expected overriding error message") 717 end 718 end) 719 after 720 purge([GitRepo, GitRepo.MixProject]) 721 end 722 723 test "checks if dependencies are using old Elixir version" do 724 in_fixture("deps_status", fn -> 725 Mix.Project.push(SuccessfulDepsApp) 726 727 Mix.Tasks.Deps.Compile.run([]) 728 Mix.Tasks.Deps.Loadpaths.run([]) 729 730 File.mkdir_p!("_build/dev/lib/ok/ebin") 731 File.mkdir_p!("_build/dev/lib/ok/.mix") 732 manifest_data = :erlang.term_to_binary({:v1, "the_future", :scm}) 733 File.write!("_build/dev/lib/ok/.mix/compile.elixir_scm", manifest_data) 734 Mix.Task.clear() 735 736 msg = 737 " the dependency was built with an out-of-date Elixir version, run \"mix deps.compile\"" 738 739 Mix.Tasks.Deps.run([]) 740 assert_received {:mix_shell, :info, [^msg]} 741 742 # deps.loadpaths will automatically recompile it 743 Mix.Tasks.Deps.Loadpaths.run([]) 744 745 Mix.Tasks.Deps.run([]) 746 refute_received {:mix_shell, :info, [^msg]} 747 end) 748 end 749 750 test "checks if dependencies are using old scm version" do 751 in_fixture("deps_status", fn -> 752 Mix.Project.push(SuccessfulDepsApp) 753 754 Mix.Tasks.Deps.Compile.run([]) 755 Mix.Tasks.Deps.Loadpaths.run([]) 756 757 File.mkdir_p!("_build/dev/lib/ok/ebin") 758 File.mkdir_p!("_build/dev/lib/ok/.mix") 759 760 manifest_data = 761 :erlang.term_to_binary({1, {System.version(), :erlang.system_info(:otp_release)}, :scm}) 762 763 File.write!("_build/dev/lib/ok/.mix/compile.elixir_scm", manifest_data) 764 Mix.Task.clear() 765 766 msg = " the dependency was built with another SCM, run \"mix deps.compile\"" 767 Mix.Tasks.Deps.run([]) 768 assert_received {:mix_shell, :info, [^msg]} 769 770 # deps.loadpaths will automatically recompile it 771 Mix.Tasks.Deps.Loadpaths.run([]) 772 773 Mix.Tasks.Deps.run([]) 774 refute_received {:mix_shell, :info, [^msg]} 775 end) 776 end 777 778 defmodule NonCompilingDeps do 779 def project do 780 [ 781 app: :raw_sample, 782 version: "0.1.0", 783 deps: [ 784 {:git_repo, "0.1.0", git: MixTest.Case.fixture_path("git_repo"), compile: false} 785 ] 786 ] 787 end 788 end 789 790 test "does not compile deps that have explicit option" do 791 in_fixture("deps_status", fn -> 792 Mix.Project.push(NonCompilingDeps) 793 794 Mix.Tasks.Deps.Compile.run([]) 795 refute_received {:mix_shell, :info, ["==> git_repo"]} 796 end) 797 end 798 799 defmodule DupDeps do 800 def project do 801 [ 802 app: :raw_sample, 803 version: "0.1.0", 804 deps: [ 805 # Simulate dependencies gathered together from umbrella 806 {:ok, "0.1.0", path: "deps/ok"}, 807 {:ok, "0.1.0", path: "deps/ok"} 808 ] 809 ] 810 end 811 end 812 813 test "warns and converges duplicated deps at the same level" do 814 in_fixture("deps_status", fn -> 815 Mix.Project.push(DupDeps) 816 817 Mix.Tasks.Deps.run([]) 818 819 msg = 820 "warning: the dependency :ok is duplicated at the top level, please remove one of them" 821 822 assert_received {:mix_shell, :error, [^msg]} 823 824 msg = "* ok 0.1.0 (deps/ok) (mix)" 825 assert_received {:mix_shell, :info, [^msg]} 826 refute_received {:mix_shell, :info, [^msg]} 827 end) 828 end 829 830 ## deps.clean 831 832 defmodule CleanDepsApp do 833 def project do 834 [ 835 app: :raw_sample, 836 version: "0.1.0", 837 deps: [ 838 {:git_repo, ">= 0.1.0", git: MixTest.Case.fixture_path("git_repo")}, 839 {:ok, ">= 2.0.0", path: "deps/ok"} 840 ] 841 ] 842 end 843 end 844 845 test "cleans dependencies" do 846 in_fixture("deps_status", fn -> 847 Mix.Project.push(CleanDepsApp) 848 849 File.mkdir_p!("_build/dev/lib/raw_sample") 850 File.mkdir_p!("_build/dev/lib/git_repo") 851 File.mkdir_p!("_build/test/lib/git_repo") 852 File.mkdir_p!("_build/dev/lib/ok") 853 File.mkdir_p!("_build/test/lib/ok") 854 855 message = 856 "\"mix deps.clean\" expects dependencies as arguments or " <> 857 "an option indicating which dependencies to clean. " <> 858 "The --all option will clean all dependencies while " <> 859 "the --unused option cleans unused dependencies" 860 861 assert_raise Mix.Error, message, fn -> 862 Mix.Tasks.Deps.Clean.run([]) 863 end 864 865 Mix.Tasks.Deps.Clean.run(["--only", "dev", "--all"]) 866 refute File.exists?("_build/dev/lib/git_repo") 867 refute File.exists?("_build/dev/lib/ok") 868 assert File.exists?("_build/test/lib/git_repo") 869 assert File.exists?("_build/dev/lib/raw_sample") 870 871 Mix.Tasks.Deps.Clean.run(["--all"]) 872 refute File.exists?("_build/dev/lib/git_repo") 873 refute File.exists?("_build/test/lib/git_repo") 874 assert File.exists?("_build/dev/lib/raw_sample") 875 end) 876 end 877 878 test "cleans unused dependencies" do 879 in_fixture("deps_status", fn -> 880 Mix.Project.push(CleanDepsApp) 881 882 File.mkdir_p!("_build/dev/lib/raw_sample") 883 File.mkdir_p!("deps/git_repo") 884 File.mkdir_p!("_build/dev/lib/git_repo") 885 File.mkdir_p!("deps/git_repo_unused") 886 File.mkdir_p!("_build/dev/lib/git_repo_unused") 887 888 Mix.Tasks.Deps.Clean.run(["--unused"]) 889 assert File.exists?("deps/git_repo") 890 assert File.exists?("_build/dev/lib/git_repo") 891 refute File.exists?("deps/git_repo_unused") 892 refute File.exists?("_build/dev/lib/git_repo_unused") 893 assert File.exists?("_build/dev/lib/raw_sample") 894 end) 895 end 896 897 test "cleans dependencies build" do 898 in_fixture("deps_status", fn -> 899 Mix.Project.push(CleanDepsApp) 900 901 File.mkdir_p!("deps/raw_sample") 902 File.mkdir_p!("_build/dev/lib/raw_sample") 903 904 Mix.Tasks.Deps.Clean.run(["raw_sample", "--build"]) 905 assert File.exists?("deps/raw_sample") 906 refute File.exists?("_build/dev/lib/raw_sample") 907 end) 908 end 909 910 test "warns on invalid path on clean dependencies" do 911 in_fixture("deps_status", fn -> 912 Mix.Project.push(CleanDepsApp) 913 914 File.mkdir_p!("deps/raw_sample") 915 File.mkdir_p!("_build/dev/lib/raw_sample") 916 917 Mix.Tasks.Deps.Clean.run(["raw_sample_with_a_typo"]) 918 assert File.exists?("deps/raw_sample") 919 920 msg = "warning: the dependency raw_sample_with_a_typo is not present in the build directory" 921 assert_received {:mix_shell, :error, [^msg]} 922 end) 923 end 924 925 test "does not remove dependency source when using :path" do 926 in_fixture("deps_status", fn -> 927 Mix.Project.push(CleanDepsApp) 928 929 assert File.exists?("deps/ok") 930 931 Mix.Tasks.Deps.Clean.run(["raw_sample", "--all"]) 932 refute File.exists?("_build/dev/lib/ok") 933 refute File.exists?("_build/test/lib/ok") 934 assert File.exists?("deps/ok") 935 end) 936 end 937end 938