You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
243 lines
7.4 KiB
243 lines
7.4 KiB
4 years ago
|
#!/usr/bin/env python
|
||
|
# coding: utf-8
|
||
|
from __future__ import division, print_function, unicode_literals
|
||
|
import re
|
||
|
import timeit
|
||
|
import codecs
|
||
|
import argparse
|
||
|
import sys
|
||
|
from builtins import str
|
||
|
from commonmark.render.html import HtmlRenderer
|
||
|
from commonmark.main import Parser, dumpAST
|
||
|
|
||
|
|
||
|
class colors(object):
|
||
|
HEADER = '\033[95m'
|
||
|
OKBLUE = '\033[94m'
|
||
|
OKGREEN = '\033[92m'
|
||
|
WARNING = '\033[93m'
|
||
|
FAIL = '\033[91m'
|
||
|
ENDC = '\033[0m'
|
||
|
|
||
|
|
||
|
def trace_calls(frame, event, arg):
|
||
|
co = frame.f_code
|
||
|
func_name = co.co_name
|
||
|
if func_name == "write":
|
||
|
return
|
||
|
line_no = frame.f_lineno
|
||
|
filename = co.co_filename
|
||
|
if event == "call" and not re.match("__", func_name) and \
|
||
|
re.search("CommonMark.py", filename) \
|
||
|
and func_name != "dumpAST":
|
||
|
print("-> " + frame.f_back.f_code.co_name +
|
||
|
" at " + str(frame.f_back.f_lineno) +
|
||
|
" called " + func_name + " at " + str(line_no) +
|
||
|
" in " + filename)
|
||
|
return trace_calls
|
||
|
|
||
|
|
||
|
def main():
|
||
|
parser = argparse.ArgumentParser(
|
||
|
description="script to run the CommonMark specification tests " +
|
||
|
"against the CommonMark.py parser")
|
||
|
parser.add_argument(
|
||
|
'-t',
|
||
|
help="Single test to run or comma separated list " +
|
||
|
"of tests (-t 10 or -t 10,11,12,13)")
|
||
|
parser.add_argument(
|
||
|
'-p',
|
||
|
action="store_true",
|
||
|
help="Print passed test information")
|
||
|
parser.add_argument(
|
||
|
'-f',
|
||
|
action="store_true",
|
||
|
help="Print failed tests (during -np...)")
|
||
|
parser.add_argument(
|
||
|
'-i',
|
||
|
action="store_true",
|
||
|
help="Interactive Markdown input mode")
|
||
|
parser.add_argument(
|
||
|
'-d',
|
||
|
action="store_true",
|
||
|
help="Debug, trace calls")
|
||
|
parser.add_argument(
|
||
|
'-np',
|
||
|
action="store_true",
|
||
|
help="Only print section header, tick, or cross")
|
||
|
parser.add_argument(
|
||
|
'-s',
|
||
|
action="store_true",
|
||
|
help="Print percent of tests passed by category")
|
||
|
args = parser.parse_args()
|
||
|
|
||
|
if args.d:
|
||
|
sys.settrace(trace_calls)
|
||
|
|
||
|
renderer = HtmlRenderer()
|
||
|
parser = Parser()
|
||
|
|
||
|
f = codecs.open("spec.txt", encoding="utf-8")
|
||
|
datalist = []
|
||
|
for line in f:
|
||
|
datalist.append(line)
|
||
|
data = "".join(datalist)
|
||
|
passed = 0
|
||
|
failed = 0
|
||
|
catStats = {}
|
||
|
examples = []
|
||
|
example_number = 0
|
||
|
current_section = ""
|
||
|
tabChar = '\u2192'
|
||
|
spaceChar = '\u2423'
|
||
|
nbspChar = '\u00A0'
|
||
|
|
||
|
def showSpaces(t):
|
||
|
t = re.sub("\\t", tabChar, t)
|
||
|
t = re.sub(" ", spaceChar, t)
|
||
|
t = re.sub(nbspChar, spaceChar, t)
|
||
|
return t
|
||
|
|
||
|
t = re.sub("\r\n", "\n", data)
|
||
|
|
||
|
tests = re.sub(
|
||
|
re.compile("^<!-- END TESTS -->(.|[\n])*", flags=re.M), '', t)
|
||
|
testMatch = re.findall(
|
||
|
re.compile(
|
||
|
r'^`{32} example\n'
|
||
|
r'([\s\S]*?)^\.\n([\s\S]*?)'
|
||
|
r'^`{32}$'
|
||
|
r'|^#{1,6} *(.*)$',
|
||
|
re.M),
|
||
|
tests)
|
||
|
|
||
|
for match in testMatch:
|
||
|
if not match[2] == "":
|
||
|
current_section = match[2]
|
||
|
else:
|
||
|
example_number += 1
|
||
|
examples.append({
|
||
|
'markdown': match[0],
|
||
|
'html': match[1],
|
||
|
'section': current_section,
|
||
|
'number': example_number})
|
||
|
|
||
|
current_section = ""
|
||
|
|
||
|
startTime = timeit.default_timer()
|
||
|
|
||
|
if args.i:
|
||
|
print(
|
||
|
colors.OKGREEN +
|
||
|
"(To end input of Markdown block enter 'end' on " +
|
||
|
"it's own line, to quit enter 'quit')" +
|
||
|
colors.ENDC)
|
||
|
while True:
|
||
|
s = ""
|
||
|
while True:
|
||
|
if sys.version_info >= (3, 0):
|
||
|
inp = input(colors.OKBLUE + 'Markdown: ' + colors.ENDC)
|
||
|
else:
|
||
|
inp = raw_input(colors.OKBLUE + 'Markdown: ' + colors.ENDC) # noqa
|
||
|
|
||
|
if not inp == "end" and inp != "quit":
|
||
|
s += inp + "\n"
|
||
|
elif inp == "end":
|
||
|
s = s[:-1]
|
||
|
break
|
||
|
elif inp == "quit":
|
||
|
print(colors.HEADER+"bye!"+colors.ENDC)
|
||
|
exit(0)
|
||
|
ast = parser.parse(s)
|
||
|
html = renderer.render(ast)
|
||
|
print(colors.WARNING+"="*10+"AST====="+colors.ENDC)
|
||
|
dumpAST(ast)
|
||
|
print(colors.WARNING+"="*10+"HTML===="+colors.ENDC)
|
||
|
print(html)
|
||
|
|
||
|
# some tests?
|
||
|
if args.t:
|
||
|
tests = args.t.split(",")
|
||
|
choice_examples = []
|
||
|
for t in tests:
|
||
|
if not t == "" and len(examples) > int(t):
|
||
|
choice_examples.append(examples[int(t)-1])
|
||
|
examples = choice_examples
|
||
|
|
||
|
# all tests
|
||
|
|
||
|
for i, example in enumerate(examples): # [0,examples[0]]
|
||
|
if not example['section'] == "" and \
|
||
|
not current_section == example['section']:
|
||
|
print('\n' + colors.HEADER + '[' + example['section'] + ']' +
|
||
|
colors.ENDC + ' ', end='')
|
||
|
current_section = example['section']
|
||
|
catStats.update({current_section: [0, 0, 0]})
|
||
|
|
||
|
catStats[current_section][2] += 1
|
||
|
if args.d:
|
||
|
print(colors.HEADER+"[Parsing]"+colors.ENDC)
|
||
|
ast = parser.parse(re.sub(tabChar, "\t", example['markdown']))
|
||
|
if args.d:
|
||
|
print(colors.HEADER+"[Rendering]"+colors.ENDC)
|
||
|
actual = renderer.render(ast)
|
||
|
if re.sub('\t', tabChar, actual) == example['html']:
|
||
|
passed += 1
|
||
|
catStats[current_section][0] += 1
|
||
|
if not args.f:
|
||
|
print(colors.OKGREEN + '✓' + colors.ENDC, end='')
|
||
|
if args.d:
|
||
|
dumpAST(ast)
|
||
|
if args.p or args.d and not args.np:
|
||
|
print(
|
||
|
colors.OKBLUE +
|
||
|
"=== markdown ===============\n" +
|
||
|
colors.ENDC + showSpaces(example['markdown']) +
|
||
|
colors.OKBLUE +
|
||
|
"\n=== expected ===============\n" +
|
||
|
colors.ENDC + showSpaces(example['html']) +
|
||
|
colors.OKBLUE +
|
||
|
"\n=== got ====================\n" +
|
||
|
colors.ENDC + showSpaces(actual))
|
||
|
else:
|
||
|
failed += 1
|
||
|
catStats[current_section][1] += 1
|
||
|
if args.t:
|
||
|
print("Test #" + str(args.t.split(",")[i]), end='')
|
||
|
else:
|
||
|
print("Test #" + str(i+1), end='')
|
||
|
print(' ' + colors.FAIL + "✗" + colors.ENDC)
|
||
|
if args.d:
|
||
|
dumpAST(ast)
|
||
|
if not args.np or args.f:
|
||
|
print(
|
||
|
colors.WARNING +
|
||
|
"=== markdown ===============\n" +
|
||
|
colors.ENDC + showSpaces(example['markdown']) +
|
||
|
colors.WARNING +
|
||
|
"\n=== expected ===============\n" +
|
||
|
colors.ENDC + showSpaces(example['html']) +
|
||
|
colors.WARNING +
|
||
|
"\n=== got ====================\n" +
|
||
|
colors.ENDC + showSpaces(actual))
|
||
|
|
||
|
print('\n' + str(passed) + ' tests passed, ' + str(failed) + ' failed')
|
||
|
|
||
|
endTime = timeit.default_timer()
|
||
|
runTime = endTime - startTime
|
||
|
|
||
|
if args.s:
|
||
|
for i in catStats.keys():
|
||
|
per = catStats[i][0]/catStats[i][2]
|
||
|
print(colors.HEADER + "[" + i + "]" + colors.ENDC +
|
||
|
"\t" + str(per*100) + "% Passed")
|
||
|
|
||
|
print("runtime: " + str(runTime) + "s")
|
||
|
|
||
|
if (failed > 0):
|
||
|
sys.exit(1)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|