defmodule GitGud.Workflows.ExprTest do
use ExUnit.Case, async: true
alias GitGud.Workflows.Expr
@contexts %{
"github" => %{
"workflow" => "ci",
"ref" => "refs/heads/main",
"head_ref" => "",
"run_id" => "42",
"event" => %{"pull_request" => %{"number" => 7}, "forced" => false}
},
"inputs" => %{"env" => "prod"},
"vars" => %{"REGION" => "eu"},
"matrix" => %{"target" => "arm64", "n" => 2},
"needs" => %{"build" => %{"result" => "success", "outputs" => %{"tag" => "v1"}}}
}
defp i(string), do: Expr.interpolate(string, @contexts)
describe "the patterns concurrency groups are made of" do
test "workflow and ref" do
assert i("${{ github.workflow }}-${{ github.ref }}") == {:ok, "ci-refs/heads/main"}
end
test "a pull request's number, else the ref" do
assert i("${{ github.event.pull_request.number || github.ref }}") == {:ok, "7"}
assert Expr.interpolate(
"${{ github.event.pull_request.number || github.ref }}",
put_in(@contexts, ["github", "event"], %{})
) == {:ok, "refs/heads/main"}
end
test "head_ref, else the run id: an empty string is falsy" do
assert i("${{ github.head_ref || github.run_id }}") == {:ok, "42"}
end
test "inputs, vars, matrix and needs" do
assert i("deploy-${{ inputs.env }}") == {:ok, "deploy-prod"}
assert i("${{ vars.REGION }}") == {:ok, "eu"}
assert i("${{ matrix.target }}-${{ matrix.n }}") == {:ok, "arm64-2"}
assert i("${{ needs.build.outputs.tag }}") == {:ok, "v1"}
end
test "index syntax, case-insensitively" do
assert i("${{ inputs['env'] }}") == {:ok, "prod"}
assert i("${{ GitHub.Workflow }}") == {:ok, "ci"}
assert i("${{ github['event']['pull_request'].number }}") == {:ok, "7"}
end
test "format" do
assert i("${{ format('{0}-{1}', github.workflow, inputs.env) }}") == {:ok, "ci-prod"}
assert i("${{ format('{{literal}} {0}', 'x') }}") == {:ok, "{literal} x"}
end
test "text without an expression is itself" do
assert i("deploy-prod") == {:ok, "deploy-prod"}
end
end
describe "operators and values" do
test "|| falls back over null and empty string, && keeps the falsy operand" do
assert i("${{ github.nothing || 'fallback' }}") == {:ok, "fallback"}
assert i("${{ '' || null || 'x' }}") == {:ok, "x"}
assert i("${{ github.head_ref && 'yes' }}") == {:ok, ""}
assert i("${{ github.workflow && 'yes' }}") == {:ok, "yes"}
end
test "== and != compare strings ignoring case, and loosely across types" do
assert Expr.evaluate("github.ref == 'REFS/HEADS/MAIN'", @contexts) == {:ok, true}
assert Expr.evaluate("github.ref != 'refs/heads/main'", @contexts) == {:ok, false}
assert Expr.evaluate("github.run_id == 42", @contexts) == {:ok, true}
assert Expr.evaluate("null == 0", @contexts) == {:ok, true}
assert Expr.evaluate("'abc' == 0", @contexts) == {:ok, false}
end
test "!, parentheses and precedence" do
assert Expr.evaluate("!github.event.forced", @contexts) == {:ok, true}
assert Expr.evaluate("!(true && false) || false", @contexts) == {:ok, true}
assert Expr.evaluate("false || true && false", @contexts) == {:ok, false}
end
test "values stringify as GitHub does" do
assert i("${{ null }}|${{ true }}|${{ false }}|${{ 1.0 }}|${{ 0x10 }}|${{ 'it''s' }}") ==
{:ok, "|true|false|1|16|it's"}
end
test "a path through something missing is null" do
assert i("${{ github.event.nope.deeper }}") == {:ok, ""}
end
end
describe "what isn't supported is an error, not a guess" do
test "other functions" do
assert i("${{ toJSON(github) }}") == :error
assert i("${{ contains(github.ref, 'main') }}") == :error
end
test "a context nobody supplied" do
assert i("${{ env.FOO }}") == :error
end
test "unknown syntax" do
assert i("${{ github.* }}") == :error
assert i("${{ github.ref < 'x' }}") == :error
assert i("${{ \"double\" }}") == :error
assert i("${{ github.ref") == :error
end
test "an object where a string was wanted" do
assert i("${{ github.event }}") == :error
end
end
end
neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
4.2 KiB · text
History
6b5083e