3.5 KiB · text History 0d6bdf0
defmodule GitGud.Badges.SvgTest do
  use ExUnit.Case, async: true

  alias GitGud.Badges
  alias GitGud.Badges.Palette
  alias GitGud.Badges.Spec
  alias GitGud.Badges.Svg

  @content %{label: "ci", value: "passing", slot: "success"}

  test "lettering is outlines, never <text>" do
    for style <- Spec.styles(), mode <- [:auto, :inline, {:theme, "forest"}] do
      svg = Svg.render(@content, %Spec{style: style, gg: true}, mode)
      refute svg =~ "<text"
      assert svg =~ ~s(<path d="M)
      assert svg =~ ~s(aria-label="ci: passing")
    end
  end

  test "a fixed theme writes its colors onto the shapes" do
    svg = Svg.render(@content, %Spec{}, {:theme, "forest"})
    assert svg =~ ~s(fill="#{Palette.hex("forest", "success-bg")}")
    refute svg =~ "<style"
    refute svg =~ "class="
  end

  test "auto carries both schemes" do
    svg = Svg.render(@content, %Spec{}, :auto)
    assert svg =~ "<style>"
    assert svg =~ "@media (prefers-color-scheme: light)"
    assert svg =~ Palette.hex("dark", "success-bg")
    assert svg =~ Palette.hex("light", "success-bg")
  end

  test "inline leaves color to the page" do
    svg = Svg.render(@content, %Spec{}, :inline)
    assert svg =~ ~s(class="ggb")
    assert svg =~ ~s(class="f-success-bg")
    assert svg =~ ~s(class="g-r")
    refute svg =~ "<style"
  end

  test "scale sizes the image, not the drawing" do
    one = Svg.render(@content, %Spec{}, :auto)
    big = Svg.render(@content, %Spec{scale: "2.5x"}, :auto)

    [_, w] = Regex.run(~r/<svg[^>]* width="([\d.]+)"/, one)
    [_, big_w] = Regex.run(~r/<svg[^>]* width="([\d.]+)"/, big)
    [_, h] = Regex.run(~r/<svg[^>]* height="([\d.]+)"/, big)
    assert h == "50"
    assert elem(Float.parse(big_w), 0) == String.to_integer(w) * 2.5
    # The drawing keeps its 1x coordinates.
    assert big =~ ~s(viewBox="0 0 #{w} 20")
  end

  test "square corners and the theme's pill" do
    assert Svg.render(@content, %Spec{corners: "square"}, {:theme, "her"}) =~ ~s(rx="0")
    assert Svg.render(@content, %Spec{}, {:theme, "her"}) =~ ~s(rx="10")
    assert Svg.render(@content, %Spec{}, {:theme, "dark"}) =~ ~s(rx="4")
  end

  test "a PNG is the same drawing rasterized" do
    spec = %Spec{format: "png", theme: "sky", scale: "2x"}

    assert {:ok, "image/png", <<137, 80, 78, 71, 13, 10, 26, 10, _::binary>> = png} =
             Badges.render_content(@content, spec)

    # IHDR: width and height, big-endian, right after the chunk header.
    <<_sig::binary-8, _len::32, "IHDR", _w::32, height::32, _::binary>> = png
    assert height == 40
  end

  test "the clip path id can be given, and defaults per badge" do
    assert Svg.render(@content, %Spec{}, :inline, id: "ggb-one") =~ ~s(id="ggb-one")

    a = Svg.render(@content, %Spec{}, :auto)
    b = Svg.render(%{@content | value: "failing", slot: "error"}, %Spec{}, :auto)
    [_, id_a] = Regex.run(~r/clipPath id="([^"]+)"/, a)
    [_, id_b] = Regex.run(~r/clipPath id="([^"]+)"/, b)
    refute id_a == id_b
  end

  test "emoji come from the fallback font, not as `?`" do
    alias GitGud.Badges.Native

    question = Native.text_path("?", false, 11.0, 0.0, 14.0)
    star = Native.text_path("⭐", false, 11.0, 0.0, 14.0)
    refute star == question
    assert star =~ "M"

    # The variation selector in ❤️ takes no room.
    assert Native.text_width("❤️", false, 11.0) == Native.text_width("❤", false, 11.0)
    assert Native.text_width("⭐", false, 11.0) > 0
  end

  test "the mark alone" do
    for style <- Spec.styles() do
      assert Svg.render(:mark, %Spec{style: style}, :auto) =~ ~s(aria-label="GitGud")
    end
  end
end