class SetTagTests(TestCase):
    """Coordinate tag validation tests."""

    def setUp(self):
        """Instantiate the ExerciseValidator class."""
        self.exercise_validator = ExerciseValidator()
        self.template_dom = etree.parse('tests/set_tag_tests/test_set_tag.xml')

    def test_validate_template_with_coordinate_tags(self):
        """Validate: coordinate tag in a para tag within a problem tag."""
        self.assertEqual(self.exercise_validator.validate(etree.tostring(self.template_dom)), None)
 def setUp(self):
     """Instantiate the ExerciseValidator class."""
     self.exercise_validator = ExerciseValidator()
     self.template_dom = etree.parse('tests/set_tag_tests/test_set_tag.xml')
 def setUp(self):
     self.exercise_validator = ExerciseValidator()
class ExerciseValidatorTests(TestCase):
    """
    Test that the ExerciseValidator class correctly validates a given XML structure.

    This assume a specific exercise layout specification.
    """

    def setUp(self):
        self.exercise_validator = ExerciseValidator()

    def test_validate_with_valid_xml(self):
        """
        Test the minimum needed elements for a template.

        Response is actually optional since that is not needed for entries in books.
        """
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                </problem>
                <response>
                </response>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    @raises(XmlValidationError)
    def test_validate_with_invalid_xml(self):
        good_template_dom = etree.fromstring("<exercise-container></exercise-container>")

        self.exercise_validator.validate(good_template_dom)

    def test_validate_with_note_tag(self):
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <note type="note">
                    </note>
                </problem>
                <solution>
                    <note type="note">
                    </note>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_note_tag_with_variety_of_typical_subtags(self):
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <note type="note">
                        In-line Elements
                        <number>5</number>
                        <sup>2</sup>
                    </note>
                </problem>
                <solution>
                    <note type="note">
                        Para Elements
                        <list><item>1</item><item>2</item><item>3</item></list>
                        <latex></latex>
                    </note>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_note_tag_with_text(self):
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <note type="note">Note Content</note>
                </problem>
                <solution>
                    <note type="tip">Note Content</note>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_note_tag_with_para(self):
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <note type="note"><para>Note Content</para></note>
                </problem>
                <solution>
                    <note type="tip"><para>Note Content</para></note>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    @raises(KeyError)
    def test_validate_with_note_tag_with_no_attribute(self):
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <note>
                    </note>
                </problem>
                <solution>
                    <note>
                    </note>
                </solution>
            </entry>
        </exercise-container>"""
        )

        self.exercise_validator.validate(good_template_dom)

    @raises(XmlValidationError)
    def test_validate_with_note_tag_with_incorrect_attribute(self):
        bad_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <note type="bob">
                    </note>
                </problem>
                <solution>
                    <note type="bob">
                    </note>
                </solution>
            </entry>
        </exercise-container>"""
        )

        self.exercise_validator.validate(bad_template_dom)

    @raises(XmlValidationError)
    def test_validate_with_note_tag_with_book_note_attribute(self):
        bad_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <note type="warning">
                    </note>
                </problem>
                <solution>
                    <note type="warning">
                    </note>
                </solution>
            </entry>
        </exercise-container>"""
        )

        self.exercise_validator.validate(bad_template_dom)

    def test_validate_with_nuclear_notation_tag_no_atomic_number(self):
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <nuclear_notation><symbol>He</symbol><mass_number>5</mass_number></nuclear_notation>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_nuclear_notation_tag_no_mass_number(self):
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <nuclear_notation>
                        <symbol>He</symbol>
                        <atomic_number>5</atomic_number>
                    </nuclear_notation>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    # @raises(XmlValidationError)
    def test_validate_with_nuclear_notation_tag_no_symbol(self):
        """
        Raise an error since the symbol tag should be required.

        The problem lies in the unordered modifier since the spec for that is a hack and matches
        incorrect patterns. This needs to be corrected.
        """
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <nuclear_notation>
                        <atomic_number>He</atomic_number>
                        <mass_number>5</mass_number>
                    </nuclear_notation>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_nuclear_notation_tag_no_children(self):
        """
        Raise an error since nuclear_notation is required to contain at least the symbol tag.

        The problem lies in the unordered modifier since the spec for that is a hack and matches
        incorrect patterns. This needs to be corrected.
        """
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <nuclear_notation></nuclear_notation>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_currency_tag_no_children_no_text(self):
        """Test the currency tag with no children and no text."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <currency></currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    @raises(XmlValidationError)
    def test_validate_with_currency_tag_no_children_text(self):
        """Test the currency tag with no children and text."""
        bad_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <currency>R 5</currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        self.exercise_validator.validate(bad_template_dom)

    def test_validate_currency_tag_with_only_symbol_child(self):
        """Test the currency tag with only symbol child."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <currency>
                        <symbol>R</symbol>
                    </currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_currency_tag_with_only_number_child(self):
        """Test the currency tag with only number child."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <currency>
                        <number>5</number>
                    </currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_currency_tag_with_both_children(self):
        """Test the currency tag with both children."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <currency>
                        <number>5</number><symbol>R</symbol>
                    </currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_pspicture_tag_no_children(self):
        """
        Test validation of pspicture with no child tags.

        This should raise an error since pspicture is required to contain at
        least either src or code child.
        The problem lies in the unordered modifier since the spec
        for that is a hack and matches incorrect patterns.
        This needs to be corrected.
        """
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <pspicture></pspicture>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_tikzpicture_tag_no_children(self):
        """
        Raise an error since tikzpicture is required to contain at least either src or code child.

        The problem lies in the unordered modifier since the spec for that is a hack and matches
        incorrect patterns. This needs to be corrected.
        """
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <tikzpicture></tikzpicture>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_style_tag(self):
        """Test that the style tag works and allows the font-color attribute."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <para><style font-color="blue">blue text</style></para>
                    <para><style font-color="blue"><number>5</number></style></para>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    # @raises(XmlValidationError)
    def test_validate_with_number_tag(self):
        """
        Test that the number tag works and checks the type of number.

        This really should fail, oh dear another bad instance.
        """
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <para><number>5x/5</number></para>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_meta_data(self):
        """
        Testing that the meta data part is working as expected.

        Authors is optional. There must be an author child tag.
        Title is not optional but the validator does not actually check that it is present.
        Difficulty is also not optional. This must contain level in the updated validator.
        Language is not optional. Only valid language codes are accepted here: en, en-ZA, af, af-ZA.
        Link is optional and there can be multiple links.
        Link must be self-closing and contain rel and href as attributes
        """
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
                <title>title</title>
                <authors>
                    <author>anon</author>
                </authors>
                <difficulty>
                    1
                </difficulty>
                <language>en-ZA</language>
                <link rel="textbook" href="content://siyavula.com/grade-10/#ESAAN"/>
            </meta>
            <entry>
                <problem>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_quote_tag_block_children(self):
        """Test that the quote tag works with block children."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <quote><para>Some text</para></quote>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_quote_tag_inline_children_no_para(self):
        """Test that the quote tag works with inline children and no para tag."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <quote>Some <emphasis>emphasised</emphasis> text not in a paragraph</quote>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_table_tag_notes_and_latex(self):
        """Test that the table tag works with multiple inline tags."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <html5table>
                        <tbody>
                            <tr>
                                <td><note type="inlinetip">inline tip</note> and
                                <latex>x</latex></td>
                            </tr>
                        </tbody>
                    </html5table>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_table_tag_notes_and_quotes(self):
        """Test that the table tag works with multiple block tags."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <html5table>
                        <tbody>
                            <tr>
                                <td><note type="tip">tip</note> and
                                <quote>quote</quote></td>
                            </tr>
                        </tbody>
                    </html5table>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_table_tag_notes_and_emphasis(self):
        """Test that the table tag works with inline and block tags."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <html5table>
                        <tbody>
                            <tr>
                                <td><note type="inlinetip">inline tip</note> and
                                <emphasis>emphas</emphasis></td>
                            </tr>
                        </tbody>
                    </html5table>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    def test_validate_with_list_tag_notes_and_emphasis(self):
        """Test that the list tag works with inline and block tags."""
        good_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <list>
                        <item><unit_number><number>5</number><unit>h</unit></unit_number> and
                        <note type="inlinetip">emphas</note></item>
                    </list>
                </problem>
                <solution>
                </solution>
            </entry>
        </exercise-container>"""
        )

        assert self.exercise_validator.validate(good_template_dom) is None

    @raises(XmlValidationError)
    def test_validate_book_tag_is_invalid(self):
        """
        This tests that using a tag specific to books gives an error
        """
        bad_template_dom = etree.fromstring(
            """
        <exercise-container>
            <meta>
            </meta>
            <entry>
                <problem>
                    <presentation>
                        <title>The title</title>
                        <url>google.com</url>
                    </presentation>
                </problem>
                <solution>
                    <presentation>
                        <title>The title</title>
                        <url>google.com</url>
                    </presentation>
                </solution>
            </entry>
        </exercise-container>"""
        )

        self.exercise_validator.validate(bad_template_dom)
 def setUp(self):
     self.exercise_validator = ExerciseValidator()
     self.maxDiff = None
class ExerciseValidatorTests(TestCase):
    """
    Test that the ExerciseValidator class correctly validates a given XML structure.

    This assume a specific exercise layout specification.
    """

    def setUp(self):
        self.exercise_validator = ExerciseValidator()
        self.maxDiff = None

    def test_validate_with_valid_xml(self):
        """
        Test the minimum needed elements for a template.

        Response is actually optional since that is not needed for entries in books.
        """
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem></problem>
                <response></response>
                <solution></solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_invalid_xml(self):
        invalid_template_dom = etree.fromstring('<template></template>')

        self.exercise_validator.validate(invalid_template_dom)

        error = self.exercise_validator.errors[0]
        self.assertIn('Child match failed for a /template element', error)
        self.assertIn('((title,)((multi-part,)|(entry,)))', error)
        self.assertIn('<template></template>', error)

    def test_validate_with_meta_tag(self):
        invalid_template_dom = etree.fromstring('''
        <template>
            <meta></meta>
            <entry>
                <problem></problem>
                <solution></solution>
            </entry>
        </template>''')

        self.exercise_validator.validate(invalid_template_dom)

        error = self.exercise_validator.errors[0]
        self.assertIn('Child match failed for a /template element', error)
        self.assertIn("((title,)((multi-part,)|(entry,)))", error)
        self.assertIn(
            '<template>\n'
            '            <meta></meta>\n'
            '            <entry>\n'
            '                <problem></problem>\n'
            '                <solution></solution>\n'
            '            </entry>\n'
            '        </template>', error)

    def test_validate_missing_title(self):
        invalid_template_dom = etree.fromstring('''
        <template>
            <entry>
                <problem></problem>
                <solution></solution>
            </entry>
        </template>''')

        self.exercise_validator.validate(invalid_template_dom)

        error = self.exercise_validator.errors[0]
        self.assertIn('Child match failed for a /template element', error)
        self.assertIn("((title,)((multi-part,)|(entry,)))", error)
        self.assertIn(
            '<template>\n'
            '            <entry>\n'
            '                <problem></problem>\n'
            '                <solution></solution>\n'
            '            </entry>\n'
            '        </template>', error)

    def test_validate_missing_entry(self):
        invalid_template_dom = etree.fromstring('''
        <template>
            <title></title>
        </template>''')

        self.exercise_validator.validate(invalid_template_dom)

        error = self.exercise_validator.errors[0]
        self.assertIn('Child match failed for a /template element', error)
        self.assertIn('((title,)((multi-part,)|(entry,)))', error)
        self.assertIn(
            '<template>\n'
            '            <title></title>\n'
            '        </template>', error)

    def test_validate_title_tag_with_other_elements(self):
        """
        Test validation with a title tag containing other elements.

        Allowed tags are: br, space, newline, chem_compound, correct, currency
        emphasis, latex, link, nth, nuclear_notation, number, percentage
        spec_note, sub, sup, unit_number, unit, input, style, check
        """
        good_template_dom = etree.fromstring('''
        <template>
            <title><latex>x</latex> makes <sup>the</sup> title. '
            '<unit>Units</unit> are needed.</title>
            <entry>
                <problem></problem>
                <response></response>
                <solution></solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_note_tag(self):
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <note type="note"></note>
                </problem>
                <solution>
                    <note type="note"></note>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_note_tag_with_variety_of_typical_subtags(self):
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <note type="note">
                        In-line Elements
                        <number>5</number>
                        <sup>2</sup>
                    </note>
                </problem>
                <solution>
                    <note type="note">
                        Para Elements
                        <list><item>1</item><item>2</item><item>3</item></list>
                        <latex></latex>
                    </note>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_note_tag_with_text(self):
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <note type="note">Note Content</note>
                </problem>
                <solution>
                    <note type="tip">Note Content</note>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_note_tag_with_para(self):
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <note type="note"><para>Note Content</para></note>
                </problem>
                <solution>
                    <note type="tip"><para>Note Content</para></note>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_note_tag_with_no_attribute(self):
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <note>
                    </note>
                </problem>
                <solution>
                    <note>
                    </note>
                </solution>
            </entry>
        </template>''')

        self.exercise_validator.validate(good_template_dom)
        self.assertEqual(
            self.exercise_validator.errors,
            ["Missing attribute 'type' in /template/entry/problem/note",
             "Missing attribute 'type' in /template/entry/solution/note"])

    def test_validate_with_note_tag_with_incorrect_attribute(self):
        bad_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <note type="bob">
                    </note>
                </problem>
                <solution>
                    <note type="bob">
                    </note>
                </solution>
            </entry>
        </template>''')

        self.exercise_validator.validate(bad_template_dom)
        self.assertEqual(
            self.exercise_validator.errors,
            ['Attribute value \'bob\' does not conform to type \'enum'
             '("note","tip","inlinetip","instruction","instructions","examnote")\' in '
             '/template/entry/problem/note',
             'Attribute value \'bob\' does not conform to type \'enum'
             '("note","tip","inlinetip","instruction","instructions","examnote")\' in '
             '/template/entry/solution/note'])

    def test_validate_with_note_tag_with_book_note_attribute(self):
        bad_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <note type="warning">
                    </note>
                </problem>
                <solution>
                    <note type="warning">
                    </note>
                </solution>
            </entry>
        </template>''')

        self.exercise_validator.validate(bad_template_dom)
        self.assertEqual(
            self.exercise_validator.errors,
            ['Attribute value \'warning\' does not conform to type \'enum'
             '("note","tip","inlinetip","instruction","instructions","examnote")\' in '
             '/template/entry/problem/note',
             'Attribute value \'warning\' does not conform to type \'enum'
             '("note","tip","inlinetip","instruction","instructions","examnote")\' in '
             '/template/entry/solution/note'])

    def test_validate_with_nuclear_notation_tag_no_atomic_number(self):
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <nuclear_notation><symbol>He</symbol><mass_number>5</mass_number></nuclear_notation>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_nuclear_notation_tag_no_mass_number(self):
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <nuclear_notation>
                        <symbol>He</symbol>
                        <atomic_number>5</atomic_number>
                    </nuclear_notation>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_nuclear_notation_tag_no_symbol(self):
        """
        Raise an error since the symbol tag should be required.

        The problem lies in the unordered modifier since the spec for that is a hack and matches
        incorrect patterns. This needs to be corrected.
        """
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <nuclear_notation>
                        <atomic_number>He</atomic_number>
                        <mass_number>5</mass_number>
                    </nuclear_notation>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_nuclear_notation_tag_no_children(self):
        """
        Raise an error since nuclear_notation is required to contain at least the symbol tag.

        The problem lies in the unordered modifier since the spec for that is a hack and matches
        incorrect patterns. This needs to be corrected.
        """
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <nuclear_notation></nuclear_notation>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_currency_tag_no_children_no_text(self):
        """Test the currency tag with no children and no text."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <currency></currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_currency_tag_no_children_text(self):
        """Test the currency tag with no children and text."""
        bad_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <currency>R 5</currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.exercise_validator.validate(bad_template_dom)

        error = self.exercise_validator.errors[0]
        self.assertIn('//currency element must not have any text', error)
        self.assertIn('Found at the beginning of the element:', error)
        self.assertIn('R 5', error)
        self.assertIn('<currency>R 5</currency>', error)

    def test_validate_currency_tag_with_only_symbol_child(self):
        """Test the currency tag with only symbol child."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <currency>
                        <symbol>R</symbol>
                    </currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_currency_tag_with_only_number_child(self):
        """Test the currency tag with only number child."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <currency>
                        <number>5</number>
                    </currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_currency_tag_with_both_children(self):
        """Test the currency tag with both children."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <currency>
                        <number>5</number><symbol>R</symbol>
                    </currency>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_pspicture_tag_no_children(self):
        """
        Test validation of pspicture with no child tags.

        This should raise an error since pspicture is required to contain at
        least either src or code child.
        The problem lies in the unordered modifier since the spec
        for that is a hack and matches incorrect patterns.
        This needs to be corrected.
        """
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <pspicture></pspicture>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_tikzpicture_tag_no_children(self):
        """
        Raise an error since tikzpicture is required to contain at least either src or code child.

        The problem lies in the unordered modifier since the spec for that is a hack and matches
        incorrect patterns. This needs to be corrected.
        """
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <tikzpicture></tikzpicture>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_style_tag(self):
        """Test that the style tag works and allows the font-color attribute."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <para><style font-color="blue">blue text</style></para>
                    <para><style font-color="blue"><number>5</number></style></para>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    # @raises(XmlValidationError)
    def test_validate_with_number_tag(self):
        """
        Test that the number tag works and checks the type of number.

        This really should fail, oh dear another bad instance.
        """
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <para><number>5x/5</number></para>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_quote_tag_block_children(self):
        """Test that the quote tag works with block children."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <quote><para>Some text</para></quote>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_quote_tag_inline_children_no_para(self):
        """Test that the quote tag works with inline children and no para tag."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <quote>Some <emphasis>emphasised</emphasis> text not in a paragraph</quote>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_table_tag_notes_and_latex(self):
        """Test that the table tag works with multiple inline tags."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <html5table>
                        <tbody>
                            <tr>
                                <td><note type="inlinetip">inline tip</note> and
                                <latex>x</latex></td>
                            </tr>
                        </tbody>
                    </html5table>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_table_tag_notes_and_quotes(self):
        """Test that the table tag works with multiple block tags."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <html5table>
                        <tbody>
                            <tr>
                                <td><note type="tip">tip</note> and
                                <quote>quote</quote></td>
                            </tr>
                        </tbody>
                    </html5table>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_table_tag_notes_and_emphasis(self):
        """Test that the table tag works with inline and block tags."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <html5table>
                        <tbody>
                            <tr>
                                <td><note type="inlinetip">inline tip</note> and
                                <emphasis>emphas</emphasis></td>
                            </tr>
                        </tbody>
                    </html5table>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_list_tag_notes_and_emphasis(self):
        """Test that the list tag works with inline and block tags."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <list>
                        <item><unit_number><number>5</number><unit>h</unit></unit_number> and
                        <note type="inlinetip">emphas</note></item>
                    </list>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_check_tag_not_in_latex(self):
        """
        Test that the check tag works with inline and block tags (not latex).

        In this case the check tag is not inside a latex tag.
        """
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <para><check>Some text</check></para>
                    <note type="note">
                        <check/>
                    </note>
                    <list>
                        <item><check> this is correct</check></item>
                    </list>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_with_check_tag_in_latex(self):
        """Test that the check tag works with inline and block latex."""
        good_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <para>
                        <latex>x <check/></latex>
                    </para>
                    <latex display="block">
                        x = 2 <check> for subtraction</check>
                    </latex>
                </problem>
                <solution>
                </solution>
            </entry>
        </template>''')

        self.assertIsNone(self.exercise_validator.validate(good_template_dom))
        self.assertEqual(self.exercise_validator.errors, [])
        self.assertEqual(self.exercise_validator.warnings, [])

    def test_validate_book_tag_is_invalid(self):
        """Test that using a tag specific to books gives an error."""
        bad_template_dom = etree.fromstring('''
        <template>
            <title></title>
            <entry>
                <problem>
                    <presentation>
                        <title>The title</title>
                        <url>google.com</url>
                    </presentation>
                </problem>
                <solution>
                    <presentation>
                        <title>The title</title>
                        <url>google.com</url>
                    </presentation>
                </solution>
            </entry>
        </template>''')

        self.exercise_validator.validate(bad_template_dom)

        error1 = self.exercise_validator.errors[0]
        self.assertIn('Child match failed for a //entry/problem element', error1)
        self.assertIn(
            '((((((((((para,)|(((list,)|(pspicture,)|(tikzpicture,)|(image,)|(html5table,)|'
            '(figure,)|(equation,)|(latex,)|(correct,)|(note,)|(centre,)|'
            '(coordinate,)|(set,)|(interval,)))))|(definition,)|(quote,)|(note,)|(radio,)'
            '|(centre,)|(coordinate,)|(set,)|(interval,)))){,}))|((((((br,)|(space,)'
            '|(newline,)|(chem_compound,)|(correct,)|(currency,)|(emphasis,)|(latex,)'
            '|(link,)|(nth,)|(nuclear_notation,)|(number,)|(percentage,)|(spec_note,)'
            '|(sub,)|(sup,)|(unit_number,)|(unit,)|(input,)|(style,)|(check,)|'
            '(coordinate,)|(set,)|(interval,)))){,}))))', error1)
        self.assertIn(
            '<problem>\n'
            '                    <presentation>\n'
            '                        <title>The title</title>\n'
            '                        <url>google.com</url>\n'
            '                    </presentation>\n'
            '                </problem>', error1)

        error2 = self.exercise_validator.errors[1]
        self.assertIn('Child match failed for a //entry/solution element', error2)
        self.assertIn(
            '((((((step,)|(hint,))){,})|((((((((para,)|(((list,)|(pspicture,)|(tikzpicture,)'
            '|(image,)|(html5table,)|(figure,)|(equation,)|(latex,)|(correct,)|(note,)'
            '|(centre,)|(coordinate,)|(set,)|(interval,)))))|(definition,)|(quote,)'
            '|(note,)|(radio,)|(centre,)|(coordinate,)|(set,)|(interval,)))){,}))|((((((br,)'
            '|(space,)|(newline,)|(chem_compound,)|(correct,)|(currency,)|(emphasis,)'
            '|(latex,)|(link,)|(nth,)|(nuclear_notation,)|(number,)|(percentage,)'
            '|(spec_note,)|(sub,)|(sup,)|(unit_number,)|(unit,)|(input,)|(style,)'
            '|(check,)|(coordinate,)|(set,)|(interval,)))){,}))))', error2)
        self.assertIn(
            '<solution>\n'
            '                    <presentation>\n'
            '                        <title>The title</title>\n'
            '                        <url>google.com</url>\n'
            '                    </presentation>\n'
            '                </solution>', error2)
class RadioButtonValidatorTests(TestCase):
    """Test that ExerciseValidator correctly validates a given XML for the radio buttons."""

    def setUp(self):
        self.exercise_validator = ExerciseValidator()

    def test_validate_with_radio_buttons_without_text(self):
        """validate: None when radio buttons do not have text, i.e. <button></button>."""
        good_template_dom = etree.fromstring('''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button></button>
                                <button></button>
                                <button></button>
                                <button></button>
                                <button></button>
                             </radio>
                        </query>
                        <type>
                            <value>radiobutton</value>
                        </type>
                        <correct>
                            <value>1</value>
                        </correct>
                        <marks>
                            <value>1</value>
                        </marks>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_radio_button_with_text_only(self):
        """validate: None when radio buttons have text only."""
        good_template_dom = etree.fromstring('''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button>
                                    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                </button>
                                <button>
                                    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                </button>
                                <button>
                                    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                </button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_radio_button_with_inline_elements(self):
        """validate: None when radio buttons have inline elements only."""
        good_template_dom = etree.fromstring('''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button>
                                    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
                                    do eiusmod tempor incididunt ut labore et dolore magna.
                                    Number <number>3.14</number> Nth e.g. <nth>1</nth>
                                    Percentages e.g. <percentage>34</percentage> Super- and
                                    subscripts e.g. <sup>up</sup> <sub>down</sub> Units e.g.
                                    <unit>m&#183;s<sup>-1 </sup></unit> Numbers with units e.g.
                                    <unit_number><number>3.14
                                    </number><unit>m&#183;s<sup>-1</sup></unit>
                                    </unit_number> Currency e.g. <currency><number>3.14</number>
                                    </currency> Chemical compound e.g. <chem_compound>H_2O
                                    </chem_compound> Spectroscopic notation e.g.
                                    <spec_note>3s^{2}3p^{5}</spec_note> Nuclear notation e.g.
                                    <nuclear_notation><symbol>Z</symbol><mass_number>x
                                    </mass_number><atomic_number>y</atomic_number>
                                    </nuclear_notation> Emphasis
                                    e.g. <emphasis>boom!</emphasis> Style (font colour) e.g.
                                    <style font-color="red">hypotenuse</style> In-line latex
                                    e.g. <latex>e^{i\pi} + 1 = 0</latex> In-line tip e.g.
                                    <note type="inlinetip">tip your hat</note> Web link e.g.
                                    <link url="www.google.com">Google</link>
                                </button>
                                <button>
                                    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
                                    do eiusmod tempor incididunt ut labore et dolore magna.
                                    Number <number>3.14</number> Nth e.g. <nth>1</nth>
                                    Percentages e.g. <percentage>34</percentage> Super- and
                                    subscripts e.g. <sup>up</sup> <sub>down</sub> Units e.g.
                                    <unit>m&#183;s<sup>-1 </sup></unit> Numbers with units e.g.
                                    <unit_number><number>3.14
                                    </number><unit>m&#183;s<sup>-1</sup></unit>
                                    </unit_number> Currency e.g. <currency><number>3.14</number>
                                    </currency> Chemical compound e.g. <chem_compound>H_2O
                                    </chem_compound> Spectroscopic notation e.g.
                                    <spec_note>3s^{2}3p^{5}</spec_note> Nuclear notation e.g.
                                    <nuclear_notation><symbol>Z</symbol><mass_number>x
                                    </mass_number><atomic_number>y</atomic_number>
                                    </nuclear_notation> Emphasis
                                    e.g. <emphasis>boom!</emphasis> Style (font colour) e.g.
                                    <style font-color="red">hypotenuse</style> In-line latex
                                    e.g. <latex>e^{i\pi} + 1 = 0</latex> In-line tip e.g.
                                    <note type="inlinetip">tip your hat</note> Web link e.g.
                                    <link url="www.google.com">Google</link>
                                </button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_radio_button_with_para_tags_with_text_only(self):
        """validate: None when radio buttons have para tags."""
        good_template_dom = etree.fromstring('''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                    </para>
                                </button>
                                <button>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                    </para>
                                </button>
                                <button>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                    </para>
                                </button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_radio_button_with_multiple_para_tags_with_mixed_content(self):
        """validate: None when radio buttons have multiple para tags with mixed content."""
        good_template_dom = etree.fromstring('''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                    </para>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
                                        do eiusmod tempor incididunt ut labore et dolore magna.
                                        Number <number>3.14</number> Nth e.g. <nth>1</nth>
                                        Percentages e.g. <percentage>34</percentage> Super- and
                                        subscripts e.g. <sup>up</sup> <sub>down</sub> Units e.g.
                                        <unit>m&#183;s<sup>-1 </sup></unit> Numbers with units e.g.
                                        <unit_number><number>3.14
                                        </number><unit>m&#183;s<sup>-1</sup></unit>
                                        </unit_number> Currency e.g. <currency><number>3.14</number>
                                        </currency> Chemical compound e.g. <chem_compound>H_2O
                                        </chem_compound> Spectroscopic notation e.g.
                                        <spec_note>3s^{2}3p^{5}</spec_note> Nuclear notation e.g.
                                        <nuclear_notation><symbol>Z</symbol><mass_number>x
                                        </mass_number><atomic_number>y</atomic_number>
                                        </nuclear_notation> Emphasis
                                        e.g. <emphasis>boom!</emphasis> Style (font colour) e.g.
                                        <style font-color="red">hypotenuse</style> In-line latex
                                        e.g. <latex>e^{i\pi} + 1 = 0</latex> In-line tip e.g.
                                        <note type="inlinetip">tip your hat</note> Web link e.g.
                                        <link url="www.google.com">Google</link>
                                    </para>
                                </button>
                                <button>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                    </para>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
                                        do eiusmod tempor incididunt ut labore et dolore magna.
                                        Number <number>3.14</number> Nth e.g. <nth>1</nth>
                                        Percentages e.g. <percentage>34</percentage> Super- and
                                        subscripts e.g. <sup>up</sup> <sub>down</sub> Units e.g.
                                        <unit>m&#183;s<sup>-1 </sup></unit> Numbers with units e.g.
                                        <unit_number><number>3.14
                                        </number><unit>m&#183;s<sup>-1</sup></unit>
                                        </unit_number> Currency e.g. <currency><number>3.14</number>
                                        </currency> Chemical compound e.g. <chem_compound>H_2O
                                        </chem_compound> Spectroscopic notation e.g.
                                        <spec_note>3s^{2}3p^{5}</spec_note> Nuclear notation e.g.
                                        <nuclear_notation><symbol>Z</symbol><mass_number>x
                                        </mass_number><atomic_number>y</atomic_number>
                                        </nuclear_notation> Emphasis
                                        e.g. <emphasis>boom!</emphasis> Style (font colour) e.g.
                                        <style font-color="red">hypotenuse</style> In-line latex
                                        e.g. <latex>e^{i\pi} + 1 = 0</latex> In-line tip e.g.
                                        <note type="inlinetip">tip your hat</note> Web link e.g.
                                        <link url="www.google.com">Google</link>
                                    </para>
                                </button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_radio_button_with_latex_block_elements(self):
        """validate: None when radio buttons have latex block elements."""
        good_template_dom = etree.fromstring(r'''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button>
                                    <latex display="block">
                                        \begin{aligned}
                                             z &amp; = 5x^5 + 4x^4 - 3xy^2 - 6y^{\frac{2}{3}} \\
                                               &amp; = 3x
                                        \end{aligned}
                                    </latex>
                                </button>
                                <button>
                                    <latex display="block">
                                        \begin{aligned}
                                             z &amp; = 5x^5 + 4x^4 - 3xy^2 - 6y^{\frac{2}{3}} \\
                                               &amp; = 3x^{\frac{3}{5}}
                                        \end{aligned}
                                    </latex>
                                </button>
                                <button>
                                    <latex display="block">
                                        \begin{aligned}
                                             z &amp; = 5x^5 + 4x^4 - 3xy^2 - 6y^{\frac{2}{3}} \\
                                               &amp; = \frac{2}{3}x
                                        \end{aligned}
                                    </latex>
                                </button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_radio_button_with_tikzpicture_images(self):
        """validate: None when radio buttons have tikzpicture images."""
        good_template_dom = etree.fromstring('''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button>
                                    <tikzpicture>
                                        <usepackage>pgfplots</usepackage>
                                        <src>hist_normal.tikz</src>
                                    </tikzpicture>
                                </button>
                                <button>
                                    <tikzpicture>
                                        <usepackage>pgfplots</usepackage>
                                        <src>hist_flat.tikz</src>
                                    </tikzpicture>
                                </button>
                                <button>
                                    <tikzpicture>
                                        <usepackage>pgfplots</usepackage>
                                        <src>hist_right.tikz</src>
                                    </tikzpicture>
                                </button>
                                <button>
                                    <tikzpicture>
                                        <usepackage>pgfplots</usepackage>
                                        <src>hist_left.tikz</src>
                                    </tikzpicture>
                                </button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_radio_button_with_quote_tags(self):
        """validate: None when radio buttons have quote tags."""
        good_template_dom = etree.fromstring('''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button>
                                    <quote>
                                        <emphasis>Something</emphasis> is the thing that defines
                                        the law
                                    </quote>
                                </button>
                                <button>
                                    <quote>
                                        <emphasis>Something</emphasis> is the thing that defines
                                        the law
                                    </quote>
                                </button>
                                <button>
                                    <quote>
                                        <emphasis>Something</emphasis> is the thing that defines
                                        the law
                                    </quote>
                                </button>
                                <button>
                                    <quote>
                                        <emphasis>Something</emphasis> is the thing that defines
                                        the law
                                    </quote>
                                </button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_radio_button_with_different_block_elements(self):
        """validate: None when radio buttons have different block elements."""
        good_template_dom = etree.fromstring(r'''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <radio>
                                <button>
                                    <quote>
                                        <emphasis>Something</emphasis> is the thing that defines
                                        the law
                                    </quote>
                                </button>
                                <button>
                                    <tikzpicture>
                                        <usepackage>pgfplots</usepackage>
                                        <src>hist_normal.tikz</src>
                                    </tikzpicture>
                                </button>
                                <button>
                                    <latex display="block">
                                        \begin{aligned}
                                             z &amp; = 5x^5 + 4x^4 - 3xy^2 - 6y^{\frac{2}{3}} \\
                                               &amp; = 3x
                                        \end{aligned}
                                    </latex>
                                </button>
                                <button>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
                                    </para>
                                    <para>
                                        Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
                                        do eiusmod tempor incididunt ut labore et dolore magna.
                                        Number <number>3.14</number> Nth e.g. <nth>1</nth>
                                        Percentages e.g. <percentage>34</percentage> Super- and
                                        subscripts e.g. <sup>up</sup> <sub>down</sub> Units e.g.
                                        <unit>m&#183;s<sup>-1 </sup></unit> Numbers with units e.g.
                                        <unit_number><number>3.14
                                        </number><unit>m&#183;s<sup>-1</sup></unit>
                                        </unit_number> Currency e.g. <currency><number>3.14</number>
                                        </currency> Chemical compound e.g. <chem_compound>H_2O
                                        </chem_compound> Spectroscopic notation e.g.
                                        <spec_note>3s^{2}3p^{5}</spec_note> Nuclear notation e.g.
                                        <nuclear_notation><symbol>Z</symbol><mass_number>x
                                        </mass_number><atomic_number>y</atomic_number>
                                        </nuclear_notation> Emphasis
                                        e.g. <emphasis>boom!</emphasis> Style (font colour) e.g.
                                        <style font-color="red">hypotenuse</style> In-line latex
                                        e.g. <latex>e^{i\pi} + 1 = 0</latex> In-line tip e.g.
                                        <note type="inlinetip">tip your hat</note> Web link e.g.
                                        <link url="www.google.com">Google</link>
                                    </para>
                                </button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)

    def test_validate_with_query_tag_with_two_response_types_radio_button_and_numeric(self):
        """validate: None when query tags have two response types, one being radio buttons."""
        good_template_dom = etree.fromstring('''
            <exercise-container>
                <meta>
                </meta>
                <entry>
                    <problem>
                    </problem>
                    <response>
                        <query>
                            <para>
                                <latex>y = </latex> <input/>
                            </para>
                            <para>
                                My favourite colour is:
                            </para>
                            <radio>
                                <button>Blue</button>
                                <button>Green</button>
                                <button>Yellow</button>
                                <button>Purple</button>
                            </radio>
                        </query>
                    </response>
                    <solution>
                    </solution>
                </entry>
            </exercise-container>''')

        self.assertEqual(self.exercise_validator.validate(good_template_dom), None)