Skip to content

Commit

Permalink
Move doc-related tests into their own file
Browse files Browse the repository at this point in the history
  • Loading branch information
whatyouhide committed Apr 6, 2023
1 parent aa8bc45 commit aa6b7cb
Show file tree
Hide file tree
Showing 2 changed files with 374 additions and 334 deletions.
374 changes: 374 additions & 0 deletions test/nimble_options/docs_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,374 @@
defmodule NimbleOptions.DocsTest do
use ExUnit.Case, async: true

describe "NimbleOptions.docs/1" do
test "override docs for recursive keys" do
docs = """
* `:type` (`t:atom/0`) - Required. The type of the option item.
* `:required` (`t:boolean/0`) - Defines if the option item is required. The default value is `false`.
* `:keys` (`t:keyword/0`) - Defines which set of keys are accepted.
* `:default` - The default.
"""

assert NimbleOptions.docs(recursive_schema()) == docs
end

test "generate inline indented docs for nested options" do
schema = [
producer: [
type: :non_empty_keyword_list,
doc: "The producer. Supported options:",
keys: [
module: [type: :mod_arg, doc: "The module."],
rate_limiting: [
type: :non_empty_keyword_list,
doc: """
A list of options to enable and configure rate limiting. Supported options:
""",
keys: [
allowed_messages: [type: :pos_integer, doc: "Number of messages per interval."],
interval: [required: true, type: :pos_integer, doc: "The interval."]
]
]
]
],
other_key: [type: :string]
]

docs = """
* `:producer` (non-empty `t:keyword/0`) - The producer. Supported options:
* `:module` - The module.
* `:rate_limiting` (non-empty `t:keyword/0`) - A list of options to enable and configure rate limiting. Supported options:
* `:allowed_messages` (`t:pos_integer/0`) - Number of messages per interval.
* `:interval` (`t:pos_integer/0`) - Required. The interval.
* `:other_key` (`t:String.t/0`)
"""

assert NimbleOptions.docs(schema) == docs
assert NimbleOptions.docs(NimbleOptions.new!(schema)) == docs
end

test "supports paragraphs and keeps the correct indentation" do
schema = [
producer: [
type: :non_empty_keyword_list,
doc: """
The producer.
Which is very cool.
""",
keys: [
nested: [
type: :integer,
doc: """
The nestedness.
It should be quite nested.
"""
]
]
]
]

docs = """
* `:producer` (non-empty `t:keyword/0`) - The producer.
Which is very cool.
* `:nested` (`t:integer/0`) - The nestedness.
It should be quite nested.
"""

assert NimbleOptions.docs(schema) == docs
assert NimbleOptions.docs(NimbleOptions.new!(schema)) == docs
end

test "uses the type_doc option" do
schema = [
foo: [type: :string, type_doc: "`t:SomeModule.t/0`", doc: "The foo."],
bar: [type: :string, type_doc: "`t:SomeModule.t/0`"],
baz: [type: :integer, type_doc: false, doc: "The bar."],
quux: [type: :integer, type_doc: false, doc: false]
]

docs = """
* `:foo` (`t:SomeModule.t/0`) - The foo.
* `:bar` (`t:SomeModule.t/0`)
* `:baz` - The bar.
"""

assert NimbleOptions.docs(schema) == docs
assert NimbleOptions.docs(NimbleOptions.new!(schema)) == docs
end

test "passing specific indentation" do
nested_schema = [
allowed_messages: [type: :pos_integer, doc: "Allowed messages."],
interval: [type: :pos_integer, doc: "Interval."]
]

schema = [
producer: [
type: {:or, [:string, keyword_list: nested_schema]},
doc: """
The producer. Either a string or a keyword list with the following keys:
#{NimbleOptions.docs(nested_schema)}
"""
],
map_with_keys: [
type: :map,
keys: [key_a: [type: :string, required: true], key_b: [type: {:map, :string, :integer}]]
],
other_key: [type: {:list, :atom}]
]

docs = """
* `:producer` - The producer. Either a string or a keyword list with the following keys:
* `:allowed_messages` (`t:pos_integer/0`) - Allowed messages.
* `:interval` (`t:pos_integer/0`) - Interval.
* `:map_with_keys` (`t:map/0`)
* `:key_a` (`t:String.t/0`) - Required.
* `:key_b` (map of `t:String.t/0` keys and `t:integer/0` values)
* `:other_key` (list of `t:atom/0`)
"""

assert NimbleOptions.docs(schema) == docs
end

test "generate subsections for nested options" do
schema = [
name: [required: true, type: :atom, doc: "The name."],
producer: [
type: :non_empty_keyword_list,
doc: "This is the producer summary. See \"Producers options\" section below.",
subsection: """
### Producers options
The producer options allow users to set up the producer.
The available options are:
""",
keys: [
module: [type: :mod_arg, doc: "The module."],
concurrency: [type: :pos_integer, doc: "The concurrency."]
]
],
other_key: [type: :string]
]

docs = """
* `:name` (`t:atom/0`) - Required. The name.
* `:producer` (non-empty `t:keyword/0`) - This is the producer summary. See "Producers options" section below.
* `:other_key` (`t:String.t/0`)
### Producers options
The producer options allow users to set up the producer.
The available options are:
* `:module` - The module.
* `:concurrency` (`t:pos_integer/0`) - The concurrency.
"""

assert NimbleOptions.docs(schema) == docs
end

test "keep indentation of multiline doc" do
schema = [
name: [
type: :string,
doc: """
The name.
This a multiline text.
Another line.
""",
default: "HELLO"
],
module: [
type: :atom,
doc: "The module."
]
]

docs = """
* `:name` (`t:String.t/0`) - The name.
This a multiline text.
Another line.
The default value is `"HELLO"`.
* `:module` (`t:atom/0`) - The module.
"""

assert NimbleOptions.docs(schema) == docs
end

test "the option doesn't appear in the documentation when the :doc option is false" do
schema = [
name: [type: :atom, doc: "An atom."],
secret: [type: :string, doc: false],
count: [type: :integer]
]

docs = """
* `:name` (`t:atom/0`) - An atom.
* `:count` (`t:integer/0`)
"""

assert NimbleOptions.docs(schema) == docs
end

test "the option and its children don't appear in the documentation when the :doc option is false" do
schema = [
producer: [
type: :keyword_list,
doc: false,
keys: [
name: [type: :atom],
concurrency: [type: :pos_integer]
]
]
]

docs = """
"""

assert NimbleOptions.docs(schema) == docs
end

test "stop generating docs recursively if type has no :keys" do
schema = [
custom_keys: [
type: :keyword_list,
doc: "Custom keys",
keys: [*: [type: :atom, doc: "Won't be there!"]]
]
]

opts = [custom_keys: [key1: :a, key2: :b]]

assert {:ok, ^opts} = NimbleOptions.validate(opts, schema)

assert NimbleOptions.docs(schema) == """
* `:custom_keys` (`t:keyword/0`) - Custom keys
"""
end

test "autogenerated type docs" do
schema = [
no_type: [],
custom: [type: {:custom, __MODULE__, :foo, []}],
or: [type: {:or, [:integer, :boolean]}],
f: [type: {:fun, 3}],
kw: [type: :keyword_list],
nonempty_kw: [type: :non_empty_keyword_list],
int: [type: :integer],
ref: [type: :reference],
list_of_ints: [type: {:list, :integer}],
nested_list_of_ints: [type: {:list, {:list, :integer}}],
list_of_kws: [type: {:list, {:keyword_list, []}}],
map: [type: :map],
map_of_strings: [type: {:map, :string, :string}],
tuple: [type: {:tuple, [:integer, :atom, {:list, :string}]}],
struct: [type: {:struct, URI}]
]

assert NimbleOptions.docs(schema) == """
* `:no_type`
* `:custom`
* `:or`
* `:f` (function of arity 3)
* `:kw` (`t:keyword/0`)
* `:nonempty_kw` (non-empty `t:keyword/0`)
* `:int` (`t:integer/0`)
* `:ref` (`t:reference/0`)
* `:list_of_ints` (list of `t:integer/0`)
* `:nested_list_of_ints` (list of list of `t:integer/0`)
* `:list_of_kws` (list of `t:keyword/0`)
* `:map` (`t:map/0`)
* `:map_of_strings` (map of `t:String.t/0` keys and `t:String.t/0` values)
* `:tuple` (tuple of `t:integer/0`, `t:atom/0`, list of `t:String.t/0` values)
* `:struct` (struct of type URI)
"""
end
end

defp recursive_schema() do
[
*: [
type: :keyword_list,
keys: [
type: [
type: :atom,
required: true,
doc: "The type of the option item."
],
required: [
type: :boolean,
default: false,
doc: "Defines if the option item is required."
],
keys: [
type: :keyword_list,
doc: "Defines which set of keys are accepted.",
keys: &recursive_schema/0
],
default: [
doc: "The default."
]
]
]
]
end
end
Loading

0 comments on commit aa6b7cb

Please sign in to comment.