# coding=utf-8 """ Tests capa util """ import unittest import codejail.safe_exec import ddt from django.test.utils import TestContextDecorator from lxml import etree from xmodule.capa.tests.helpers import mock_capa_system from xmodule.capa.util import ( compare_with_tolerance, contextualize_text, get_inner_html_from_xpath, remove_markup, sanitize_html, ) @ddt.ddt class UtilTest(unittest.TestCase): """Tests for util""" def setUp(self): super().setUp() self.system = mock_capa_system() def test_compare_with_tolerance(self): # pylint: disable=too-many-statements """Test numeric comparison with relative and absolute tolerances.""" # Test default tolerance '0.001%' (it is relative) result = compare_with_tolerance(100.0, 100.0) assert result result = compare_with_tolerance(100.001, 100.0) assert result result = compare_with_tolerance(101.0, 100.0) assert not result # Test absolute percentage tolerance result = compare_with_tolerance(109.9, 100.0, "10%", False) assert result result = compare_with_tolerance(110.1, 100.0, "10%", False) assert not result # Test relative percentage tolerance result = compare_with_tolerance(111.0, 100.0, "10%", True) assert result result = compare_with_tolerance(112.0, 100.0, "10%", True) assert not result # Test absolute tolerance (string) result = compare_with_tolerance(109.9, 100.0, "10.0", False) assert result result = compare_with_tolerance(110.1, 100.0, "10.0", False) assert not result # Test relative tolerance (string) result = compare_with_tolerance(111.0, 100.0, "0.1", True) assert result result = compare_with_tolerance(112.0, 100.0, "0.1", True) assert not result # Test absolute tolerance (float) result = compare_with_tolerance(109.9, 100.0, 10.0, False) assert result result = compare_with_tolerance(110.1, 100.0, 10.0, False) assert not result # Test relative tolerance (float) result = compare_with_tolerance(111.0, 100.0, 0.1, True) assert result result = compare_with_tolerance(112.0, 100.0, 0.1, True) assert not result # Infinite values # infinity = float("Inf") # Test relative tolerance (float) result = compare_with_tolerance(infinity, 100.0, 1.0, True) assert not result result = compare_with_tolerance(100.0, infinity, 1.0, True) assert not result result = compare_with_tolerance(infinity, infinity, 1.0, True) assert result # Test absolute tolerance (float) result = compare_with_tolerance(infinity, 100.0, 1.0, False) assert not result result = compare_with_tolerance(100.0, infinity, 1.0, False) assert not result result = compare_with_tolerance(infinity, infinity, 1.0, False) assert result # Test relative tolerance (string) result = compare_with_tolerance(infinity, 100.0, "1.0", True) assert not result result = compare_with_tolerance(100.0, infinity, "1.0", True) assert not result result = compare_with_tolerance(infinity, infinity, "1.0", True) assert result # Test absolute tolerance (string) result = compare_with_tolerance(infinity, 100.0, "1.0", False) assert not result result = compare_with_tolerance(100.0, infinity, "1.0", False) assert not result result = compare_with_tolerance(infinity, infinity, "1.0", False) assert result # Test absolute tolerance for smaller values result = compare_with_tolerance(100.01, 100.0, 0.01, False) assert result result = compare_with_tolerance(100.001, 100.0, 0.001, False) assert result result = compare_with_tolerance(100.01, 100.0, "0.01%", False) assert result result = compare_with_tolerance(100.002, 100.0, 0.001, False) assert not result result = compare_with_tolerance(0.4, 0.44, 0.01, False) assert not result result = compare_with_tolerance(100.01, 100.0, 0.010, False) assert result # Test complex_number instructor_complex result = compare_with_tolerance(0.4, complex(0.44, 0), 0.01, False) assert not result result = compare_with_tolerance(100.01, complex(100.0, 0), 0.010, False) assert result result = compare_with_tolerance(110.1, complex(100.0, 0), "10.0", False) assert not result result = compare_with_tolerance(111.0, complex(100.0, 0), "10%", True) assert result def test_sanitize_html(self): """ Test for html sanitization with nh3. """ allowed_tags = ["div", "p", "audio", "pre", "span"] for tag in allowed_tags: queue_msg = f"<{tag}>Test message" assert sanitize_html(queue_msg) == queue_msg not_allowed_tag = "script" queue_msg = f"<{not_allowed_tag}>Test message" expected = "" assert sanitize_html(queue_msg) == expected def test_get_inner_html_from_xpath(self): """ Test for getting inner html as string from xpath node. """ xpath_node = etree.XML('aabbcc') assert get_inner_html_from_xpath(xpath_node) == 'aabbcc' def test_remove_markup(self): """ Test for markup removal with nh3. """ assert ( remove_markup("The Truth is Out There & you need to find it") == "The Truth is Out There & you need to find it" ) @ddt.data("When the root level failš the whole hierarchy won’t work anymore.", "あなたあなたあなた") def test_contextualize_text(self, context_value): """Verify that variable substitution works as intended with non-ascii characters.""" key = "answer0" text = "$answer0" context = {key: context_value} contextual_text = contextualize_text(text, context) assert context_value == contextual_text def test_contextualize_text_with_non_ascii_context(self): """Verify that variable substitution works as intended with non-ascii characters.""" key = "あなた$a $b" text = "$" + key context = {"a": "あなたあなたあなた", "b": "あなたhi"} expected_text = "$あなたあなたあなたあなた あなたhi" contextual_text = contextualize_text(text, context) assert expected_text == contextual_text class UseUnsafeCodejail(TestContextDecorator): """ Tell codejail to run in unsafe mode for the scope of the decorator. Use this as a decorator on Django TestCase classes or methods. This is needed because codejail has significant OS-level setup requirements which we don't even attempt to fulfill for unit testing purposes. Running tests in unsafe mode (that is, running code executions in-process, with no sandboxing) is only safe because we control the contents of the unit tests. It's not a perfect replica of how safe mode operates but it's generally good enough for testing the integration and overall behavior. """ def __init__(self): self.old_be_unsafe = None super().__init__() def enable(self): """Enable unsafe mode for codejail within the test scope.""" self.old_be_unsafe = codejail.safe_exec.ALWAYS_BE_UNSAFE codejail.safe_exec.ALWAYS_BE_UNSAFE = True def disable(self): """Restore the previous codejail unsafe mode state.""" codejail.safe_exec.ALWAYS_BE_UNSAFE = self.old_be_unsafe