Newer
Older
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
#! /usr/bin/env python
import imp, logging, os, unittest
check = imp.load_source("check", # Import non-.py file
os.path.join(os.path.dirname(__file__), "check"))
# Make log messages visible to help audit test failures
check.start_logging(level=logging.DEBUG)
class BaseTemplateTest(unittest.TestCase):
"""Common methods for testing template validators"""
SAMPLE_FILE = "" # Path to a file that should pass all tests
VALIDATOR = check.MarkdownValidator
def setUp(self):
self.sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
def _create_validator(self, markdown):
"""Create validator object from markdown string; useful for failures"""
return self.VALIDATOR(markdown=markdown)
class TestAstHelpers(BaseTemplateTest):
SAMPLE_FILE = '../pages/index.md'
VALIDATOR = check.MarkdownValidator
def test_link_text_extracted(self):
"""Verify that link text and destination are extracted correctly"""
validator = self._create_validator("""[This is a link](discussion.html)""")
links = validator.ast.find_external_links(validator.ast.children[0])
dest, link_text = validator.ast.get_link_info(links[0])
self.assertEqual(dest, "discussion.html")
self.assertEqual(link_text, "This is a link")
class TestIndexPage(BaseTemplateTest):
"""Test the ability to correctly identify and validate specific sections
of a markdown file"""
SAMPLE_FILE = "../pages/index.md"
VALIDATOR = check.IndexPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
self.assertTrue(res)
def test_headers_missing_hrs(self):
validator = self._create_validator("""Blank row
layout: lesson
title: Lesson Title
keywords: ["some", "key terms", "in a list"]
Another section that isn't an HR
""")
self.assertFalse(validator._validate_doc_headers())
def test_headers_missing_a_line(self):
"""One of the required headers is missing"""
validator = self._create_validator("""---
layout: lesson
keywords: ["some", "key terms", "in a list"]
---""")
self.assertFalse(validator._validate_doc_headers())
# TESTS INVOLVING DOCUMENT HEADER SECTION
def test_headers_fail_with_other_content(self):
validator = self._create_validator("""---
layout: lesson
title: Lesson Title
keywords: ["some", "key terms", "in a list"]
otherline: Nothing
---""")
self.assertFalse(validator._validate_doc_headers())
def test_headers_fail_because_invalid_content(self):
validator = self._create_validator("""---
layout: lesson
title: Lesson Title
keywords: this is not a list
---""")
self.assertFalse(validator._validate_doc_headers())
# TESTS INVOLVING SECTION TITLES/HEADINGS
def test_index_has_valid_section_headings(self):
"""The provided index page"""
res = self.sample_validator._validate_section_heading_order()
self.assertTrue(res)
def test_index_fail_when_section_heading_absent(self):
res = self.sample_validator.ast.has_section_heading("Fake heading")
self.assertFalse(res)
def test_fail_when_section_heading_is_wrong_level(self):
"""All headings must be exactly level 2"""
validator = self._create_validator("""---
layout: page
title: Lesson Title
---
Paragraph of introductory material.
> ## Prerequisites
>
> A short paragraph describing what learners need to know
> before tackling this lesson.
### Topics
1. [Topic Title 1](01-one.html)
2. [Topic Title 2](02-two.html)
## Other Resources
* [Motivation](motivation.html)
* [Reference Guide](reference.html)
* [Next Steps](discussion.html)
* [Instructor's Guide](instructors.html)""")
self.assertFalse(validator._validate_section_heading_order())
def test_fail_when_section_headings_in_wrong_order(self):
validator = self._create_validator("""---
layout: lesson
title: Lesson Title
keywords: ["some", "key terms", "in a list"]
---
Paragraph of introductory material.
> ## Prerequisites
>
> A short paragraph describing what learners need to know
> before tackling this lesson.
## Other Resources
* [Motivation](motivation.html)
* [Reference Guide](reference.html)
* [Instructor's Guide](instructors.html)
## Topics
* [Topic Title 1](01-one.html)
* [Topic Title 2](02-two.html)""")
self.assertFalse(validator._validate_section_heading_order())
def test_pass_when_prereq_section_has_correct_heading_level(self):
validator = self._create_validator("""---
layout: lesson
title: Lesson Title
keywords: ["some", "key terms", "in a list"]
---
Paragraph of introductory material.
> ## Prerequisites
>
> A short paragraph describing what learners need to know
> before tackling this lesson.
""")
self.assertTrue(validator._validate_intro_section())
def test_fail_when_prereq_section_has_incorrect_heading_level(self):
validator = self._create_validator("""---
layout: lesson
title: Lesson Title
keywords: ["some", "key terms", "in a list"]
---
Paragraph of introductory material.
> # Prerequisites
>
> A short paragraph describing what learners need to know
> before tackling this lesson.
""")
self.assertFalse(validator._validate_intro_section())
# TESTS INVOLVING LINKS TO OTHER CONTENT
def test_file_links_validate(self):
res = self.sample_validator._validate_links()
self.assertTrue(res)
def test_html_link_to_extant_md_file_passes(self):
"""Verify that an HTML link with corresponding MD file will pass"""
validator = self._create_validator("""[Topic Title One](01-one.html)""")
self.assertTrue(validator._validate_links())
def test_html_link_with_anchor_to_extant_md_passes(self):
"""Verify that link is identified correctly even if to page anchor
For now this just tests that the regex handles #anchors.
It doesn't validate that the named anchor exists in the md file
"""
validator = self._create_validator("""[Topic Title One](01-one.html#anchor)""")
self.assertTrue(validator._validate_links())
def test_inpage_anchor_passes_validation(self):
"""Links that reference anchors within the page should be ignored"""
# TODO: Revisit once anchor rules are available
validator = self._create_validator("""Most databases also support Booleans and date/time values;
SQLite uses the integers 0 and 1 for the former, and represents the latter as discussed [earlier](#a:dates).""")
self.assertTrue(validator._validate_links())
def test_missing_markdown_file_fails_validation(self):
"""Fail validation when an html file is linked without corresponding
markdown file"""
validator = self._create_validator("""[Broken link](nonexistent.html)""")
self.assertFalse(validator._validate_links())
def test_website_link_ignored_by_validator(self):
"""Don't look for markdown if the file linked isn't local-
remote website links are ignored"""
validator = self._create_validator("""[Broken link](http://website.com/filename.html)""")
self.assertTrue(validator._validate_links())
def test_malformed_website_link_fails_validator(self):
"""If the link isn't prefixed by http(s):// or ftp://, fail.
This is because there are a lot of edge cases in distinguishing
between filenames and URLs: err on the side of certainty."""
validator = self._create_validator("""[Broken link](www.website.com/filename.html)""")
self.assertFalse(validator._validate_links())
def test_finds_image_asset(self):
"""Image asset is found"""
validator = self._create_validator(
"""""")
self.assertTrue(validator._validate_links())
def test_image_asset_not_found(self):
"""Image asset can't be found if path is invalid"""
validator = self._create_validator(
"""""")
self.assertFalse(validator._validate_links())
def test_non_html_link_finds_csv(self):
"""Look for CSV file in appropriate folder"""
validator = self._create_validator(
"""Use [this CSV](data/data.csv) for the exercise.""")
self.assertTrue(validator._validate_links())
def test_non_html_links_are_path_sensitive(self):
"""Fails to find CSV file with wrong path."""
validator = self._create_validator(
"""Use [this CSV](data.csv) for the exercise.""")
self.assertFalse(validator._validate_links())
class TestTopicPage(BaseTemplateTest):
"""Verifies that the topic page validator works as expected"""
SAMPLE_FILE = "../pages/01-one.md"
VALIDATOR = check.TopicPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
self.assertTrue(res)
class TestMotivationPage(BaseTemplateTest):
"""Verifies that the instructors page validator works as expected"""
SAMPLE_FILE = "../pages/motivation.md"
VALIDATOR = check.MotivationPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
self.assertTrue(res)
class TestReferencePage(BaseTemplateTest):
"""Verifies that the reference page validator works as expected"""
SAMPLE_FILE = "../pages/reference.md"
VALIDATOR = check.ReferencePageValidator
def test_missing_glossary_definition(self):
validator = self._create_validator("")
self.assertFalse(validator._validate_glossary_entry(
["Key word"]))
def test_missing_colon_at_glossary_definition(self):
validator = self._create_validator("")
self.assertFalse(validator._validate_glossary_entry(
["Key word", "Definition of term"]))
def test_wrong_indentation_at_glossary_definition(self):
validator = self._create_validator("")
self.assertFalse(validator._validate_glossary_entry(
["Key word", ": Definition of term"]))
def test_wrong_continuation_at_glossary_definition(self):
validator = self._create_validator("")
self.assertFalse(validator._validate_glossary_entry(
["Key word", ": Definition of term", "continuation"]))
def test_valid_glossary_definition(self):
validator = self._create_validator("")
self.assertTrue(validator._validate_glossary_entry(
["Key word", ": Definition of term", " continuation"]))
def test_only_definitions_can_appear_after_glossary_heading(self):
validator = self._create_validator("""## Glossary
Key Word 1
: Definition of first term
Paragraph
Key Word 2
: Definition of second term
""")
self.assertFalse(validator._validate_glossary())
def test_glossary(self):
validator = self._create_validator("""## Glossary
Key Word 1
: Definition of first term
Key Word 2
: Definition of second term
""")
self.assertTrue(validator._validate_glossary())
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
self.assertTrue(res)
class TestInstructorPage(BaseTemplateTest):
"""Verifies that the instructors page validator works as expected"""
SAMPLE_FILE = "../pages/instructors.md"
VALIDATOR = check.InstructorPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
self.assertTrue(res)
class TestLicensePage(BaseTemplateTest):
SAMPLE_FILE = '../pages/LICENSE.md'
VALIDATOR = check.LicensePageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
self.assertTrue(res)
def test_modified_file_fails_validation(self):
with open(self.SAMPLE_FILE, 'rU') as f:
orig_text = f.read()
mod_text = orig_text.replace("The", "the")
validator = self._create_validator(mod_text)
self.assertFalse(validator.validate())
class TestDiscussionPage(BaseTemplateTest):
SAMPLE_FILE = '../pages/discussion.md'
VALIDATOR = check.DiscussionPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
self.assertTrue(res)
if __name__ == "__main__":
unittest.main()