Skip to content

Commit

Permalink
test: Tests are updated for refactored code
Browse files Browse the repository at this point in the history
  • Loading branch information
myhailo-chernyshov-rg committed Jan 7, 2025
1 parent 01f21c5 commit de68907
Show file tree
Hide file tree
Showing 14 changed files with 310 additions and 202 deletions.
20 changes: 10 additions & 10 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from cc2olx.cli import parse_args
from cc2olx.models import Cartridge
from cc2olx.settings import collect_settings
from cc2olx.parser import parse_options


@pytest.fixture(scope="session")
Expand Down Expand Up @@ -77,29 +77,29 @@ def studio_course_xml(fixtures_data_dir):


@pytest.fixture
def settings(imscc_file, link_map_csv):
def options(imscc_file, link_map_csv):
"""
Basic settings fixture.
Basic options fixture.
"""

parsed_args = parse_args(["-i", str(imscc_file), "-f", str(link_map_csv)])
args = parse_args(["-i", str(imscc_file), "-f", str(link_map_csv)])

_settings = collect_settings(parsed_args)
options = parse_options(args)

yield _settings
yield options

shutil.rmtree(_settings["workspace"], ignore_errors=True)
shutil.rmtree(options["workspace"], ignore_errors=True)


@pytest.fixture
def cartridge(imscc_file, settings):
cartridge = Cartridge(imscc_file, settings["workspace"])
def cartridge(imscc_file, options):
cartridge = Cartridge(imscc_file, options["workspace"])
cartridge.load_manifest_extracted()
cartridge.normalize()

yield cartridge

shutil.rmtree(str(settings["workspace"] / imscc_file.stem))
shutil.rmtree(str(options["workspace"] / imscc_file.stem))


@pytest.fixture(scope="session")
Expand Down
24 changes: 22 additions & 2 deletions tests/fixtures_data/studio_course_xml/course.xml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,17 @@
<discussion display_name="Discussion" discussion_category="Discussion Topic" discussion_target="Discussion Topic" url_name="discussion_topic"/>
</vertical>
<vertical display_name="Image File Webcontent" url_name="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
<html display_name="Image File Webcontent" url_name="resource_5_image_file"><![CDATA[<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/></head><body><p><img src="/static/elearning.png" alt="elearning.png"></p></body></html>]]></html>
<html display_name="Image File Webcontent" url_name="resource_5_image_file"><![CDATA[<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<p>
<img src="/static/elearning.png" alt="elearning.png">
</p>
</body>
</html>
]]></html>
</vertical>
<vertical display_name="Wiki Content" url_name="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
<html display_name="Wiki Content" url_name="resource_6_wiki_content"><![CDATA[<html>
Expand Down Expand Up @@ -227,7 +237,17 @@
<video edx_video_id="42d2a5e2-bced-45d6-b8dc-2f5901c9fdd0" display_name="Video With Other Content" url_name="resource_9_video"/>
</vertical>
<vertical display_name="PDF Outside of Web Resources" url_name="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
<html display_name="PDF Outside of Web Resources" url_name="pdf_dependency"><![CDATA[<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/></head><body><p><a href="/static/extra_files/example.pdf" alt="extra_files/example.pdf">extra_files/example.pdf<a></p></body></html>]]></html>
<html display_name="PDF Outside of Web Resources" url_name="pdf_dependency"><![CDATA[<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<p>
<a href="/static/extra_files/example.pdf" alt="extra_files/example.pdf">extra_files/example.pdf<a>
</p>
</body>
</html>
]]></html>
</vertical>
<vertical display_name="Web Link Content" url_name="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx">
<html display_name="Web Link Content" url_name="resource_8_web_link_content"><![CDATA[<a href='http://web-link'>Web Link Content</a>]]></html>
Expand Down
Empty file.
128 changes: 128 additions & 0 deletions tests/test_content_parsers/test_html.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
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())
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)
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)
idref_mock = Mock()

parser._parse_content(idref_mock)

logger_mock.info.assert_called_once_with("Missing resource: %s", idref_mock)

@pytest.mark.parametrize(
"resource_type",
[
"imsbasiclti_xmlv1p2",
"imsbasiclti_xmlv1p3",
"imsqti_xmlv1p3/imscc_xmlv1p1/assessment",
"imsqti_xmlv1p3/imscc_xmlv1p3/assessment",
"imsdt_xmlv1p2",
"imsdt_xmlv1p3",
],
)
@patch("cc2olx.content_parsers.html.HtmlContentParser._parse_web_link_content", Mock(return_value=None))
def test_parse_content_returns_default_content_for_some_other_cc_resource_types(self, resource_type):
cartridge_mock = Mock(define_resource=Mock(return_value={"type": resource_type}))
parser = HtmlContentParser(cartridge_mock)
expected_content = {"html": "<p>MISSING CONTENT</p>"}

actual_content = parser._parse_content(Mock())

assert actual_content == expected_content

@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)

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_res_file_path=Mock(return_value=Path("web_resources/unknown/path/to/file.ext")))
)
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):
res_file_path = Path("web_resources/unknown/path/to/file.ext")
parser = HtmlContentParser(Mock(build_res_file_path=Mock(return_value=res_file_path)))

parser._parse_webcontent(Mock(), MagicMock())

logger_mock.info.assert_called_once_with("Skipping webcontent: %s", res_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())
idref_mock = Mock()
res_file_path_mock = Mock()

with pytest.raises(FileNotFoundError):
parser._parse_webcontent_html_file(idref_mock, res_file_path_mock)

logger_mock.error.assert_called_once_with("Failure reading %s from id %s", res_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())
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
44 changes: 44 additions & 0 deletions tests/test_content_parsers/test_qti.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from unittest.mock import MagicMock, Mock, PropertyMock, call, patch

import pytest

from cc2olx.content_parsers import QtiContentParser
from cc2olx.exceptions import QtiError


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())

with patch("cc2olx.content_parsers.qti.QtiContentParser._parse_problem_profile", return_value=cc_profile):
with pytest.raises(QtiError) as exc_info:
parser._parse_problem(MagicMock(), Mock(), Mock())

assert str(exc_info.value) == f'Unknown cc_profile: "{cc_profile}"'

@patch("cc2olx.content_parsers.qti.logger")
@patch("cc2olx.content_parsers.qti.QtiContentParser._parse_problem_profile")
def test_parse_problem_logs_inability_to_process_problem(self, cc_profile_mock, logger_mock):
parser = QtiContentParser(Mock())
ident_mock = MagicMock()
res_file_path_mock = Mock()
problem_mock = 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.return_value),
call(" At file %s.", res_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.return_value: Mock(side_effect=NotImplementedError)
}

parser._parse_problem(problem_mock, Mock(), res_file_path_mock)

assert logger_mock.info.call_count == 3
assert logger_mock.info.call_args_list == expected_logger_info_call_args_list
24 changes: 24 additions & 0 deletions tests/test_content_parsers/test_video.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from unittest.mock import Mock, patch

from cc2olx.content_parsers import VideoContentParser


class TestVideoContentParser:
def test_parse_content_returns_none_if_there_is_no_resource_identifier(self):
parser = VideoContentParser(Mock())

actual_content = parser._parse_content(None)

assert actual_content is None

@patch(
"cc2olx.content_parsers.video.VideoContentParser._parse_web_link_content",
Mock(return_value={"href": "youtube.com/watch?v=ABCDeF12345"}),
)
def test_parse_content_parses_youtube_link(self):
parser = VideoContentParser(Mock())
expected_content = {"youtube": "ABCDeF12345"}

actual_content = parser._parse_content(Mock())

assert actual_content == expected_content
22 changes: 11 additions & 11 deletions tests/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
from .utils import format_xml


def test_convert_one_file(settings, imscc_file, studio_course_xml):
def test_convert_one_file(options, imscc_file, studio_course_xml):
"""
Tests, that ``convert_one_file`` call for ``imscc`` file results in
tar.gz archive with olx course.
"""
expected_tgz_members_num = 7

convert_one_file(imscc_file, settings["workspace"], settings["link_file"])
convert_one_file(imscc_file, options["workspace"], options["link_file"])

tgz_path = str((imscc_file.parent / "output" / imscc_file.stem).with_suffix(".tar.gz"))

Expand All @@ -28,36 +28,36 @@ def test_convert_one_file(settings, imscc_file, studio_course_xml):
break


def test_main(mocker, imscc_file, settings):
def test_main(mocker, imscc_file, options):
"""
Tests, that invocation of main function results in converted ``.imscc`` file.
"""

mocker.patch("cc2olx.main.parse_args")
mocker.patch("cc2olx.main.collect_settings", return_value=settings)
mocker.patch("cc2olx.main.parse_options", return_value=options)

main()

# workspace has been created
assert settings["workspace"].exists()
assert options["workspace"].exists()

# content of imscc has been extracted
assert (settings["workspace"] / imscc_file.stem).exists()
assert (options["workspace"] / imscc_file.stem).exists()

# archived olx course has been generated
assert (settings["workspace"] / imscc_file.stem).with_suffix(".tar.gz").exists()
assert (options["workspace"] / imscc_file.stem).with_suffix(".tar.gz").exists()


def test_main_zip_output(mocker, settings):
def test_main_zip_output(mocker, options):
"""
Tests, that ``--result zip`` cli option works fine.
"""

settings["output_format"] = RESULT_TYPE_ZIP
options["output_format"] = RESULT_TYPE_ZIP

mocker.patch("cc2olx.main.parse_args")
mocker.patch("cc2olx.main.collect_settings", return_value=settings)
mocker.patch("cc2olx.main.parse_options", return_value=options)

main()

assert settings["workspace"].with_suffix(".zip").exists()
assert options["workspace"].with_suffix(".zip").exists()
Loading

0 comments on commit de68907

Please sign in to comment.