if Code.ensure_loaded?(ExUnitProperties) do
  defmodule Jason.PropertyTest do
    use ExUnit.Case, async: true
    use ExUnitProperties

    property "string roundtrip" do
      check all(string <- string(:printable)) do
        assert decode(:thoas.encode(string, %{})) == string
      end
    end

    property "integer roundtrip" do
      check all(integer <- integer()) do
        assert decode(:thoas.encode(integer, %{})) == integer
      end
    end

    property "float roundtrip" do
      check all(float <- float()) do
        assert decode(:thoas.encode(float, %{})) == float
      end
    end

    property "string-keyed objects roundrtip" do
      check all(json <- json(string(:printable))) do
        assert decode(:thoas.encode(json, %{})) == json
      end
    end

    property "html escaping" do
      check all(string <- string(:printable)) do
        encoded = :thoas.encode(string, %{escape: :html})
        refute encoded =~ <<0x2028::utf8>>
        refute encoded =~ <<0x2029::utf8>>
        refute encoded =~ ~r"(?<!\\)/"
        assert decode(encoded) == string
      end
    end

    property "javascript escaping" do
      check all(string <- string(:printable)) do
        encoded = :thoas.encode(string, %{escape: :javascript})
        refute encoded =~ <<0x2028::utf8>>
        refute encoded =~ <<0x2029::utf8>>
        assert decode(encoded) == string
      end
    end

    defp decode(data, opts \\ %{}) do
      {:ok, x} = :thoas.decode(data, opts)
      x
    end

    defp json(keys) do
      simple = one_of([integer(), float(), string(:printable), boolean(), :null])

      tree(simple, fn json ->
        one_of([list_of(json), map_of(keys, json)])
      end)
    end
  end
end
