Skip to content

Commit 06594f5

Browse files
authored
Fix --fail-above with --exclude (#11306)
And improve test coverage.
1 parent dc753d6 commit 06594f5

File tree

2 files changed

+102
-52
lines changed

2 files changed

+102
-52
lines changed

lib/mix/lib/mix/tasks/xref.ex

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -586,10 +586,16 @@ defmodule Mix.Tasks.Xref do
586586

587587
## Graph
588588

589-
defp excluded(opts) do
590-
opts
591-
|> Keyword.get_values(:exclude)
592-
|> Enum.flat_map(&[{&1, nil}, {&1, :compile}, {&1, :export}])
589+
defp exclude(file_references, []), do: file_references
590+
591+
defp exclude(file_references, excluded) do
592+
excluded_set = MapSet.new(excluded)
593+
594+
file_references
595+
|> Map.drop(excluded)
596+
|> Map.new(fn {key, list} ->
597+
{key, Enum.reject(list, fn {ref, _kind} -> MapSet.member?(excluded_set, ref) end)}
598+
end)
593599
end
594600

595601
defp label_filter(nil), do: :all
@@ -671,7 +677,7 @@ defmodule Mix.Tasks.Xref do
671677
end
672678

673679
defp write_graph(file_references, filter, opts) do
674-
excluded = excluded(opts)
680+
file_references = exclude(file_references, Keyword.get_values(opts, :exclude))
675681
sources = get_files(:source, opts, file_references)
676682
sinks = get_files(:sink, opts, file_references)
677683

@@ -683,7 +689,7 @@ defmodule Mix.Tasks.Xref do
683689
end
684690

685691
# Filter according to non direct label
686-
file_references = filter(file_references, excluded, filter)
692+
file_references = filter(file_references, filter)
687693

688694
# If a label is given, remove empty root nodes
689695
file_references =
@@ -700,13 +706,12 @@ defmodule Mix.Tasks.Xref do
700706
file_references
701707
|> Map.drop(sinks || [])
702708
|> Enum.map(&{elem(&1, 0), nil})
703-
|> Kernel.--(excluded)
704709
end
705710

706711
callback = fn {file, type} ->
707712
children = if opts[:only_nodes], do: [], else: Map.get(file_references, file, [])
708713
type = type && "(#{type})"
709-
{{file, type}, Enum.sort(children -- excluded)}
714+
{{file, type}, Enum.sort(children)}
710715
end
711716

712717
{found, count} =
@@ -755,18 +760,18 @@ defmodule Mix.Tasks.Xref do
755760
Enum.reduce(file_references, 0, fn {_, refs}, total -> total + length(refs) end)
756761
end
757762

758-
defp filter_fn(file_references, excluded, :compile_connected),
763+
defp filter_fn(file_references, :compile_connected),
759764
do: fn {key, type} ->
760-
type == :compile and match?([_ | _], (file_references[key] || []) -- excluded)
765+
type == :compile and match?([_ | _], file_references[key] || [])
761766
end
762767

763-
defp filter_fn(_file_references, _excluded, filter),
768+
defp filter_fn(_file_references, filter),
764769
do: fn {_key, type} -> type == filter end
765770

766-
defp filter(file_references, _excluded, :all), do: file_references
771+
defp filter(file_references, :all), do: file_references
767772

768-
defp filter(file_references, excluded, filter) do
769-
filter_fn = filter_fn(file_references, excluded, filter)
773+
defp filter(file_references, filter) do
774+
filter_fn = filter_fn(file_references, filter)
770775

771776
for {key, children} <- file_references,
772777
into: %{},

lib/mix/test/mix/tasks/xref_test.exs

Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,33 @@ defmodule Mix.Tasks.XrefTest do
449449
""")
450450
end
451451

452+
@abc_linear_files %{
453+
"lib/a.ex" => "defmodule A, do: def a, do: B.b()",
454+
"lib/b.ex" => "defmodule B, do: def b, do: C.c()",
455+
"lib/c.ex" => "defmodule C, do: def c, do: true"
456+
}
457+
458+
test "exclude one from linear case" do
459+
assert_graph(
460+
~w[--exclude lib/b.ex],
461+
"""
462+
lib/a.ex
463+
lib/c.ex
464+
""",
465+
files: @abc_linear_files
466+
)
467+
end
468+
469+
test "exclude one with source from linear case" do
470+
assert_graph(
471+
~w[--exclude lib/b.ex --source lib/a.ex],
472+
"""
473+
lib/a.ex
474+
""",
475+
files: @abc_linear_files
476+
)
477+
end
478+
452479
test "only nodes" do
453480
assert_graph(~w[--only-nodes], """
454481
lib/a.ex
@@ -507,6 +534,19 @@ defmodule Mix.Tasks.XrefTest do
507534
end
508535
end
509536

537+
test "exclude many with fail-above" do
538+
message = "Too many references (found: 1, permitted: 0)"
539+
540+
assert_raise Mix.Error, message, fn ->
541+
assert_graph(~w[--exclude lib/c.ex --exclude lib/b.ex --fail-above 0], """
542+
lib/a.ex
543+
lib/d.ex
544+
`-- lib/e.ex
545+
lib/e.ex
546+
""")
547+
end
548+
end
549+
510550
test "filter by compile direct label" do
511551
assert_graph(~w[--label compile --only-direct], """
512552
lib/a.ex
@@ -795,49 +835,54 @@ defmodule Mix.Tasks.XrefTest do
795835
end)
796836
end
797837

798-
defp assert_graph(opts \\ [], expected) do
799-
in_fixture("no_mixfile", fn ->
800-
File.write!("lib/a.ex", """
801-
defmodule A do
802-
def a, do: :ok
803-
B.b2()
804-
end
805-
""")
806-
807-
File.write!("lib/b.ex", """
808-
defmodule B do
809-
def b1, do: A.a() == C.c()
810-
def b2, do: :ok
811-
:e.e()
812-
end
813-
""")
814-
815-
File.write!("lib/c.ex", """
816-
defmodule C do
817-
def c, do: :ok
818-
:d.d()
819-
end
820-
""")
821-
822-
File.write!("lib/d.ex", """
823-
defmodule :d do
824-
def d, do: :ok
825-
def e, do: :e.e()
826-
end
827-
""")
838+
@default_files %{
839+
"lib/a.ex" => """
840+
defmodule A do
841+
def a, do: :ok
842+
B.b2()
843+
end
844+
""",
845+
"lib/b.ex" => """
846+
defmodule B do
847+
def b1, do: A.a() == C.c()
848+
def b2, do: :ok
849+
:e.e()
850+
end
851+
""",
852+
"lib/c.ex" => """
853+
defmodule C do
854+
def c, do: :ok
855+
:d.d()
856+
end
857+
""",
858+
"lib/d.ex" => """
859+
defmodule :d do
860+
def d, do: :ok
861+
def e, do: :e.e()
862+
end
863+
""",
864+
"lib/e.ex" => """
865+
defmodule :e do
866+
def e, do: :ok
867+
end
868+
"""
869+
}
828870

829-
File.write!("lib/e.ex", """
830-
defmodule :e do
831-
def e, do: :ok
832-
end
833-
""")
871+
defp assert_graph(opts \\ [], expected, params \\ []) do
872+
in_fixture("no_mixfile", fn ->
873+
nb_files =
874+
Enum.count(params[:files] || @default_files, fn {path, content} ->
875+
File.write!(path, content)
876+
end)
834877

835878
assert Mix.Task.run("xref", opts ++ ["graph"]) == :ok
879+
first_line = "Compiling #{nb_files} files (.ex)"
836880

837-
assert "Compiling 5 files (.ex)\nGenerated sample app\n" <> result =
838-
receive_until_no_messages([])
881+
assert [
882+
^first_line | ["Generated sample app" | result]
883+
] = receive_until_no_messages([]) |> String.split("\n")
839884

840-
assert normalize_graph_output(result) == expected
885+
assert normalize_graph_output(result |> Enum.join("\n")) == expected
841886
end)
842887
end
843888

0 commit comments

Comments
 (0)