Packages
excoveralls
0.8.1
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.1
0.17.0
0.16.1
0.16.0
0.15.3
0.15.2
0.15.1
0.15.0
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.4
0.13.3
0.13.2
0.13.1
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.6
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.5
0.7.4
0.7.3
0.7.2
0.7.1
0.7.0
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
Coverage report tool for Elixir with coveralls.io integration.
Current section
Files
Jump to
Current section
Files
lib/excoveralls/local.ex
defmodule ExCoveralls.Local do
@moduledoc """
Locally displays the result to screen.
"""
defmodule Count do
@moduledoc """
Stores count information for calculating coverage values.
"""
defstruct lines: 0, relevant: 0, covered: 0
end
@doc """
Provides an entry point for the module.
"""
def execute(stats, options \\ []) do
print_summary(stats, options)
if options[:detail] == true do
source(stats, options[:filter]) |> IO.puts
end
ExCoveralls.Stats.ensure_minimum_coverage(stats)
end
@doc """
Format the source code with color for the files that matches with
the specified patterns.
"""
def source(stats, _patterns = nil), do: source(stats)
def source(stats, _patterns = []), do: source(stats)
def source(stats, patterns) do
Enum.filter(stats, fn(stat) -> String.contains?(stat[:name], patterns) end) |> source
end
def source(stats) do
stats |> Enum.map(&format_source/1)
|> Enum.join("\n")
end
@doc """
Prints summary statistics for given coverage.
"""
def print_summary(stats, options \\ []) do
file_width = ExCoveralls.Settings.get_file_col_width
IO.puts "----------------"
IO.puts print_string("~-6s ~-#{file_width}s ~8s ~8s ~8s", ["COV", "FILE", "LINES", "RELEVANT", "MISSED"])
coverage(stats, options) |> IO.puts
IO.puts "----------------"
end
defp format_source(stat) do
"\n\e[33m--------#{stat[:name]}--------\e[m\n" <> colorize(stat)
end
defp colorize([{:name, _name}, {:source, source}, {:coverage, coverage}]) do
lines = String.split(source, "\n")
Enum.zip(lines, coverage)
|> Enum.map(&do_colorize/1)
|> Enum.join("\n")
end
defp do_colorize({line, coverage}) do
case coverage do
nil -> line
0 -> "\e[31m#{line}\e[m"
_ -> "\e[32m#{line}\e[m"
end
end
@doc """
Format the source coverage stats into string.
"""
def coverage(stats, options \\ []) do
count_info = Enum.map(stats, fn(stat) -> [stat, calculate_count(stat[:coverage])] end)
count_info = sort(count_info, options)
Enum.join(format_body(count_info), "\n") <> "\n" <> format_total(count_info)
end
defp sort(count_info, options) do
if options[:sort] do
sort_order = parse_sort_options(options)
flattened =
Enum.map(count_info, fn original ->
[stat, count] = original
%{
"cov" => get_coverage(count),
"file" => stat[:name],
"lines" => count.lines,
"relevant" => count.relevant,
"missed" => count.relevant - count.covered,
:_original => original
}
end)
sorted =
Enum.reduce(sort_order, flattened, fn {key, comparator}, acc ->
Enum.sort(acc, fn(x, y) ->
args = [x[key], y[key]]
apply(Kernel, comparator, args)
end)
end)
Enum.map(sorted, fn flattened -> flattened[:_original] end)
else
Enum.sort(count_info, fn([x, _], [y, _]) -> x[:name] <= y[:name] end)
end
end
defp parse_sort_options(options) do
sort_order =
options[:sort]
|> String.split(",")
|> Enum.reverse()
Enum.map(sort_order, fn sort_chunk ->
case String.split(sort_chunk, ":") do
[key, "asc"] -> {key, :<=}
[key, "desc"] -> {key, :>=}
[key] -> {key, :>=}
end
end)
end
defp format_body(info) do
Enum.map(info, &format_info/1)
end
defp format_info([stat, count]) do
coverage = get_coverage(count)
file_width = ExCoveralls.Settings.get_file_col_width
print_string("~5.1f% ~-#{file_width}s ~8w ~8w ~8w",
[coverage, stat[:name], count.lines, count.relevant, count.relevant - count.covered])
end
defp format_total(info) do
totals = Enum.reduce(info, %Count{}, fn([_, count], acc) -> append(count, acc) end)
coverage = get_coverage(totals)
print_string("[TOTAL] ~5.1f%", [coverage])
end
defp append(a, b) do
%Count{
lines: a.lines + b.lines,
relevant: a.relevant + b.relevant,
covered: a.covered + b.covered
}
end
defp get_coverage(count) do
case count.relevant do
0 -> default_coverage_value()
_ -> (count.covered / count.relevant) * 100
end
end
defp default_coverage_value do
options = ExCoveralls.Settings.get_coverage_options
case Map.fetch(options, "treat_no_relevant_lines_as_covered") do
{:ok, false} -> 0.0
_ -> 100.0
end
end
@doc """
Calucate count information from thhe coverage stats.
"""
def calculate_count(coverage) do
do_calculate_count(coverage, 0, 0, 0)
end
defp do_calculate_count([], lines, relevant, covered) do
%Count{lines: lines, relevant: relevant, covered: covered}
end
defp do_calculate_count([h|t], lines, relevant, covered) do
case h do
nil -> do_calculate_count(t, lines + 1, relevant, covered)
0 -> do_calculate_count(t, lines + 1, relevant + 1, covered)
n when is_number(n)
-> do_calculate_count(t, lines + 1, relevant + 1, covered + 1)
_ -> raise "Invalid data - #{h}"
end
end
defp print_string(format, params) do
char_list = :io_lib.format(format, params)
List.to_string(char_list)
end
end