forked from openedx/cc2olx
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: [FC-0063] Content processors are tested
- Loading branch information
1 parent
a4e158e
commit 1c28a30
Showing
18 changed files
with
489 additions
and
323 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
[pytest] | ||
usefixtures = chdir_to_workspace | ||
DJANGO_SETTINGS_MODULE = cc2olx.django_settings | ||
DJANGO_SETTINGS_MODULE = cc2olx.settings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<webLink xmlns="http://www.imsglobal.org/xsd/imsccv1p3/imswl_v1p3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/imsccv1p3/imswl_v1p3 http://www.imsglobal.org/profile/cc/ccv1p3/ccv1p3_imswl_v1p3.xsd"> | ||
<title>Web Link Content</title> | ||
<url href="http://web-link"/> | ||
<url href="/web-link"/> | ||
</webLink> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
from pathlib import Path | ||
from unittest.mock import MagicMock, Mock, patch | ||
|
||
import pytest | ||
|
||
from cc2olx.content_parsers import HtmlContentParser | ||
|
||
|
||
class TestHtmlContentParser: | ||
def test_parse_content_returns_default_content_if_there_is_no_resource_identifier(self): | ||
parser = HtmlContentParser(Mock(), Mock()) | ||
expected_content = {"html": "<p>MISSING CONTENT</p>"} | ||
|
||
actual_content = parser._parse_content(None) | ||
|
||
assert actual_content == expected_content | ||
|
||
def test_parse_content_returns_default_content_if_the_resource_is_missed_in_cartridge(self): | ||
cartridge_mock = Mock(define_resource=Mock(return_value=None)) | ||
parser = HtmlContentParser(cartridge_mock, Mock()) | ||
expected_content = {"html": "<p>MISSING CONTENT</p>"} | ||
|
||
actual_content = parser._parse_content(Mock()) | ||
|
||
assert actual_content == expected_content | ||
|
||
@patch("cc2olx.content_parsers.html.logger") | ||
def test_parse_content_logs_missing_resource(self, logger_mock): | ||
cartridge_mock = Mock(define_resource=Mock(return_value=None)) | ||
parser = HtmlContentParser(cartridge_mock, Mock()) | ||
idref_mock = Mock() | ||
|
||
parser._parse_content(idref_mock) | ||
|
||
logger_mock.info.assert_called_once_with("Missing resource: %s", idref_mock) | ||
|
||
@patch("cc2olx.content_parsers.html.HtmlContentParser._parse_web_link_content", Mock(return_value=None)) | ||
@patch("cc2olx.content_parsers.html.HtmlContentParser.is_known_unprocessed_resource_type", Mock(return_value=True)) | ||
def test_parse_content_returns_default_content_for_known_unprocessed_resource_types(self): | ||
parser = HtmlContentParser(MagicMock(), Mock()) | ||
expected_content = {"html": "<p>MISSING CONTENT</p>"} | ||
|
||
actual_content = parser._parse_content(Mock()) | ||
|
||
assert actual_content == expected_content | ||
|
||
@pytest.mark.parametrize( | ||
"resource_type", | ||
[ | ||
"imsbasiclti_xmlv1p2", | ||
"imsbasiclti_xmlv1p3", | ||
"imsqti_xmlv1p3/imscc_xmlv1p1/assessment", | ||
"imsqti_xmlv1p3/imscc_xmlv1p3/assessment", | ||
"imsdt_xmlv1p2", | ||
"imsdt_xmlv1p3", | ||
], | ||
) | ||
def test_known_unprocessed_resource_types_is_detected(self, resource_type): | ||
parser = HtmlContentParser(Mock(), Mock()) | ||
|
||
assert parser.is_known_unprocessed_resource_type(resource_type) is True | ||
|
||
@pytest.mark.parametrize("resource_type", ["imsbasicabc_xmlv1p2", "imsexample_xmlv1p3", "not_cc_type", "imsscorm"]) | ||
def test_not_known_unprocessed_resource_types_is_detected(self, resource_type): | ||
parser = HtmlContentParser(Mock(), Mock()) | ||
|
||
assert parser.is_known_unprocessed_resource_type(resource_type) is False | ||
|
||
@pytest.mark.parametrize( | ||
"resource_type", | ||
["unsupported_resource_type", "chess_game_xmlv1p1", "drag_and_drop_xmlv1p1", "imsab_xmlv1p2"], | ||
) | ||
@patch("cc2olx.content_parsers.html.HtmlContentParser._parse_web_link_content", Mock(return_value=None)) | ||
@patch("cc2olx.content_parsers.html.HtmlContentParser._parse_not_imported_content") | ||
def test_parse_content_parses_not_imported_content(self, parse_not_imported_content_mock, resource_type): | ||
cartridge_mock = Mock(define_resource=Mock(return_value={"type": "imsqti_xmlv1p2"})) | ||
parser = HtmlContentParser(cartridge_mock, Mock()) | ||
|
||
actual_content = parser._parse_content(Mock()) | ||
|
||
assert actual_content == parse_not_imported_content_mock.return_value | ||
|
||
@patch("cc2olx.content_parsers.html.imghdr.what", Mock(return_value=None)) | ||
def test_parse_webcontent_returns_default_content_for_unknown_webcontent_type_from_web_resources_dir(self): | ||
parser = HtmlContentParser( | ||
Mock(build_resource_file_path=Mock(return_value=Path("web_resources/unknown/path/to/file.ext"))), | ||
Mock(), | ||
) | ||
expected_content = {"html": "<p>MISSING CONTENT</p>"} | ||
|
||
actual_content = parser._parse_webcontent(Mock(), MagicMock()) | ||
|
||
assert actual_content == expected_content | ||
|
||
@patch("cc2olx.content_parsers.html.logger") | ||
@patch("cc2olx.content_parsers.html.imghdr.what", Mock(return_value=None)) | ||
def test_parse_webcontent_logs_skipping_webcontent(self, logger_mock): | ||
resource_file_path = Path("web_resources/unknown/path/to/file.ext") | ||
parser = HtmlContentParser(Mock(build_resource_file_path=Mock(return_value=resource_file_path)), Mock()) | ||
|
||
parser._parse_webcontent(Mock(), MagicMock()) | ||
|
||
logger_mock.info.assert_called_once_with("Skipping webcontent: %s", resource_file_path) | ||
|
||
@patch("cc2olx.content_parsers.html.logger") | ||
@patch("cc2olx.content_parsers.html.open", Mock(side_effect=FileNotFoundError)) | ||
def test_webcontent_html_file_reading_failure_is_logged(self, logger_mock): | ||
parser = HtmlContentParser(Mock(), Mock()) | ||
idref_mock = Mock() | ||
resource_file_path_mock = Mock() | ||
|
||
with pytest.raises(FileNotFoundError): | ||
parser._parse_webcontent_html_file(idref_mock, resource_file_path_mock) | ||
|
||
logger_mock.error.assert_called_once_with("Failure reading %s from id %s", resource_file_path_mock, idref_mock) | ||
|
||
@pytest.mark.parametrize( | ||
"resource,message", | ||
[ | ||
( | ||
{"type": "some_type_mock", "href": "https://example.com/some/type/link/"}, | ||
"Not imported content: type = 'some_type_mock', href = 'https://example.com/some/type/link/'", | ||
), | ||
({"type": "some_type_mock"}, "Not imported content: type = 'some_type_mock'"), | ||
], | ||
) | ||
@patch("cc2olx.content_parsers.html.logger") | ||
def test_not_imported_content_parsing_with_href_in_resource(self, logger_mock, resource, message): | ||
parser = HtmlContentParser(Mock(), Mock()) | ||
expected_content = {"html": message} | ||
|
||
actual_content = parser._parse_not_imported_content(resource) | ||
|
||
logger_mock.info.assert_called_once_with("%s", message) | ||
assert actual_content == expected_content | ||
|
||
def test_parsing_results(self, cartridge): | ||
parser = HtmlContentParser(cartridge, Mock()) | ||
|
||
assert parser.parse("resource_1_course") == { | ||
"html": "Not imported content: type = 'associatedcontent/imscc_xmlv1p1/learning-application-resource', " | ||
"href = 'course_settings/canvas_export.txt'" | ||
} | ||
|
||
assert parser.parse("resource_3_vertical") == { | ||
"html": '<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\n' | ||
"<title>Vertical</title>\n" | ||
'<meta name="identifier" content="resource_3_vertical"/>\n' | ||
'<meta name="editing_roles" content="teachers"/>\n' | ||
'<meta name="workflow_state" content="active"/>\n' | ||
"</head>\n<body>\n" | ||
'<img src="/static/QuizImages/fractal.jpg" alt="fractal.jpg"' | ||
' width="500" height="375" />\n' | ||
"<p>Fractal Image <a " | ||
'href="/static/QuizImages/fractal.jpg?canvas_download=1" ' | ||
'target="_blank">Fractal Image</a></p>\n' | ||
"</body>\n</html>\n" | ||
} | ||
|
||
assert parser.parse("resource_6_wiki_content") == { | ||
"html": '<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\n' | ||
"<title>Vertical</title>\n" | ||
'<meta name="identifier" content="resource_6_wiki_content"/>\n' | ||
'<meta name="editing_roles" content="teachers"/>\n' | ||
'<meta name="workflow_state" content="active"/>\n' | ||
"</head>\n<body>\n" | ||
'<p>Lorem ipsum...</p>\n<a href="/jump_to_id/resource_6_wiki_content">Wiki Content</a>' | ||
"\n</body>\n</html>\n" | ||
} | ||
|
||
assert parser.parse("resource_7_canvas_content") == { | ||
"html": '<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\n' | ||
"<title>Vertical</title>\n" | ||
'<meta name="identifier" content="resource_7_canvas_content"/>\n' | ||
'<meta name="editing_roles" content="teachers"/>\n' | ||
'<meta name="workflow_state" content="active"/>\n' | ||
"</head>\n<body>\n" | ||
'<p>Lorem ipsum...</p>\n<a href="/jump_to_id/abc">Canvas Content</a>' | ||
"\n</body>\n</html>\n" | ||
} | ||
|
||
assert parser.parse("resource_module-|-introduction") == { | ||
"html": '<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>\n' | ||
"<title>Vertical</title>\n" | ||
'<meta name="identifier" content="resource_module-|-introduction"/>\n' | ||
'<meta name="editing_roles" content="teachers"/>\n' | ||
'<meta name="workflow_state" content="active"/>\n' | ||
"</head>\n<body>\n" | ||
'<p>Lorem ipsum...</p>\n<a href="/jump_to_id/resource_6_wiki_content">Wiki Content</a>' | ||
"\n</body>\n</html>\n" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from unittest.mock import Mock | ||
|
||
from cc2olx.content_parsers import LtiContentParser | ||
|
||
|
||
class TestLtiContentParser: | ||
def test_parsing_results(self, cartridge): | ||
parser = LtiContentParser(cartridge, Mock()) | ||
|
||
assert parser.parse("resource_2_lti") == { | ||
"title": "Learning Tools Interoperability", | ||
"description": "https://www.imsglobal.org/activity/learning-tools-interoperability", | ||
"launch_url": "https://lti.local/launch", | ||
"height": "500", | ||
"width": "500", | ||
"custom_parameters": {}, | ||
"lti_id": "learning_tools_interoperability", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from unittest.mock import MagicMock, Mock, PropertyMock, call, patch | ||
|
||
import pytest | ||
|
||
from cc2olx.content_parsers import QtiContentParser | ||
from cc2olx.exceptions import QtiError | ||
|
||
|
||
class TestQtiContentParser: | ||
class TestQtiContentParser: | ||
@pytest.mark.parametrize("cc_profile", ["unknown_profile", "cc.chess.v0p1", "cc.drag_and_drop.v0p1", "123"]) | ||
def test_parse_problem_raises_qti_error_if_cc_profile_is_unknown(self, cc_profile): | ||
parser = QtiContentParser(Mock(), Mock()) | ||
problem_mock = MagicMock(profile=cc_profile) | ||
|
||
with pytest.raises(QtiError) as exc_info: | ||
parser._parse_problem(problem_mock, Mock(), Mock()) | ||
|
||
assert str(exc_info.value) == f'Unknown cc_profile: "{cc_profile}"' | ||
|
||
@patch("cc2olx.content_parsers.qti.logger") | ||
def test_parse_problem_logs_inability_to_process_problem(self, logger_mock): | ||
parser = QtiContentParser(Mock(), Mock()) | ||
ident_mock = MagicMock() | ||
resource_file_path_mock = Mock() | ||
cc_profile_mock = Mock() | ||
problem_mock = Mock(profile=cc_profile_mock, attrib={"ident": ident_mock}) | ||
expected_logger_info_call_args_list = [ | ||
call("Problem with ID %s can't be converted.", ident_mock), | ||
call(" Profile %s is not supported.", cc_profile_mock), | ||
call(" At file %s.", resource_file_path_mock), | ||
] | ||
|
||
with patch( | ||
"cc2olx.content_parsers.qti.QtiContentParser._problem_parsers_map", | ||
new_callable=PropertyMock, | ||
) as problem_parsers_map_mock: | ||
problem_parsers_map_mock.return_value = {cc_profile_mock: Mock(side_effect=NotImplementedError)} | ||
|
||
parser._parse_problem(problem_mock, Mock(), resource_file_path_mock) | ||
|
||
assert logger_mock.info.call_count == 3 | ||
assert logger_mock.info.call_args_list == expected_logger_info_call_args_list |
Oops, something went wrong.