@@ -8,16 +8,16 @@ Kernel.ParallelCompiler.compile_to_path(files, path, return_diagnostics: true)
88
99defmodule Protocol.ConsolidationTest do
1010 use ExUnit.Case , async: true
11- alias Protocol.ConsolidationTest . { Sample , WithAny }
11+ alias Protocol.ConsolidationTest . { Sample , WithAny , NoImpl }
1212
1313 defimpl WithAny , for: Map do
14- def ok ( map ) do
14+ def ok ( map , _opts ) do
1515 { :ok , map }
1616 end
1717 end
1818
1919 defimpl WithAny , for: Any do
20- def ok ( any ) do
20+ def ok ( any , _opts ) do
2121 { :ok , any }
2222 end
2323 end
@@ -47,14 +47,24 @@ defmodule Protocol.ConsolidationTest do
4747 { :ok , binary } = Protocol . consolidate ( Sample , [ Any , ImplStruct ] )
4848 :code . load_binary ( Sample , ~c" protocol_test.exs" , binary )
4949
50- @ sample_binary binary
50+ defp sample_binary , do: unquote ( binary )
5151
5252 # Any should be moved to the end
5353 :code . purge ( WithAny )
5454 :code . delete ( WithAny )
5555 { :ok , binary } = Protocol . consolidate ( WithAny , [ Any , ImplStruct , Map ] )
5656 :code . load_binary ( WithAny , ~c" protocol_test.exs" , binary )
5757
58+ defp with_any_binary , do: unquote ( binary )
59+
60+ # No Any
61+ :code . purge ( NoImpl )
62+ :code . delete ( NoImpl )
63+ { :ok , binary } = Protocol . consolidate ( NoImpl , [ ] )
64+ :code . load_binary ( NoImpl , ~c" protocol_test.exs" , binary )
65+
66+ defp no_impl_binary , do: unquote ( binary )
67+
5868 test "consolidated?/1" do
5969 assert Protocol . consolidated? ( WithAny )
6070 refute Protocol . consolidated? ( Enumerable )
@@ -64,7 +74,7 @@ defmodule Protocol.ConsolidationTest do
6474 output =
6575 ExUnit.CaptureIO . capture_io ( :stderr , fn ->
6676 defimpl WithAny , for: Integer do
67- def ok ( _any ) , do: :ok
77+ def ok ( _any , _opts ) , do: :ok
6878 end
6979 end )
7080
@@ -86,7 +96,7 @@ defmodule Protocol.ConsolidationTest do
8696 :code . delete ( WithAny.Integer )
8797 end
8898
89- test "consolidated implementations without any" do
99+ test "consolidated implementations without fallback to any" do
90100 assert is_nil ( Sample . impl_for ( :foo ) )
91101 assert is_nil ( Sample . impl_for ( fn x -> x end ) )
92102 assert is_nil ( Sample . impl_for ( 1 ) )
@@ -106,8 +116,9 @@ defmodule Protocol.ConsolidationTest do
106116 assert Sample . impl_for ( % NoImplStruct { } ) == nil
107117 end
108118
109- test "consolidated implementations with any and tuple fallback " do
119+ test "consolidated implementations with fallback to any " do
110120 assert WithAny . impl_for ( % NoImplStruct { } ) == WithAny.Any
121+
111122 # Derived
112123 assert WithAny . impl_for ( % ImplStruct { } ) ==
113124 Protocol.ConsolidationTest.WithAny.Protocol.ConsolidationTest.ImplStruct
@@ -118,66 +129,120 @@ defmodule Protocol.ConsolidationTest do
118129 end
119130
120131 test "consolidation keeps docs" do
121- { :ok , { Sample , [ { ~c" Docs" , docs_bin } ] } } = :beam_lib . chunks ( @ sample_binary , [ ~c" Docs" ] )
132+ { :ok , { Sample , [ { ~c" Docs" , docs_bin } ] } } = :beam_lib . chunks ( sample_binary ( ) , [ ~c" Docs" ] )
122133 { :docs_v1 , _ , _ , _ , _ , _ , docs } = :erlang . binary_to_term ( docs_bin )
123134 ok_doc = List . keyfind ( docs , { :function , :ok , 1 } , 0 )
124135
125136 assert { { :function , :ok , 1 } , _ , [ "ok(term)" ] , % { "en" => "Ok" } , _ } = ok_doc
126137 end
127138
128- test "consolidation keeps chunks" do
129- deprecated = [ { { :ok , 1 } , "Reason" } ]
130- assert deprecated == Sample . __info__ ( :deprecated )
131-
132- { :ok , { Sample , [ { ~c" ExCk" , check_bin } ] } } = :beam_lib . chunks ( @ sample_binary , [ ~c" ExCk" ] )
133- assert { :elixir_checker_v1 , contents } = :erlang . binary_to_term ( check_bin )
134- assert % { { :ok , 1 } => % { deprecated: "Reason" , sig: _ } } = Map . new ( contents . exports )
135- end
136-
137139 @ tag :requires_source
138140 test "consolidation keeps source" do
139141 assert Sample . __info__ ( :compile ) [ :source ]
140142 end
141143
142144 test "consolidated keeps callbacks" do
143- { :ok , callbacks } = Code.Typespec . fetch_callbacks ( @ sample_binary )
145+ { :ok , callbacks } = Code.Typespec . fetch_callbacks ( sample_binary ( ) )
144146 assert callbacks != [ ]
145147 end
146148
147- test "consolidation errors on missing BEAM files" do
148- defprotocol NoBeam do
149- def example ( arg )
150- end
151-
152- assert Protocol . consolidate ( String , [ ] ) == { :error , :not_a_protocol }
153- assert Protocol . consolidate ( NoBeam , [ ] ) == { :error , :no_beam_info }
154- end
155-
156149 test "consolidation updates attributes" do
157150 assert Sample . __protocol__ ( :consolidated? )
158151 assert Sample . __protocol__ ( :impls ) == { :consolidated , [ ImplStruct ] }
159152 assert WithAny . __protocol__ ( :consolidated? )
160153 assert WithAny . __protocol__ ( :impls ) == { :consolidated , [ Any , Map , ImplStruct ] }
154+ assert NoImpl . __protocol__ ( :consolidated? )
155+ assert NoImpl . __protocol__ ( :impls ) == { :consolidated , [ ] }
161156 end
162157
163- test "consolidation extracts protocols" do
164- protos = Protocol . extract_protocols ( [ Application . app_dir ( :elixir , "ebin" ) ] )
165- assert Enumerable in protos
166- assert Inspect in protos
167- end
158+ describe "exports" do
159+ import Module.Types.Descr
160+ alias Module.Types.Of
161+
162+ defp exports ( binary ) do
163+ { :ok , { _ , [ { ~c" ExCk" , check_bin } ] } } = :beam_lib . chunks ( binary , [ ~c" ExCk" ] )
164+ assert { :elixir_checker_v1 , contents } = :erlang . binary_to_term ( check_bin )
165+ Map . new ( contents . exports )
166+ end
167+
168+ test "keeps deprecations" do
169+ deprecated = [ { { :ok , 1 } , "Reason" } ]
170+ assert deprecated == Sample . __info__ ( :deprecated )
171+
172+ assert % { { :ok , 1 } => % { deprecated: "Reason" , sig: _ } } = exports ( sample_binary ( ) )
173+ end
174+
175+ test "defines signatures without fallback to any" do
176+ exports = exports ( sample_binary ( ) )
177+
178+ assert % { { :impl_for , 1 } => % { sig: { :strong , domain , clauses } } } = exports
179+ assert domain == [ term ( ) ]
180+
181+ assert clauses == [
182+ { [ Of . impl ( ImplStruct ) ] , atom ( [ Sample.Protocol.ConsolidationTest.ImplStruct ] ) } ,
183+ { [ negation ( Of . impl ( ImplStruct ) ) ] , atom ( [ nil ] ) }
184+ ]
168185
169- test "consolidation extracts implementations with charlist path" do
170- protos =
171- Protocol . extract_impls ( Enumerable , [ to_charlist ( Application . app_dir ( :elixir , "ebin" ) ) ] )
186+ assert % { { :impl_for! , 1 } => % { sig: { :strong , domain , clauses } } } = exports
187+ assert domain == [ Of . impl ( ImplStruct ) ]
172188
173- assert List in protos
174- assert Function in protos
189+ assert clauses == [
190+ { [ Of . impl ( ImplStruct ) ] , atom ( [ Sample.Protocol.ConsolidationTest.ImplStruct ] ) }
191+ ]
192+
193+ assert % { { :ok , 1 } => % { sig: { :strong , nil , clauses } } } = exports
194+
195+ assert clauses == [
196+ { [ Of . impl ( ImplStruct ) ] , dynamic ( ) }
197+ ]
198+ end
199+
200+ test "defines signatures with fallback to any" do
201+ exports = exports ( with_any_binary ( ) )
202+
203+ assert % {
204+ { :impl_for , 1 } => % { sig: { :strong , domain , clauses } } ,
205+ { :impl_for! , 1 } => % { sig: { :strong , domain , clauses } }
206+ } = exports
207+
208+ assert domain == [ term ( ) ]
209+
210+ assert clauses == [
211+ { [ Of . impl ( Map ) ] , atom ( [ WithAny.Map ] ) } ,
212+ { [ Of . impl ( ImplStruct ) ] , atom ( [ WithAny.Protocol.ConsolidationTest.ImplStruct ] ) } ,
213+ { [ negation ( union ( Of . impl ( ImplStruct ) , Of . impl ( Map ) ) ) ] , atom ( [ WithAny.Any ] ) }
214+ ]
215+
216+ assert % { { :ok , 2 } => % { sig: { :strong , nil , clauses } } } = exports
217+
218+ assert clauses == [
219+ { [ term ( ) , term ( ) ] , dynamic ( ) }
220+ ]
221+ end
222+
223+ test "defines signatures without implementation" do
224+ exports = exports ( no_impl_binary ( ) )
225+
226+ assert % { { :impl_for , 1 } => % { sig: { :strong , domain , clauses } } } = exports
227+ assert domain == [ term ( ) ]
228+ assert clauses == [ { [ term ( ) ] , atom ( [ nil ] ) } ]
229+
230+ assert % { { :impl_for! , 1 } => % { sig: { :strong , domain , clauses } } } = exports
231+ assert domain == [ none ( ) ]
232+ assert clauses == [ { [ none ( ) ] , none ( ) } ]
233+
234+ assert % { { :ok , 1 } => % { sig: { :strong , nil , clauses } } } = exports
235+ assert clauses == [ { [ none ( ) ] , dynamic ( ) } ]
236+ end
175237 end
176238
177- test "consolidation extracts implementations with binary path" do
178- protos = Protocol . extract_impls ( Enumerable , [ Application . app_dir ( :elixir , "ebin" ) ] )
179- assert List in protos
180- assert Function in protos
239+ test "consolidation errors on missing BEAM files" do
240+ defprotocol NoBeam do
241+ def example ( arg )
242+ end
243+
244+ assert Protocol . consolidate ( String , [ ] ) == { :error , :not_a_protocol }
245+ assert Protocol . consolidate ( NoBeam , [ ] ) == { :error , :no_beam_info }
181246 end
182247
183248 test "protocol not implemented" do
@@ -191,4 +256,26 @@ defmodule Protocol.ConsolidationTest do
191256 sample . ok ( :foo )
192257 end
193258 end
259+
260+ describe "extraction" do
261+ test "protocols" do
262+ protos = Protocol . extract_protocols ( [ Application . app_dir ( :elixir , "ebin" ) ] )
263+ assert Enumerable in protos
264+ assert Inspect in protos
265+ end
266+
267+ test "implementations with charlist path" do
268+ protos =
269+ Protocol . extract_impls ( Enumerable , [ to_charlist ( Application . app_dir ( :elixir , "ebin" ) ) ] )
270+
271+ assert List in protos
272+ assert Function in protos
273+ end
274+
275+ test "implementations with binary path" do
276+ protos = Protocol . extract_impls ( Enumerable , [ Application . app_dir ( :elixir , "ebin" ) ] )
277+ assert List in protos
278+ assert Function in protos
279+ end
280+ end
194281end
0 commit comments