1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
import os
import markdown
import codecs
import difflib
try:
import nose
except ImportError:
raise ImportError, "The nose testing framework is required to run " \
"Python-Markdown tests. Run `easy_install nose` " \
"to install the latest version."
import util
from plugins import HtmlOutput, Markdown
try:
import tidy
except ImportError:
tidy = None
test_dir = os.path.abspath(os.path.dirname(__file__))
def relpath(path, start=test_dir):
""" reimplement relpath for python 2.3-2.5 from 2.6 """
if not path:
raise ValueError('no path secified')
start_list = os.path.abspath(start).split(os.path.sep)
path_list = os.path.abspath(path).split(os.path.sep)
# Work out how much of the filepath is shared by start and path.
i = len(os.path.commonprefix([start_list, path_list]))
rel_list = [os.path.pardir] * (len(start_list)-i) + path_list[i:]
if not rel_list:
return test_dir
return os.path.join(*rel_list)
def get_config(dir_name):
""" Get config for given directory name. """
config = util.CustomConfigParser({'normalize': '0',
'skip': '0',
'input_ext': '.txt',
'output_ext': '.html'})
config.read(os.path.join(dir_name, 'test.cfg'))
return config
def get_section(file, config):
""" Get name of config section for given file. """
filename = os.path.basename(file)
if config.has_section(filename):
return filename
else:
return 'DEFAULT'
def get_args(file, config):
""" Get args to pass to markdown from config for a given file. """
args = {}
section = get_section(file, config)
for key, v in config.items(section):
# Filter out args unique to testing framework
if key not in ['normalize', 'skip', 'input_ext', 'output_ext']:
args[key] = config.get(section, key)
return args
def normalize(text):
""" Normalize whitespace for a string of html using tidy. """
return str(tidy.parseString(text.encode('utf-8', 'xmlcharrefreplace'),
drop_empty_paras=0,
fix_backslash=0,
fix_bad_comments=0,
fix_uri=0,
join_styles=0,
lower_literals=0,
merge_divs=0,
output_xhtml=1,
quote_ampersand=0,
show_body_only=1,
char_encoding='utf8',
newline='LF')).decode('string-escape')
class CheckSyntax(object):
def __init__(self, description=None):
if description:
self.description = 'TestSyntax: "%s"' % description
def __call__(self, file, config):
""" Compare expected output to actual output and report result. """
cfg_section = get_section(file, config)
if config.get(cfg_section, 'skip'):
raise nose.plugins.skip.SkipTest, 'Test skipped per config.'
input_file = file + config.get(cfg_section, 'input_ext')
input = codecs.open(input_file, encoding="utf-8").read()
output_file = file + config.get(cfg_section, 'output_ext')
expected_output = codecs.open(output_file, encoding="utf-8").read()
output = markdown.markdown(input, **get_args(file, config))
if tidy and config.get(cfg_section, 'normalize'):
# Normalize whitespace before comparing.
expected_output = normalize(expected_output)
output = normalize(output)
elif config.get(cfg_section, 'normalize'):
# Tidy is not available. Skip this test.
raise nose.plugins.skip.SkipTest, 'Test skipped. Tidy not available in system.'
diff = [l for l in difflib.unified_diff(expected_output.splitlines(True),
output.splitlines(True),
output_file,
'actual_output.html',
n=3)]
if diff:
raise util.MarkdownSyntaxError('Output from "%s" failed to match expected '
'output.\n\n%s' % (input_file, ''.join(diff)))
def TestSyntax():
for dir_name, sub_dirs, files in os.walk(test_dir):
# Get dir specific config settings.
config = get_config(dir_name)
# Loop through files and generate tests.
for file in files:
root, ext = os.path.splitext(file)
if ext == config.get(get_section(file, config), 'input_ext'):
path = os.path.join(dir_name, root)
check_syntax = CheckSyntax(description=relpath(path, test_dir))
yield check_syntax, path, config
def generate(file, config):
""" Write expected output file for given input. """
cfg_section = get_section(file, config)
if config.get(cfg_section, 'skip'):
print 'Skipping:', file
return None
input_file = file + config.get(cfg_section, 'input_ext')
output_file = file + config.get(cfg_section, 'output_ext')
if not os.path.isfile(output_file) or \
os.path.getmtime(output_file) < os.path.getmtime(input_file):
print 'Generating:', file
markdown.markdownFromFile(input=input_file, output=output_file,
encoding='utf-8', **get_args(file, config))
else:
print 'Already up-to-date:', file
def generate_all():
""" Generate expected output for all outdated tests. """
for dir_name, sub_dirs, files in os.walk(test_dir):
# Get dir specific config settings.
config = get_config(dir_name)
# Loop through files and generate tests.
for file in files:
root, ext = os.path.splitext(file)
if ext == config.get(get_section(file, config), 'input_ext'):
generate(os.path.join(dir_name, root), config)
def run():
nose.main(addplugins=[HtmlOutput(), Markdown()])
|