Skip to content

Commit

Permalink
Merge pull request #131 from epage/spec
Browse files Browse the repository at this point in the history
Generate tests from spec document
  • Loading branch information
arp242 authored Jan 18, 2023
2 parents 6087694 + 5e0df18 commit 932693d
Show file tree
Hide file tree
Showing 106 changed files with 2,521 additions and 0 deletions.
1,010 changes: 1,010 additions & 0 deletions assets/specs/en/v1.0.0.md

Large diffs are not rendered by default.

153 changes: 153 additions & 0 deletions gen-spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#!/usr/bin/env python3

import argparse
import pathlib
import shutil
import re


ROOT = pathlib.Path(__file__).parent
VALID_ROOT = ROOT / f"tests/valid/spec"
INVALID_ROOT = ROOT / f"tests/invalid/spec"


def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--input",
metavar="MD",
type=pathlib.Path, default=ROOT / "assets/specs/en/v1.0.0.md",
help="Spec to parse for test cases",
)
args = parser.parse_args()

try:
shutil.rmtree(VALID_ROOT)
except FileNotFoundError:
pass
try:
shutil.rmtree(INVALID_ROOT)
except FileNotFoundError:
pass

markdown = args.input.read_text()
lines = markdown.splitlines()

header = "common"
case_index = 0

line_index = 0
while line_index < len(lines):
try:
line_index, header = parse_header(line_index, lines)
except ParseError:
pass
else:
print(f"Parsing {header}")
case_index = 0
continue

try:
line_index, info, block = parse_block(line_index, lines)
except ParseError:
pass
else:
if info in ["toml", ""] and block.startswith("# INVALID"):
write_invalid_case(header, case_index, block)
case_index += 1
elif info == "toml":
if has_active_invalid(block):
write_invalid_case(header, case_index, block)
else:
write_valid_case(header, case_index, block)
case_index += 1
continue

line_index += 1


class ParseError(RuntimeError):
pass


def parse_header(line_index, lines):
try:
header = lines[line_index]
if not header:
raise ParseError()

line_index += 1
dashes = lines[line_index]
if not re.fullmatch("-+", dashes):
raise ParseError()

line_index += 1
blank = lines[line_index]
if blank:
raise ParseError()

line_index += 1
except IndexError:
raise ParseError()

header = header.lower().replace(" ", "-").replace("/", "-")
return line_index, header


FENCE = "```"


def parse_block(line_index, lines):
info = ""
try:
fence = lines[line_index]
if not fence.startswith(FENCE):
raise ParseError()
info = fence.removeprefix(FENCE)

block = []
line = ""
while line != FENCE:
block.append(line)
line_index += 1
line = lines[line_index]

line_index += 1
except IndexError:
raise ParseError()

return line_index, info, "\n".join(block)


def write_invalid_case(header, index, block):
path = INVALID_ROOT / f"{header}-{index}.toml"
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(block)


def write_valid_case(header, index, block):
path = VALID_ROOT / f"{header}-{index}.toml"
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(block)

invalid_index = 0
lines = block.splitlines()
for i, line in enumerate(lines):
if "# INVALID" in line:
new_lines = lines[:]
assert line.startswith("# "), f"{line}"
new_lines[i] = line.removeprefix("# ")
write_invalid_case(header, f"{index}-{invalid_index}", "\n".join(new_lines))
invalid_index += 1


def has_active_invalid(block):
lines = block.splitlines()
for line in lines:
if "# INVALID" in line and not line.startswith("# "):
return True
return False


if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions tests/invalid/spec/inline-table-2-0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

[product]
type = { name = "Nail" }
type.edible = false # INVALID
4 changes: 4 additions & 0 deletions tests/invalid/spec/inline-table-3-0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

[product]
type.name = "Nail"
type = { edible = false } # INVALID
2 changes: 2 additions & 0 deletions tests/invalid/spec/key-value-pair-1.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

key = # INVALID
4 changes: 4 additions & 0 deletions tests/invalid/spec/keys-2.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

= "no key name" # INVALID
"" = "blank" # VALID but discouraged
'' = 'blank' # VALID but discouraged
8 changes: 8 additions & 0 deletions tests/invalid/spec/string-4-0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

str4 = """Here are two quotation marks: "". Simple enough."""
str5 = """Here are three quotation marks: """.""" # INVALID
str5 = """Here are three quotation marks: ""\"."""
str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""

# "This," she said, "is just a pointless statement."
str7 = """"This," she said, "is just a pointless statement.""""
8 changes: 8 additions & 0 deletions tests/invalid/spec/string-7-0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

quot15 = '''Here are fifteen quotation marks: """""""""""""""'''

apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
apos15 = "Here are fifteen apostrophes: '''''''''''''''"

# 'That,' she said, 'is still pointless.'
str = ''''That,' she said, 'is still pointless.''''
10 changes: 10 additions & 0 deletions tests/invalid/spec/table-9-0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

[fruit]
apple.color = "red"
apple.taste.sweet = true

[fruit.apple] # INVALID
# [fruit.apple.taste] # INVALID

[fruit.apple.texture] # you can add sub-tables
smooth = true
10 changes: 10 additions & 0 deletions tests/invalid/spec/table-9-1.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

[fruit]
apple.color = "red"
apple.taste.sweet = true

# [fruit.apple] # INVALID
[fruit.apple.taste] # INVALID

[fruit.apple.texture] # you can add sub-tables
smooth = true
147 changes: 147 additions & 0 deletions tests/valid/spec/array-0.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
{
"nested_arrays_of_ints": [
[
{
"type": "integer",
"value": "1"
},
{
"type": "integer",
"value": "2"
}
],
[
{
"type": "integer",
"value": "3"
},
{
"type": "integer",
"value": "4"
},
{
"type": "integer",
"value": "5"
}
]
],
"colors": [
{
"type": "string",
"value": "red"
},
{
"type": "string",
"value": "yellow"
},
{
"type": "string",
"value": "green"
}
],
"numbers": [
{
"type": "float",
"value": "0.1"
},
{
"type": "float",
"value": "0.2"
},
{
"type": "float",
"value": "0.5"
},
{
"type": "integer",
"value": "1"
},
{
"type": "integer",
"value": "2"
},
{
"type": "integer",
"value": "5"
}
],
"contributors": [
{
"type": "string",
"value": "Foo Bar <[email protected]>"
},
{
"name": {
"type": "string",
"value": "Baz Qux"
},
"url": {
"type": "string",
"value": "https://example.com/bazqux"
},
"email": {
"type": "string",
"value": "[email protected]"
}
}
],
"integers": [
{
"type": "integer",
"value": "1"
},
{
"type": "integer",
"value": "2"
},
{
"type": "integer",
"value": "3"
}
],
"nested_mixed_array": [
[
{
"type": "integer",
"value": "1"
},
{
"type": "integer",
"value": "2"
}
],
[
{
"type": "string",
"value": "a"
},
{
"type": "string",
"value": "b"
},
{
"type": "string",
"value": "c"
}
]
],
"string_array": [
{
"type": "string",
"value": "all"
},
{
"type": "string",
"value": "strings"
},
{
"type": "string",
"value": "are the same"
},
{
"type": "string",
"value": "type"
}
]
}

13 changes: 13 additions & 0 deletions tests/valid/spec/array-0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

integers = [ 1, 2, 3 ]
colors = [ "red", "yellow", "green" ]
nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
string_array = [ "all", 'strings', """are the same""", '''type''' ]

# Mixed-type arrays are allowed
numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
contributors = [
"Foo Bar <[email protected]>",
{ name = "Baz Qux", email = "[email protected]", url = "https://example.com/bazqux" }
]
Loading

0 comments on commit 932693d

Please sign in to comment.