@@ -8,6 +8,10 @@ defmodule Gradient.ElixirFmtTest do
88
99 @ example_module_path "test/examples/simple_app.ex"
1010
11+ setup_all config do
12+ load_wrong_ret_error_examples ( config )
13+ end
14+
1115 test "try_highlight_in_context/2" do
1216 opts = [ forms: basic_erlang_forms ( ) ]
1317 expression = { :integer , 31 , 12 }
@@ -20,16 +24,110 @@ defmodule Gradient.ElixirFmtTest do
2024 assert res == expected
2125 end
2226
23- @ tag :skip
2427 describe "types format" do
25- test "wrong return type" do
26- { _tokens , ast } = load ( "/type/Elixir.WrongRet.beam" , "/type/wrong_ret.ex" )
27- opts = [ ]
28- errors = type_check_file ( ast , opts )
28+ test "return integer() instead atom()" , % { wrong_ret_errors: errors } do
29+ msg = format_error_to_binary ( errors . ret_wrong_atom )
30+
31+ assert String . contains? ( msg , "atom()" )
32+ assert String . contains? ( msg , "1" )
33+ end
34+
35+ test "return tuple() instead atom()" , % { wrong_ret_errors: errors } do
36+ msg = format_error_to_binary ( errors . ret_wrong_atom2 )
37+
38+ assert String . contains? ( msg , "atom()" )
39+ assert String . contains? ( msg , "{:ok, []}" )
40+ end
41+
42+ test "return map() instead atom()" , % { wrong_ret_errors: errors } do
43+ msg = format_error_to_binary ( errors . ret_wrong_atom3 )
44+
45+ assert String . contains? ( msg , "atom()" )
46+ assert String . contains? ( msg , "%{required(:a) => 1}" )
47+ end
48+
49+ test "return float() instead integer()" , % { wrong_ret_errors: errors } do
50+ msg = format_error_to_binary ( errors . ret_wrong_integer )
51+
52+ assert String . contains? ( msg , "integer()" )
53+ assert String . contains? ( msg , "1.0" )
54+ end
55+
56+ test "return atom() instead integer()" , % { wrong_ret_errors: errors } do
57+ msg = format_error_to_binary ( errors . ret_wrong_integer2 )
58+
59+ assert String . contains? ( msg , "integer()" )
60+ assert String . contains? ( msg , ":ok" )
61+ end
62+
63+ test "return boolean() instead integer()" , % { wrong_ret_errors: errors } do
64+ msg = format_error_to_binary ( errors . ret_wrong_integer3 )
65+
66+ assert String . contains? ( msg , "integer()" )
67+ assert String . contains? ( msg , "true" )
68+ end
69+
70+ test "return list() instead integer()" , % { wrong_ret_errors: errors } do
71+ msg = format_error_to_binary ( errors . ret_wrong_integer4 )
72+
73+ assert String . contains? ( msg , "integer()" )
74+ assert String . contains? ( msg , "nonempty_list()" )
75+ end
76+
77+ test "return integer() out of the range()" , % { wrong_ret_errors: errors } do
78+ msg = format_error_to_binary ( errors . ret_out_of_range_int )
79+
80+ assert String . contains? ( msg , "range(1, 10)" )
81+ assert String . contains? ( msg , "12" )
82+ end
83+
84+ test "return atom() instead boolean()" , % { wrong_ret_errors: errors } do
85+ msg = format_error_to_binary ( errors . ret_wrong_boolean )
86+
87+ assert String . contains? ( msg , "boolean()" )
88+ assert String . contains? ( msg , ":ok" )
89+ end
90+
91+ test "return binary() instead boolean()" , % { wrong_ret_errors: errors } do
92+ msg = format_error_to_binary ( errors . ret_wrong_boolean2 )
93+
94+ assert String . contains? ( msg , "boolean()" )
95+ assert String . contains? ( msg , "binary()" )
96+ end
97+
98+ test "return integer() instead boolean()" , % { wrong_ret_errors: errors } do
99+ msg = format_error_to_binary ( errors . ret_wrong_boolean3 )
100+
101+ assert String . contains? ( msg , "boolean()" )
102+ assert String . contains? ( msg , "1" )
103+ end
104+
105+ test "return keyword() instead boolean()" , % { wrong_ret_errors: errors } do
106+ msg = format_error_to_binary ( errors . ret_wrong_boolean4 )
107+
108+ assert String . contains? ( msg , "boolean()" )
109+ assert String . contains? ( msg , "nonempty_list()" )
110+ end
111+
112+ test "return list() instead keyword()" , % { wrong_ret_errors: errors } do
113+ msg = format_error_to_binary ( errors . ret_wrong_keyword )
114+
115+ assert String . contains? ( msg , "{atom(), any()}" )
116+ assert String . contains? ( msg , "1" )
117+ end
118+
119+ test "return tuple() instead map()" , % { wrong_ret_errors: errors } do
120+ msg = format_error_to_binary ( errors . ret_wrong_map )
29121
30- for e <- errors do
31- :io . put_chars ( e )
32- end
122+ assert String . contains? ( msg , "map()" )
123+ assert String . contains? ( msg , "{:a, 1, 2}" )
124+ end
125+
126+ test "return lambda with wrong returned type" , % { wrong_ret_errors: errors } do
127+ msg = format_error_to_binary ( errors . ret_wrong_fun )
128+
129+ assert String . contains? ( msg , "atom()" )
130+ assert String . contains? ( msg , "12" )
33131 end
34132 end
35133
@@ -44,17 +142,52 @@ defmodule Gradient.ElixirFmtTest do
44142 IO . puts ( res )
45143 end
46144
47- def basic_erlang_forms ( ) do
145+ # Helpers
146+
147+ defp basic_erlang_forms ( ) do
48148 [ { :attribute , 1 , :file , { @ example_module_path , 1 } } ]
49149 end
50150
51- def type_check_file ( ast , opts ) do
151+ defp type_check_file ( ast , opts ) do
52152 forms = AstSpecifier . specify ( ast )
53153 opts = Keyword . put ( opts , :return_errors , true )
54154 opts = Keyword . put ( opts , :forms , forms )
55155
56- forms
57- |> :gradualizer . type_check_forms ( opts )
58- |> Enum . map ( fn { _ , err } -> ElixirFmt . format_error ( err , opts ) end )
156+ errors =
157+ forms
158+ |> :gradualizer . type_check_forms ( opts )
159+ |> Enum . map ( & elem ( & 1 , 1 ) )
160+
161+ { errors , forms }
162+ end
163+
164+ defp format_error_to_binary ( error , opts \\ [ ] ) do
165+ error
166+ |> ElixirFmt . format_error ( opts )
167+ |> :erlang . iolist_to_binary ( )
168+ end
169+
170+ @ spec load_wrong_ret_error_examples ( map ( ) ) :: map ( )
171+ defp load_wrong_ret_error_examples ( config ) do
172+ { _tokens , ast } = load ( "/type/Elixir.WrongRet.beam" , "/type/wrong_ret.ex" )
173+
174+ { errors , forms } = type_check_file ( ast , [ ] )
175+ names = get_function_names_from_ast ( forms )
176+
177+ errors_map =
178+ Enum . zip ( names , errors )
179+ |> Map . new ( )
180+
181+ Map . put ( config , :wrong_ret_errors , errors_map )
182+ end
183+
184+ @ spec get_function_names_from_ast ( [ tuple ( ) ] ) :: [ atom ( ) ]
185+ def get_function_names_from_ast ( ast ) do
186+ ast
187+ |> Enum . filter ( fn
188+ { :function , _ , name , _ , _ } -> name != :__info__
189+ _ -> false
190+ end )
191+ |> Enum . map ( & elem ( & 1 , 2 ) )
59192 end
60193end
0 commit comments