1Code.require_file("../../test_helper.exs", __DIR__) 2 3defmodule Mix.Tasks.NewTest do 4 use MixTest.Case 5 6 test "new" do 7 in_tmp("new", fn -> 8 Mix.Tasks.New.run(["hello_world"]) 9 10 assert_file("hello_world/mix.exs", fn file -> 11 assert file =~ "app: :hello_world" 12 assert file =~ "version: \"0.1.0\"" 13 end) 14 15 assert_file("hello_world/README.md", ~r/# HelloWorld\n/) 16 assert_file("hello_world/.gitignore") 17 18 assert_file("hello_world/lib/hello_world.ex", ~r/defmodule HelloWorld do/) 19 assert_file("hello_world/test/test_helper.exs", ~r/ExUnit.start()/) 20 21 assert_file("hello_world/test/hello_world_test.exs", fn file -> 22 assert file =~ ~r/defmodule HelloWorldTest do/ 23 assert file =~ "assert HelloWorld.hello() == :world" 24 end) 25 26 assert_received {:mix_shell, :info, ["* creating mix.exs"]} 27 assert_received {:mix_shell, :info, ["* creating lib/hello_world.ex"]} 28 29 # Ensure formatting is setup and consistent. 30 File.cd!("hello_world", fn -> 31 Mix.Tasks.Format.run(["--check-formatted"]) 32 end) 33 end) 34 end 35 36 test "new with --sup" do 37 in_tmp("new sup", fn -> 38 Mix.Tasks.New.run(["hello_world", "--sup"]) 39 40 assert_file("hello_world/mix.exs", fn file -> 41 assert file =~ "app: :hello_world" 42 assert file =~ "version: \"0.1.0\"" 43 assert file =~ "mod: {HelloWorld.Application, []}" 44 end) 45 46 assert_file("hello_world/README.md", ~r/# HelloWorld\n/) 47 assert_file("hello_world/.gitignore") 48 49 assert_file("hello_world/lib/hello_world.ex", fn file -> 50 assert file =~ "defmodule HelloWorld do" 51 assert file =~ "def hello do" 52 end) 53 54 assert_file("hello_world/lib/hello_world/application.ex", fn file -> 55 assert file =~ "defmodule HelloWorld.Application do" 56 assert file =~ "use Application" 57 assert file =~ "@impl true" 58 assert file =~ "Supervisor.start_link(children, opts)" 59 end) 60 61 assert_file("hello_world/test/test_helper.exs", ~r/ExUnit.start()/) 62 assert_file("hello_world/test/hello_world_test.exs", ~r/defmodule HelloWorldTest do/) 63 64 assert_received {:mix_shell, :info, ["* creating mix.exs"]} 65 assert_received {:mix_shell, :info, ["* creating lib/hello_world.ex"]} 66 67 # Ensure formatting is setup and consistent. 68 File.cd!("hello_world", fn -> 69 Mix.Tasks.Format.run(["--check-formatted"]) 70 end) 71 end) 72 end 73 74 test "new with --module uses the module name also for naming the files in lib and test" do 75 in_tmp("new_with_module", fn -> 76 Mix.Tasks.New.run(["hello_world", "--module", "MyTestModule"]) 77 assert_file("hello_world/lib/my_test_module.ex", ~r/defmodule MyTestModule do/) 78 assert_file("hello_world/test/my_test_module_test.exs", ~r/defmodule MyTestModuleTest do/) 79 end) 80 end 81 82 test "new with --app" do 83 in_tmp("new app", fn -> 84 Mix.Tasks.New.run(["HELLO_WORLD", "--app", "hello_world"]) 85 86 assert_file("HELLO_WORLD/mix.exs", fn file -> 87 assert file =~ "app: :hello_world" 88 assert file =~ "version: \"0.1.0\"" 89 end) 90 91 assert_file("HELLO_WORLD/README.md", ~r/# HelloWorld\n/) 92 assert_file("HELLO_WORLD/.gitignore") 93 94 assert_file("HELLO_WORLD/lib/hello_world.ex", ~r/defmodule HelloWorld do/) 95 96 assert_file("HELLO_WORLD/test/test_helper.exs", ~r/ExUnit.start()/) 97 assert_file("HELLO_WORLD/test/hello_world_test.exs", ~r/defmodule HelloWorldTest do/) 98 99 assert_received {:mix_shell, :info, ["* creating mix.exs"]} 100 assert_received {:mix_shell, :info, ["* creating lib/hello_world.ex"]} 101 102 # Ensure formatting is setup and consistent. 103 File.cd!("HELLO_WORLD", fn -> 104 Mix.Tasks.Format.run(["--check-formatted"]) 105 end) 106 end) 107 end 108 109 test "new with --umbrella" do 110 in_tmp("new umbrella", fn -> 111 Mix.Tasks.New.run(["hello_world", "--umbrella"]) 112 113 assert_file("hello_world/mix.exs", fn file -> 114 assert file =~ "apps_path: \"apps\"" 115 end) 116 117 assert_file("hello_world/README.md", ~r/# HelloWorld\n/) 118 assert_file("hello_world/.gitignore") 119 120 assert_received {:mix_shell, :info, ["* creating mix.exs"]} 121 122 # Ensure formatting is setup and consistent. 123 File.cd!("hello_world", fn -> 124 Mix.Tasks.Format.run(["--check-formatted"]) 125 end) 126 end) 127 end 128 129 test "new inside umbrella" do 130 in_fixture("umbrella_dep/deps/umbrella", fn -> 131 File.cd!("apps", fn -> 132 Mix.Tasks.New.run(["hello_world"]) 133 134 assert_file("hello_world/mix.exs", fn file -> 135 assert file =~ "deps_path: \"../../deps\"" 136 assert file =~ "lockfile: \"../../mix.lock\"" 137 end) 138 139 # Ensure formatting is setup and consistent. 140 File.cd!("hello_world", fn -> 141 Mix.Tasks.Format.run(["--check-formatted"]) 142 end) 143 end) 144 end) 145 end 146 147 test "new with dot" do 148 in_tmp("new_with_dot", fn -> 149 Mix.Tasks.New.run(["."]) 150 assert_file("lib/new_with_dot.ex", ~r/defmodule NewWithDot do/) 151 end) 152 end 153 154 test "new with invalid args" do 155 in_tmp("new with an invalid application name", fn -> 156 assert_raise Mix.Error, 157 ~r"Application name must start with a lowercase ASCII letter", 158 fn -> 159 Mix.Tasks.New.run(["007invalid"]) 160 end 161 162 assert_raise Mix.Error, 163 ~r"Cannot use application name \"tools\" because it is already used by Erlang/OTP or Elixir", 164 fn -> 165 Mix.Tasks.New.run(["tools"]) 166 end 167 168 assert_raise Mix.Error, 169 ~r"followed by lowercase ASCII letters, numbers, or underscores", 170 fn -> 171 Mix.Tasks.New.run(["invAlid"]) 172 end 173 174 assert_raise Mix.Error, 175 ~r"followed by lowercase ASCII letters, numbers, or underscores", 176 fn -> 177 Mix.Tasks.New.run(["inválido"]) 178 end 179 end) 180 181 in_tmp("new with an invalid application name from the app option", fn -> 182 assert_raise Mix.Error, ~r"Application name must start with a lowercase ASCII letter", fn -> 183 Mix.Tasks.New.run(["valid", "--app", "007invalid"]) 184 end 185 end) 186 187 in_tmp("new with an invalid module name from the module options", fn -> 188 assert_raise Mix.Error, ~r"Module name must be a valid Elixir alias", fn -> 189 Mix.Tasks.New.run(["valid", "--module", "not.valid"]) 190 end 191 end) 192 193 in_tmp("new with an already taken module name from the module options", fn -> 194 assert_raise Mix.Error, ~r"Module name \w+ is already taken", fn -> 195 Mix.Tasks.New.run(["valid", "--module", "Mix"]) 196 end 197 end) 198 199 in_tmp("new without a specified path", fn -> 200 assert_raise Mix.Error, "Expected PATH to be given, please use \"mix new PATH\"", fn -> 201 Mix.Tasks.New.run([]) 202 end 203 end) 204 end 205 206 test "new with existent directory" do 207 in_tmp("new_with_existent_directory", fn -> 208 File.mkdir_p!("my_app") 209 send(self(), {:mix_shell_input, :yes?, false}) 210 211 assert_raise Mix.Error, "Please select another directory for installation", fn -> 212 Mix.Tasks.New.run(["my_app"]) 213 end 214 end) 215 end 216 217 defp assert_file(file) do 218 assert File.regular?(file), "Expected #{file} to exist, but does not" 219 end 220 221 defp assert_file(file, match) do 222 cond do 223 is_struct(match, Regex) -> 224 assert_file(file, &assert(&1 =~ match)) 225 226 is_function(match, 1) -> 227 assert_file(file) 228 match.(File.read!(file)) 229 end 230 end 231end 232