forked from Python-Markdown/markdown
-
Notifications
You must be signed in to change notification settings - Fork 0
/
__init__.py
153 lines (138 loc) · 6.27 KB
/
__init__.py
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
151
152
from __future__ import with_statement
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')
with codecs.open(input_file, encoding="utf-8") as f:
input = f.read()
output_file = file + config.get(cfg_section, 'output_ext')
with codecs.open(output_file, encoding="utf-8") as f:
expected_output = f.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()])