"""Annotatable block tests"""
from django.test import TestCase
from django.test.utils import override_settings
from lxml import etree
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
from xblock.field_data import DictFieldData
from xblock.fields import ScopeIds
from xmodule import annotatable_block
from . import get_test_system
class _AnnotatableBlockTestCaseBase(TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
sample_xml = '''
Read the text.
Sing,
O goddess,
the anger of Achilles son of Peleus,
that brought countless ills upon the Achaeans. Many a brave soul did it send
hurrying down to Hades, and many a hero did it yield a prey to dogs and
vultures, for so were the counsels
of Jove fulfilled from the day on which the son of Atreus, king of men, and great
Achilles, first fell out with one another.
The Iliad of Homer by Samuel Butler
'''
__test__ = False
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.annotatable_class = annotatable_block.reset_class()
def setUp(self):
super().setUp()
self.annotatable = self.annotatable_class(
get_test_system(),
DictFieldData({'data': self.sample_xml}),
ScopeIds(None, None, None, BlockUsageLocator(CourseLocator('org', 'course', 'run'), 'category', 'name'))
)
def test_annotation_data_attr(self):
el = etree.fromstring('test')
expected_attr = {
'data-comment-body': {'value': 'foo', '_delete': 'body'},
'data-comment-title': {'value': 'bar', '_delete': 'title'},
'data-problem-id': {'value': '0', '_delete': 'problem'}
}
actual_attr = self.annotatable._get_annotation_data_attr(0, el) # lint-amnesty, pylint: disable=protected-access
assert isinstance(actual_attr, dict)
self.assertDictEqual(expected_attr, actual_attr)
def test_annotation_class_attr_default(self):
xml = 'test'
el = etree.fromstring(xml)
expected_attr = {'class': {'value': 'annotatable-span highlight'}}
actual_attr = self.annotatable._get_annotation_class_attr(0, el) # lint-amnesty, pylint: disable=protected-access
assert isinstance(actual_attr, dict)
self.assertDictEqual(expected_attr, actual_attr)
def test_annotation_class_attr_with_valid_highlight(self):
xml = 'test'
for color in self.annotatable.HIGHLIGHT_COLORS:
el = etree.fromstring(xml.format(highlight=color))
value = f'annotatable-span highlight highlight-{color}'
expected_attr = {
'class': {
'value': value,
'_delete': 'highlight'
}
}
actual_attr = self.annotatable._get_annotation_class_attr(0, el) # lint-amnesty, pylint: disable=protected-access
assert isinstance(actual_attr, dict)
self.assertDictEqual(expected_attr, actual_attr)
def test_annotation_class_attr_with_invalid_highlight(self):
xml = 'test'
for invalid_color in ['rainbow', 'blink', 'invisible', '', None]:
el = etree.fromstring(xml.format(highlight=invalid_color))
expected_attr = {
'class': {
'value': 'annotatable-span highlight',
'_delete': 'highlight'
}
}
actual_attr = self.annotatable._get_annotation_class_attr(0, el) # lint-amnesty, pylint: disable=protected-access
assert isinstance(actual_attr, dict)
self.assertDictEqual(expected_attr, actual_attr)
def test_render_annotation(self):
expected_html = 'z' # lint-amnesty, pylint: disable=line-too-long
expected_el = etree.fromstring(expected_html)
actual_el = etree.fromstring('z')
self.annotatable._render_annotation(0, actual_el) # lint-amnesty, pylint: disable=protected-access
assert expected_el.tag == actual_el.tag
assert expected_el.text == actual_el.text
self.assertDictEqual(dict(expected_el.attrib), dict(actual_el.attrib))
def test_render_content(self):
content = self.annotatable._render_content() # lint-amnesty, pylint: disable=protected-access
el = etree.fromstring(content)
assert 'div' == el.tag, 'root tag is a div'
expected_num_annotations = 5
actual_num_annotations = el.xpath('count(//span[contains(@class,"annotatable-span")])')
assert expected_num_annotations == actual_num_annotations, 'check number of annotations'
def test_get_html(self):
context = self.annotatable.get_html()
for key in ['display_name', 'element_id', 'content_html', 'instructions_html']:
assert key in context
def test_extract_instructions(self):
xmltree = etree.fromstring(self.sample_xml)
expected_xml = "Read the text.
"
actual_xml = self.annotatable._extract_instructions(xmltree) # lint-amnesty, pylint: disable=protected-access
assert actual_xml is not None
assert expected_xml.strip() == actual_xml.strip()
xmltree = etree.fromstring('foo')
actual = self.annotatable._extract_instructions(xmltree) # lint-amnesty, pylint: disable=protected-access
assert actual is None
def test_instruction_removal(self):
xmltree = etree.fromstring(self.sample_xml)
instructions = self.annotatable._extract_instructions(xmltree) # pylint: disable=protected-access
assert instructions is not None
assert "Read the text." in instructions
assert xmltree.find("instructions") is None
@override_settings(USE_EXTRACTED_ANNOTATABLE_BLOCK=True)
class ExtractedAnnotatableBlockTestCase(_AnnotatableBlockTestCaseBase):
__test__ = True
@override_settings(USE_EXTRACTED_ANNOTATABLE_BLOCK=False)
class BuiltInAnnotatableBlockTestCase(_AnnotatableBlockTestCaseBase):
__test__ = True