Current section
Files
Jump to
Current section
Files
lib/credo/service/excoveralls_missing_coverage.ex
defmodule Credo.Service.ExcoverallsMissingCoverage do
@moduledoc """
Supports lookup of missing lines of test coverage from the
ExCoveralls JSON file, if it is present.
Note that the map is sparse, meaning it only contains source
lines which SHOULD have coverage, but DON'T.
"""
use GenServer
def start_link() do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init(_) do
new_state =
case slurp_coveralls_json() do
{:ok, data} -> parse_coveralls_json(data)
_ -> :no_data
end
{:ok, new_state}
end
def data_available?() do
GenServer.call(__MODULE__, :has_data)
end
def coverage_map() do
GenServer.call(__MODULE__, :coverage_map)
end
def handle_call(:has_data, _from, :no_data) do
{:reply, false, :no_data}
end
def handle_call(:has_data, _from, state) do
{:reply, true, state}
end
def handle_call(:coverage_map, _from, state) do
{:reply, state, state}
end
defp slurp_coveralls_json() do
case File.exists?("cover/excoveralls.json") do
false -> :no_file
_ -> read_coveralls_json()
end
end
defp read_coveralls_json() do
case File.read("cover/excoveralls.json") do
{:ok, bin} -> Jason.decode(bin)
e -> e
end
end
defp parse_coveralls_json(structure) do
case Map.fetch(structure, "source_files") do
:error -> %{}
{:ok, c_items} -> items_into_map(c_items)
end
end
defp items_into_map(c_items) do
Enum.reduce(c_items, %{}, fn c_item, acc ->
case Map.fetch(c_item, "name") do
:error ->
acc
{:ok, name} ->
Map.put(
acc,
name,
map_code_lines(c_item)
)
end
end)
end
defp map_code_lines(c_item) do
case Map.fetch(c_item, "coverage") do
:error -> %{}
{:ok, l} -> index_and_map_code_lines(l)
end
end
defp index_and_map_code_lines(lines) do
lines
|> Enum.with_index()
|> Enum.reduce(%{}, fn {e, idx}, acc ->
case e do
0 -> Map.put(acc, idx + 1, e)
_ -> acc
end
end)
end
end