CI License Version Docs

Data generation from JSON schema. Supports JSON Schema draft 04 to draft 2020-12.

Usage

Add to your list of dependencies

def deps do
  [
    {:rock_solid, "~> 0.0.12", only: :test}
  ]
end

Inside a property test

defmodule MyTest do
  use ExUnit.Case
  use ExUnitProperties

  property "generates valid user profiles" do
    schema = %{
      "type" => "object",
      "additionalProperties" => false,
      "properties" => %{
        "birthDate" => %{"type" => "string", "format" => "date"},
        "name" => %{"type" => "string", "pattern" => "^[A-Z][a-z]+$"},
        "email" => %{"type" => "string", "format" => "email"}
      },
      "required" => ["birthDate", "name", "email"]
    }

    check all user_data <- RockSolid.from_schema(schema) do
      assert Regex.match?(~r/^[A-Z][a-z]+$/, user_data["name"])
      assert %Date{} = Date.from_iso8601!(user_data["birthDate"])
      assert String.split(user_data["email"], "@") |> length() == 2
    end
  end
end

or as a generator, since RockSolid.from_schema/2 returns elements of StreamData.t()

iex(1)> specs = %{
  "type" => "object",
  "properties" => %{
    "serverIPs" => %{
      "type" => "array",
      "items" => %{"type" => "string", "format" => "ipv4"},
      "uniqueItems" => true,
      "minItems" => 1
    },
    "serverName" => %{"pattern" => "^[a-z][a-z_0-9]{2,255}$", "type" => "string"},
  },
  "required" => ["serverIPs", "serverName"],
  "additionalProperties" => false
}

iex(2)> specs |> RockSolid.from_schema() |> Enum.take(3)
[
  %{"serverIPs" => ["148.50.92.205"], "serverName" => "a5l"},
  %{"serverIPs" => ["230.26.166.121"], "serverName" => "y_w"},
  %{
    "serverIPs" => ["144.154.111.248", "155.134.134.38"],
    "serverName" => "v2_5"
  }
]

Known bugs and issues

The library can generate valid payloads for most schemas, with a 87% passing rate when testing the entire catalog from Schemastore. The following are a list of known bugs, limitations and issues, ordered from most common to least common.

  • Failing to generate data when possible value set is too narrow. For example strings with "pattern" and minLength/maxLength, or a not clause that overlaps with many of the positive cases. To prevent this issue, encode the string length as part of the "pattern" keyword, and try to be specific when using "not" keywords.
  • Timeouts. Caused when defining multiple "if"/"then"/"else", "dependentSchemas", and "oneOf". To prevent timeouts, express branching logic as "anyOf" instead.
  • Recursive schemas. While recursive schemas are supported, the algorithm often needs to find the intersection of a recursive schema and another subschema, which might throw an error. There is no workaround for this issue at the moment.
  • "$dynamicRef", "$dynamicAnchor", "unevaluatedItems", "unevaluatedProperties", "maxContains" keywords are not supported currently, since their behavior is defined at runtime.