Skip to content
Snippets Groups Projects
Commit 58b9f135 authored by Greg Wilson's avatar Greg Wilson
Browse files

Merge branch 'gh-pages' of github.com:swcarpentry/lesson-template into gh-pages

parents 9220a1d9 e829a8e9
Branches
Tags
No related merge requests found
......@@ -64,6 +64,12 @@ document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'" clas'+'s="em' + 'ail">'+'mail
</ul>
<h2 id="debugging">Debugging</h2>
<p>Please add notes about problems and solutions below.</p>
<ul>
<li><p><code>pandoc: command not found</code></p>
<p>Probably you didn't install <a href="http://pandoc.org/installing.html">Pandoc</a>.</p></li>
<li><p><code>pandoc: Error running filter tools/filters/blockquote2div.py</code> due <code>ImportError: No module named 'pandocfilters'</code></p>
<p>Probably you didn't install <a href="https://pypi.python.org/pypi/pandocfilters/1.2.3">pandocfilters</a>.</p></li>
</ul>
</div>
</div>
<div class="footer">
......
......@@ -40,3 +40,13 @@
## Debugging
Please add notes about problems and solutions below.
* `pandoc: command not found`
Probably you didn't install [Pandoc](http://pandoc.org/installing.html).
* `pandoc: Error running filter tools/filters/blockquote2div.py`
due `ImportError: No module named 'pandocfilters'`
Probably you didn't install
[pandocfilters](https://pypi.python.org/pypi/pandocfilters/1.2.3).
......@@ -88,8 +88,8 @@ Paragraph(s) of introductory material.
## Other Resources
* [Motivation](motivation.html)
* [Reference Guide](reference.html)
* [Next Steps](discussion.html)
* [Reference](reference.html)
* [Discussion](discussion.html)
* [Instructor&#39;s Guide](instructors.html)</code></pre>
<p><strong>Notes:</strong></p>
<ol style="list-style-type: decimal">
......@@ -154,7 +154,8 @@ and one or more of these:
<p>Every lesson must include a short slide deck suitable for a short presentation (3 minutes or less) that the instructor can use to explain to learners how knowing the subject will help them. The slides must be laid out like this:</p>
<pre><code>---
layout: slides
title: Why Make?
title: Lesson Title
subtitle: Motivation
---
&lt;section class=&quot;slide&quot;&gt;
## Why This Topic?
......
......@@ -30,6 +30,11 @@ motivation.html : motivation.md _layouts/slides.html
$(INCLUDES) \
-o $@ $<
## unittest : Run unit test (for Python 2 and 3)
unittest: tools/check tools/validation_helpers.py tools/test_check.py
cd tools/ && python2 test_check.py
cd tools/ && python3 test_check.py
## commands : Display available commands.
commands : Makefile
@sed -n 's/^##//p' $<
......
......@@ -406,7 +406,8 @@ class TopicPageValidator(MarkdownValidator):
class MotivationPageValidator(MarkdownValidator):
"""Validate motivation.md"""
DOC_HEADERS = {"layout": vh.is_str,
"title": vh.is_str}
"title": vh.is_str,
"subtitle": vh.is_str}
# TODO: How to validate? May be a mix of reveal.js (HTML) + markdown.
......
......@@ -104,12 +104,11 @@ def blockquote2div(key, value, format, meta):
id, classes, kvs = attr
ltitle = pf.stringify(inlines).lower()
if ltitle in SPECIAL_TITLES:
classes.append(SPECIAL_TITLES[ltitle])
return pf.Div(attr, blockquote)
lowercase_title = pf.stringify(inlines).lower()
if lowercase_title in SPECIAL_TITLES:
classes.append(SPECIAL_TITLES[lowercase_title])
elif len(classes) == 1 and classes[0] in SPECIAL_CLASSES:
if len(classes) == 1 and classes[0] in SPECIAL_CLASSES:
remove_attributes(blockquote)
# a blockquote is just a list of blocks, so it can be
# passed directly to Div, which expects Div(attr, blocks)
......
#! /usr/bin/env python
import imp, logging, os, unittest
"""
Unit and functional tests for markdown lesson template validator.
Some of these tests require looking for example files, which exist only on
the gh-pages branch. Some tests may therefore fail on branch "core".
"""
import imp
import logging
import os
import unittest
check = imp.load_source("check", # Import non-.py file
os.path.join(os.path.dirname(__file__), "check"))
......@@ -8,7 +20,7 @@ check = imp.load_source("check", # Import non-.py file
check.start_logging(level=logging.DEBUG)
MARKDOWN_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir))
os.path.join(os.path.dirname(__file__), os.pardir))
class BaseTemplateTest(unittest.TestCase):
......@@ -16,9 +28,6 @@ class BaseTemplateTest(unittest.TestCase):
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)
......@@ -45,7 +54,8 @@ class TestIndexPage(BaseTemplateTest):
VALIDATOR = check.IndexPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
res = sample_validator.validate()
self.assertTrue(res)
def test_headers_missing_hrs(self):
......@@ -89,11 +99,33 @@ keywords: this is not a list
# 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()
validator = self._create_validator("""## Topics
1. [Topic Title One](01-one.html)
2. [Topic Title Two](02-two.html)
## Other Resources
* [Motivation](motivation.html)
* [Reference Guide](reference.html)
* [Next Steps](discussion.html)
* [Instructor's Guide](instructors.html)""")
res = 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")
validator = self._create_validator("""## Topics
1. [Topic Title One](01-one.html)
2. [Topic Title Two](02-two.html)
## Other Resources
* [Motivation](motivation.html)
* [Reference Guide](reference.html)
* [Next Steps](discussion.html)
* [Instructor's Guide](instructors.html)""")
res = validator.ast.has_section_heading("Fake heading")
self.assertFalse(res)
def test_fail_when_section_heading_is_wrong_level(self):
......@@ -122,7 +154,6 @@ Paragraph of introductory material.
* [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
......@@ -182,11 +213,15 @@ Paragraph of introductory material.
# TESTS INVOLVING LINKS TO OTHER CONTENT
def test_file_links_validate(self):
res = self.sample_validator._validate_links()
"""Verify that all links in a sample file validate.
Involves checking for example files; may fail on "core" branch"""
sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
res = 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"""
"""Verify that an HTML link with corresponding MD file will pass
Involves checking for example files; may fail on "core" branch"""
validator = self._create_validator("""[Topic Title One](01-one.html)""")
self.assertTrue(validator._validate_links())
......@@ -195,6 +230,8 @@ Paragraph of introductory material.
For now this just tests that the regex handles #anchors.
It doesn't validate that the named anchor exists in the md file
Involves checking for example files; may fail on "core" branch
"""
validator = self._create_validator("""[Topic Title One](01-one.html#anchor)""")
self.assertTrue(validator._validate_links())
......@@ -206,7 +243,6 @@ Paragraph of introductory material.
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"""
......@@ -227,7 +263,8 @@ SQLite uses the integers 0 and 1 for the former, and represents the latter as di
self.assertFalse(validator._validate_links())
def test_finds_image_asset(self):
"""Image asset is found"""
"""Image asset is found in the expected file location
Involves checking for example files; may fail on "core" branch"""
validator = self._create_validator(
"""![this is the image's title](fig/example.svg "this is the image's alt text")""")
self.assertTrue(validator._validate_links())
......@@ -239,7 +276,9 @@ SQLite uses the integers 0 and 1 for the former, and represents the latter as di
self.assertFalse(validator._validate_links())
def test_non_html_link_finds_csv(self):
"""Look for CSV file in appropriate folder"""
"""Look for CSV file in appropriate folder
Involves checking for example files; may fail on "core" branch
"""
validator = self._create_validator(
"""Use [this CSV](data/data.csv) for the exercise.""")
self.assertTrue(validator._validate_links())
......@@ -257,7 +296,8 @@ class TestTopicPage(BaseTemplateTest):
VALIDATOR = check.TopicPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
res = sample_validator.validate()
self.assertTrue(res)
......@@ -267,7 +307,8 @@ class TestMotivationPage(BaseTemplateTest):
VALIDATOR = check.MotivationPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
res = sample_validator.validate()
self.assertTrue(res)
......@@ -326,7 +367,8 @@ Key Word 2
self.assertTrue(validator._validate_glossary())
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
res = sample_validator.validate()
self.assertTrue(res)
......@@ -336,7 +378,8 @@ class TestInstructorPage(BaseTemplateTest):
VALIDATOR = check.InstructorPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
res = sample_validator.validate()
self.assertTrue(res)
......@@ -345,7 +388,8 @@ class TestLicensePage(BaseTemplateTest):
VALIDATOR = check.LicensePageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
res = sample_validator.validate()
self.assertTrue(res)
def test_modified_file_fails_validation(self):
......@@ -361,7 +405,8 @@ class TestDiscussionPage(BaseTemplateTest):
VALIDATOR = check.DiscussionPageValidator
def test_sample_file_passes_validation(self):
res = self.sample_validator.validate()
sample_validator = self.VALIDATOR(self.SAMPLE_FILE)
res = sample_validator.validate()
self.assertTrue(res)
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment