|
| 1 | +# SPDX-FileCopyrightText: Sudo Apt Holdings LLC |
| 2 | +# SPDX-License-Identifier: Apache-2.0 |
| 3 | +defmodule SpdxHeadersTest do |
| 4 | + @moduledoc """ |
| 5 | + Every source file this project wrote carries a copyright line and a licence line. |
| 6 | +
|
| 7 | + These are the OpenSSF Best Practices criteria `copyright_per_file` and `license_per_file`, both |
| 8 | + MUST at the gold level. They are held here rather than checked by hand for the reason every |
| 9 | + population rule in this tree is held by a test: the count only stays right if adding a file that |
| 10 | + breaks it fails something. When this test was written the tree was five files short of both |
| 11 | + criteria, and none of the five was noticed by anyone reading the tree. |
| 12 | +
|
| 13 | + The population is `git ls-files`, so a new source file is in scope by existing. The comment |
| 14 | + syntax differs by language and the marker does not: SPDX defines the tag, not the comment it |
| 15 | + sits in, which is why this checks for the tag rather than for a particular line. |
| 16 | + """ |
| 17 | + use ExUnit.Case, async: true |
| 18 | + |
| 19 | + @copyright "SPDX-FileCopyrightText" |
| 20 | + @license "SPDX-License-Identifier" |
| 21 | + |
| 22 | + # How many lines from the top the tags must appear within. HEEx templates and Rust files both |
| 23 | + # carry them first; an Elixir file may sit below a shebang or a moduledoc-free comment. |
| 24 | + @window 6 |
| 25 | + |
| 26 | + defp sources do |
| 27 | + {out, 0} = System.cmd("git", ["ls-files", "*.ex", "*.exs", "*.heex", "*.rs"]) |
| 28 | + String.split(out, "\n", trim: true) |
| 29 | + end |
| 30 | + |
| 31 | + defp head(file), do: file |> File.read!() |> String.split("\n") |> Enum.take(@window) |
| 32 | + |
| 33 | + test "the population is the tree's own source files, and it is not small" do |
| 34 | + files = sources() |
| 35 | + assert length(files) > 400, "expected the whole tree, got #{length(files)} files" |
| 36 | + end |
| 37 | + |
| 38 | + test "every source file carries a copyright statement" do |
| 39 | + missing = for f <- sources(), not Enum.any?(head(f), &String.contains?(&1, @copyright)), do: f |
| 40 | + |
| 41 | + assert missing == [], |
| 42 | + "these files carry no #{@copyright} line in their first #{@window} lines" |
| 43 | + end |
| 44 | + |
| 45 | + test "every source file carries a licence statement" do |
| 46 | + missing = for f <- sources(), not Enum.any?(head(f), &String.contains?(&1, @license)), do: f |
| 47 | + |
| 48 | + assert missing == [], |
| 49 | + "these files carry no #{@license} line in their first #{@window} lines" |
| 50 | + end |
| 51 | + |
| 52 | + test "the licence named in each file is the one the project is under" do |
| 53 | + for f <- sources(), line <- head(f), String.contains?(line, @license) do |
| 54 | + assert line =~ "Apache-2.0", |
| 55 | + "#{f} names a licence that is not the project's: #{String.trim(line)}" |
| 56 | + end |
| 57 | + end |
| 58 | +end |
0 commit comments