Skip to content

Commit cf5f57f

Browse files
yrashkJosé Valim
authored andcommitted
Implement Mix.Project.application values validation
Closes #685 Signed-off-by: José Valim <[email protected]>
1 parent fc03c8b commit cf5f57f

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

lib/mix/lib/mix/tasks/compile.app.ex

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,49 @@ defmodule Mix.Tasks.Compile.App do
8888
properties = Keyword.from_enum(properties)
8989
properties = Keyword.put properties, :description,
9090
to_char_list(properties[:description] || app)
91-
Keyword.put properties, :registered, (properties[:registered] || [])
91+
properties = Keyword.put properties, :registered, (properties[:registered] || [])
92+
validate_properties(properties)
93+
properties
94+
end
95+
96+
defp validate_properties(properties) do
97+
unless nil?(properties[:description]) or is_list(properties[:description]) do
98+
raise(Mix.Error, message: "Application description (:description) is not a character list (got #{inspect properties[:description]})")
99+
end
100+
unless nil?(properties[:id]) or is_list(properties[:id]) do
101+
raise(Mix.Error, message: "Application id (:id) is not a character list (got #{inspect properties[:id]} instead)")
102+
end
103+
unless nil?(properties[:vsn]) or is_list(properties[:vsn]) do
104+
raise(Mix.Error, message: "Application vsn (:vsn) is not a character list (got #{inspect properties[:vsn]} instead)")
105+
end
106+
unless nil?(properties[:modules]) or (is_list(properties[:modules]) and Enum.all?(properties[:modules], is_atom(&1))) do
107+
raise(Mix.Error, message: "Application modules (:modules) should be a list of atoms (got #{inspect properties[:modules]} instead)")
108+
end
109+
unless nil?(properties[:maxT]) or properties[:maxT] == :infinity or is_integer(properties[:maxT]) do
110+
raise(Mix.Error, message: "Application maximum time (:maxT) is not an integer or :infinity (got #{inspect properties[:maxT]} instead)")
111+
end
112+
unless nil?(properties[:registered]) or is_list(properties[:registered]) and (Enum.all?(properties[:registered], is_atom(&1))) do
113+
raise(Mix.Error, message: "Application registered processes (:registered) should be a list of atoms (got #{inspect properties[:registered]} instead)")
114+
end
115+
unless nil?(properties[:included_applications]) or (is_list(properties[:included_applications]) and Enum.all?(properties[:included_applications], is_atom(&1))) do
116+
raise(Mix.Error, message: "Application included applications (:included_applications) should be a list of atoms (got #{inspect properties[:included_applications]} instead)")
117+
end
118+
unless nil?(properties[:applications]) or (is_list(properties[:applications]) and Enum.all?(properties[:applications], is_atom(&1))) do
119+
raise(Mix.Error, message: "Application dependencies (:applications) should be a list of atoms (got #{inspect properties[:applications]} instead)")
120+
end
121+
unless nil?(properties[:env]) or (Keyword.keyword?(properties[:env])) do
122+
raise(Mix.Error, message: "Application dependencies (:env) should be a keyword list (got #{inspect properties[:env]} instead)")
123+
end
124+
unless nil?(properties[:mod]) do
125+
case properties[:mod] do
126+
[] -> :ok
127+
{module, _start_args} when is_atom(module) -> :ok
128+
other ->
129+
raise(Mix.Error, message: "Application callback module (:mod) should be either [] or {module, start_args} (got #{inspect properties[:mod]} instead)")
130+
end
131+
end
132+
unless nil?(properties[:start_phases]) or (Keyword.keyword?(properties[:start_phases])) do
133+
raise(Mix.Error, message: "Application start phases (:start_phases) should be a keyword list (got #{inspect properties[:start_phases]} instead)")
134+
end
92135
end
93136
end

lib/mix/test/mix/tasks/compile.app_test.exs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,25 @@ defmodule Mix.Tasks.Compile.AppTest do
1919
end
2020
end
2121

22+
defmodule InvalidProject do
23+
def project do
24+
[app: :invalid_project, version: "0.3.0"]
25+
end
26+
27+
def application do
28+
case Process.get(:error) do
29+
:modules -> [modules: :invalid]
30+
:maxT -> [maxT: :invalid]
31+
:registered -> [registered: ["invalid"]]
32+
:included_applications -> [included_applications: ["invalid"]]
33+
:applications -> [applications: ["invalid"]]
34+
:env -> [env: [:a]]
35+
:mod -> [mod: {Mod}]
36+
:start_phases -> [start_phases: [:invalid]]
37+
end
38+
end
39+
end
40+
2241
test "generates .app file when changes happen" do
2342
Mix.Project.push SimpleProject
2443

@@ -54,6 +73,24 @@ defmodule Mix.Tasks.Compile.AppTest do
5473
Mix.Project.pop
5574
end
5675

76+
test "application properties validation" do
77+
Mix.Project.push InvalidProject
78+
79+
in_fixture "no_mixfile", fn ->
80+
lc error inlist [:modules, :maxT, :registered, :included_applications,
81+
:applications, :env, :mod, :start_phases] do
82+
Process.put(:error, error)
83+
assert e = Mix.Error[] = catch_error(Mix.Tasks.Compile.App.run([]))
84+
assert e.message =~ %r/:#{error}/
85+
assert e.message =~ %r/#{inspect InvalidProject.application[error]}/
86+
end
87+
Process.delete(:error)
88+
end
89+
after
90+
purge [A, B, C]
91+
Mix.Project.pop
92+
end
93+
5794
test ".app contains description and registered (as required by systools)" do
5895
Mix.Project.push SimpleProject
5996

0 commit comments

Comments
 (0)