#!/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("^(.|[\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()