replaced unittest assertions pytest assertions (#26530)
This commit is contained in:
@@ -42,7 +42,7 @@ class TestLazyMod(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
assert module_name not in sys.modules
|
||||
colorsys = LazyModule(module_name)
|
||||
hsv = colorsys.rgb_to_hsv(.3, .4, .2)
|
||||
self.assertEqual(hsv[0], 0.25)
|
||||
assert hsv[0] == 0.25
|
||||
|
||||
def test_dotted(self):
|
||||
# wsgiref is a module with submodules that is not already imported.
|
||||
@@ -54,4 +54,4 @@ class TestLazyMod(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
del sys.modules[module_name]
|
||||
assert module_name not in sys.modules
|
||||
wsgiref_util = LazyModule(module_name)
|
||||
self.assertEqual(wsgiref_util.guess_scheme({}), "http")
|
||||
assert wsgiref_util.guess_scheme({}) == 'http'
|
||||
|
||||
@@ -26,19 +26,19 @@ class TestSafeExec(unittest.TestCase): # lint-amnesty, pylint: disable=missing-
|
||||
def test_set_values(self):
|
||||
g = {}
|
||||
safe_exec("a = 17", g)
|
||||
self.assertEqual(g['a'], 17)
|
||||
assert g['a'] == 17
|
||||
|
||||
def test_division(self):
|
||||
g = {}
|
||||
# Future division: 1/2 is 0.5.
|
||||
safe_exec("a = 1/2", g)
|
||||
self.assertEqual(g['a'], 0.5)
|
||||
assert g['a'] == 0.5
|
||||
|
||||
def test_assumed_imports(self):
|
||||
g = {}
|
||||
# Math is always available.
|
||||
safe_exec("a = int(math.pi)", g)
|
||||
self.assertEqual(g['a'], 3)
|
||||
assert g['a'] == 3
|
||||
|
||||
def test_random_seeding(self):
|
||||
g = {}
|
||||
@@ -47,11 +47,11 @@ class TestSafeExec(unittest.TestCase): # lint-amnesty, pylint: disable=missing-
|
||||
|
||||
# Without a seed, the results are unpredictable
|
||||
safe_exec("rnums = [random.randint(0, 999) for _ in xrange(100)]", g)
|
||||
self.assertNotEqual(g['rnums'], rnums)
|
||||
assert g['rnums'] != rnums
|
||||
|
||||
# With a seed, the results are predictable
|
||||
safe_exec("rnums = [random.randint(0, 999) for _ in xrange(100)]", g, random_seed=17)
|
||||
self.assertEqual(g['rnums'], rnums)
|
||||
assert g['rnums'] == rnums
|
||||
|
||||
def test_random_is_still_importable(self):
|
||||
g = {}
|
||||
@@ -63,7 +63,7 @@ class TestSafeExec(unittest.TestCase): # lint-amnesty, pylint: disable=missing-
|
||||
"import random\n"
|
||||
"rnums = [random.randint(0, 999) for _ in xrange(100)]\n",
|
||||
g, random_seed=17)
|
||||
self.assertEqual(g['rnums'], rnums)
|
||||
assert g['rnums'] == rnums
|
||||
|
||||
def test_python_lib(self):
|
||||
pylib = os.path.dirname(__file__) + "/test_files/pylib"
|
||||
@@ -75,9 +75,9 @@ class TestSafeExec(unittest.TestCase): # lint-amnesty, pylint: disable=missing-
|
||||
|
||||
def test_raising_exceptions(self):
|
||||
g = {}
|
||||
with self.assertRaises(SafeExecException) as cm:
|
||||
with pytest.raises(SafeExecException) as cm:
|
||||
safe_exec("1/0", g)
|
||||
self.assertIn("ZeroDivisionError", text_type(cm.exception))
|
||||
assert 'ZeroDivisionError' in text_type(cm.exception)
|
||||
|
||||
|
||||
class TestSafeOrNot(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -87,7 +87,7 @@ class TestSafeOrNot(unittest.TestCase): # lint-amnesty, pylint: disable=missing
|
||||
pytest.skip()
|
||||
|
||||
g = {}
|
||||
with self.assertRaises(SafeExecException) as cm:
|
||||
with pytest.raises(SafeExecException) as cm:
|
||||
safe_exec("import os; files = os.listdir('/')", g)
|
||||
assert "OSError" in text_type(cm.exception)
|
||||
assert "Permission denied" in text_type(cm.exception)
|
||||
@@ -95,7 +95,7 @@ class TestSafeOrNot(unittest.TestCase): # lint-amnesty, pylint: disable=missing
|
||||
def test_can_do_something_forbidden_if_run_unsafely(self):
|
||||
g = {}
|
||||
safe_exec("import os; files = os.listdir('/')", g, unsafely=True)
|
||||
self.assertEqual(g['files'], os.listdir('/'))
|
||||
assert g['files'] == os.listdir('/')
|
||||
|
||||
|
||||
class TestLimitConfiguration(unittest.TestCase):
|
||||
@@ -199,16 +199,16 @@ class TestSafeExecCaching(unittest.TestCase):
|
||||
|
||||
# Cache miss
|
||||
safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
|
||||
self.assertEqual(g['a'], 3)
|
||||
assert g['a'] == 3
|
||||
# A result has been cached
|
||||
self.assertEqual(list(cache.values())[0], (None, {'a': 3}))
|
||||
assert list(cache.values())[0] == (None, {'a': 3})
|
||||
|
||||
# Fiddle with the cache, then try it again.
|
||||
cache[list(cache.keys())[0]] = (None, {'a': 17})
|
||||
|
||||
g = {}
|
||||
safe_exec("a = int(math.pi)", g, cache=DictCache(cache))
|
||||
self.assertEqual(g['a'], 17)
|
||||
assert g['a'] == 17
|
||||
|
||||
def test_cache_large_code_chunk(self):
|
||||
# Caching used to die on memcache with more than 250 bytes of code.
|
||||
@@ -218,7 +218,7 @@ class TestSafeExecCaching(unittest.TestCase):
|
||||
g = {}
|
||||
cache = {}
|
||||
safe_exec(code, g, cache=DictCache(cache))
|
||||
self.assertEqual(g['a'], 12345)
|
||||
assert g['a'] == 12345
|
||||
|
||||
def test_cache_exceptions(self):
|
||||
# Used to be that running code that raised an exception didn't cache
|
||||
@@ -226,28 +226,28 @@ class TestSafeExecCaching(unittest.TestCase):
|
||||
code = "1/0"
|
||||
g = {}
|
||||
cache = {}
|
||||
with self.assertRaises(SafeExecException):
|
||||
with pytest.raises(SafeExecException):
|
||||
safe_exec(code, g, cache=DictCache(cache))
|
||||
|
||||
# The exception should be in the cache now.
|
||||
self.assertEqual(len(cache), 1)
|
||||
assert len(cache) == 1
|
||||
cache_exc_msg, cache_globals = list(cache.values())[0] # lint-amnesty, pylint: disable=unused-variable
|
||||
self.assertIn("ZeroDivisionError", cache_exc_msg)
|
||||
assert 'ZeroDivisionError' in cache_exc_msg
|
||||
|
||||
# Change the value stored in the cache, the result should change.
|
||||
cache[list(cache.keys())[0]] = ("Hey there!", {})
|
||||
|
||||
with self.assertRaises(SafeExecException):
|
||||
with pytest.raises(SafeExecException):
|
||||
safe_exec(code, g, cache=DictCache(cache))
|
||||
|
||||
self.assertEqual(len(cache), 1)
|
||||
assert len(cache) == 1
|
||||
cache_exc_msg, cache_globals = list(cache.values())[0]
|
||||
self.assertEqual("Hey there!", cache_exc_msg)
|
||||
assert 'Hey there!' == cache_exc_msg
|
||||
|
||||
# Change it again, now no exception!
|
||||
cache[list(cache.keys())[0]] = (None, {'a': 17})
|
||||
safe_exec(code, g, cache=DictCache(cache))
|
||||
self.assertEqual(g['a'], 17)
|
||||
assert g['a'] == 17
|
||||
|
||||
def test_unicode_submission(self):
|
||||
# Check that using non-ASCII unicode does not raise an encoding error.
|
||||
@@ -288,8 +288,8 @@ class TestUpdateHash(unittest.TestCase):
|
||||
del d2[i]
|
||||
|
||||
# Check that our dicts are equal, but with different key order.
|
||||
self.assertEqual(d1, d2)
|
||||
self.assertNotEqual(list(d1.keys()), list(d2.keys()))
|
||||
assert d1 == d2
|
||||
assert list(d1.keys()) != list(d2.keys())
|
||||
|
||||
return d1, d2
|
||||
|
||||
@@ -298,19 +298,19 @@ class TestUpdateHash(unittest.TestCase):
|
||||
h10 = self.hash_obj(10)
|
||||
hs1 = self.hash_obj("1")
|
||||
|
||||
self.assertNotEqual(h1, h10)
|
||||
self.assertNotEqual(h1, hs1)
|
||||
assert h1 != h10
|
||||
assert h1 != hs1
|
||||
|
||||
def test_list_ordering(self):
|
||||
h1 = self.hash_obj({'a': [1, 2, 3]})
|
||||
h2 = self.hash_obj({'a': [3, 2, 1]})
|
||||
self.assertNotEqual(h1, h2)
|
||||
assert h1 != h2
|
||||
|
||||
def test_dict_ordering(self):
|
||||
d1, d2 = self.equal_but_different_dicts()
|
||||
h1 = self.hash_obj(d1)
|
||||
h2 = self.hash_obj(d2)
|
||||
self.assertEqual(h1, h2)
|
||||
assert h1 == h2
|
||||
|
||||
def test_deep_ordering(self):
|
||||
d1, d2 = self.equal_but_different_dicts()
|
||||
@@ -318,7 +318,7 @@ class TestUpdateHash(unittest.TestCase):
|
||||
o2 = {'a': [1, 2, [d2], 3, 4]}
|
||||
h1 = self.hash_obj(o1)
|
||||
h2 = self.hash_obj(o2)
|
||||
self.assertEqual(h1, h2)
|
||||
assert h1 == h2
|
||||
|
||||
|
||||
class TestRealProblems(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -386,4 +386,4 @@ class TestRealProblems(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
""")
|
||||
g = {}
|
||||
safe_exec(code, g)
|
||||
self.assertIn("aVAP", g)
|
||||
assert 'aVAP' in g
|
||||
|
||||
@@ -58,12 +58,12 @@ class CapaAnswerPoolTest(unittest.TestCase):
|
||||
# [('choice_3', u'wrong-3'), ('choice_5', u'correct-2'), ('choice_1', u'wrong-2'), ('choice_4', u'wrong-4')]
|
||||
self.assertRegex(the_html, r"<div>.*\[.*'wrong-3'.*'correct-2'.*'wrong-2'.*'wrong-4'.*\].*</div>")
|
||||
self.assertRegex(the_html, r"<div>\{.*'1_solution_2'.*\}</div>")
|
||||
self.assertEqual(the_html, problem.get_html(), 'should be able to call get_html() twice')
|
||||
assert the_html == problem.get_html(), 'should be able to call get_html() twice'
|
||||
# Check about masking
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertTrue(response.has_answerpool())
|
||||
self.assertEqual(response.unmask_order(), ['choice_3', 'choice_5', 'choice_1', 'choice_4'])
|
||||
assert not response.has_mask()
|
||||
assert response.has_answerpool()
|
||||
assert response.unmask_order() == ['choice_3', 'choice_5', 'choice_1', 'choice_4']
|
||||
|
||||
def test_answer_pool_4_choices_1_multiplechoiceresponse_seed2(self):
|
||||
problem = new_loncapa_problem(self.common_question_xml, seed=9)
|
||||
@@ -73,9 +73,9 @@ class CapaAnswerPoolTest(unittest.TestCase):
|
||||
self.assertRegex(the_html, r"<div>\{.*'1_solution_1'.*\}</div>")
|
||||
# Check about masking
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertTrue(hasattr(response, 'has_answerpool'))
|
||||
self.assertEqual(response.unmask_order(), ['choice_0', 'choice_4', 'choice_3', 'choice_2'])
|
||||
assert not response.has_mask()
|
||||
assert hasattr(response, 'has_answerpool')
|
||||
assert response.unmask_order() == ['choice_0', 'choice_4', 'choice_3', 'choice_2']
|
||||
|
||||
def test_no_answer_pool_4_choices_1_multiplechoiceresponse(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
@@ -117,11 +117,11 @@ class CapaAnswerPoolTest(unittest.TestCase):
|
||||
the_html = problem.get_html()
|
||||
self.assertRegex(the_html, r"<div>.*\[.*'wrong-1'.*'wrong-2'.*'correct-1'.*'wrong-3'.*'wrong-4'.*'correct-2'.*\].*</div>") # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertRegex(the_html, r"<div>\{.*'1_solution_1'.*'1_solution_2'.*\}</div>")
|
||||
self.assertEqual(the_html, problem.get_html(), 'should be able to call get_html() twice')
|
||||
assert the_html == problem.get_html(), 'should be able to call get_html() twice'
|
||||
# Check about masking
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertFalse(response.has_answerpool())
|
||||
assert not response.has_mask()
|
||||
assert not response.has_answerpool()
|
||||
|
||||
def test_0_answer_pool_4_choices_1_multiplechoiceresponse(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
@@ -164,8 +164,8 @@ class CapaAnswerPoolTest(unittest.TestCase):
|
||||
self.assertRegex(the_html, r"<div>.*\[.*'wrong-1'.*'wrong-2'.*'correct-1'.*'wrong-3'.*'wrong-4'.*'correct-2'.*\].*</div>") # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertRegex(the_html, r"<div>\{.*'1_solution_1'.*'1_solution_2'.*\}</div>")
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertFalse(response.has_answerpool())
|
||||
assert not response.has_mask()
|
||||
assert not response.has_answerpool()
|
||||
|
||||
def test_invalid_answer_pool_value(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
@@ -282,8 +282,8 @@ class CapaAnswerPoolTest(unittest.TestCase):
|
||||
self.assertRegex(the_html, r"<div>.*\[.*'correct-2'.*'wrong-1'.*'wrong-2'.*.*'wrong-3'.*'wrong-4'.*\].*</div>")
|
||||
self.assertRegex(the_html, r"<div>\{.*'1_solution_2'.*\}</div>")
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertEqual(response.unmask_order(), ['choice_5', 'choice_0', 'choice_1', 'choice_3', 'choice_4'])
|
||||
assert not response.has_mask()
|
||||
assert response.unmask_order() == ['choice_5', 'choice_0', 'choice_1', 'choice_3', 'choice_4']
|
||||
|
||||
def test_answer_pool_2_multiplechoiceresponses_seed1(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
@@ -543,8 +543,8 @@ class CapaAnswerPoolTest(unittest.TestCase):
|
||||
self.assertRegex(the_html, str1)
|
||||
# attributes *not* present
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertFalse(response.has_answerpool())
|
||||
assert not response.has_mask()
|
||||
assert not response.has_answerpool()
|
||||
|
||||
def test_answer_pool_and_no_answer_pool(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
|
||||
@@ -5,7 +5,7 @@ Test capa problem.
|
||||
|
||||
import textwrap
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import six
|
||||
from lxml import etree
|
||||
@@ -48,17 +48,9 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
""".format(question=question)
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': question,
|
||||
'descriptions': {'description_1_1_1': 'Only the paranoid survive.'}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.assertEqual(len(problem.tree.xpath('//label')), 0)
|
||||
assert problem.problem_data ==\
|
||||
{'1_2_1': {'label': question, 'descriptions': {'description_1_1_1': 'Only the paranoid survive.'}}}
|
||||
assert len(problem.tree.xpath('//label')) == 0
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -85,20 +77,8 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
""".format(question, label_attr)
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': question,
|
||||
'descriptions': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
len(problem.tree.xpath("//*[normalize-space(text())='{}']".format(question))),
|
||||
0
|
||||
)
|
||||
assert problem.problem_data == {'1_2_1': {'label': question, 'descriptions': {}}}
|
||||
assert len(problem.tree.xpath("//*[normalize-space(text())='{}']".format(question))) == 0
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -137,26 +117,10 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
""".format(question1, question2)
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': question1,
|
||||
'descriptions': {}
|
||||
},
|
||||
'1_3_1':
|
||||
{
|
||||
'label': question2,
|
||||
'descriptions': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
assert problem.problem_data ==\
|
||||
{'1_2_1': {'label': question1, 'descriptions': {}}, '1_3_1': {'label': question2, 'descriptions': {}}}
|
||||
for question in (question1, question2):
|
||||
self.assertEqual(
|
||||
len(problem.tree.xpath('//label[text()="{}"]'.format(question))),
|
||||
0
|
||||
)
|
||||
assert len(problem.tree.xpath('//label[text()="{}"]'.format(question))) == 0
|
||||
|
||||
def test_multiple_descriptions(self):
|
||||
"""
|
||||
@@ -176,19 +140,9 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
""".format(desc1, desc2)
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': '___ requires sacrifices.',
|
||||
'descriptions': {
|
||||
'description_1_1_1': desc1,
|
||||
'description_1_1_2': desc2
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
assert problem.problem_data ==\
|
||||
{'1_2_1': {'label': '___ requires sacrifices.',
|
||||
'descriptions': {'description_1_1_1': desc1, 'description_1_1_2': desc2}}}
|
||||
|
||||
def test_additional_answer_is_skipped_from_resulting_html(self):
|
||||
"""Tests that additional_answer element is not present in transformed HTML"""
|
||||
@@ -204,8 +158,8 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
"""
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(len(problem.extracted_tree.xpath('//additional_answer')), 0)
|
||||
self.assertNotIn('additional_answer', problem.get_html())
|
||||
assert len(problem.extracted_tree.xpath('//additional_answer')) == 0
|
||||
assert 'additional_answer' not in problem.get_html()
|
||||
|
||||
def test_non_accessible_inputtype(self):
|
||||
"""
|
||||
@@ -223,18 +177,9 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
""".format(question, question)
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': question,
|
||||
'descriptions': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
assert problem.problem_data == {'1_2_1': {'label': question, 'descriptions': {}}}
|
||||
# <p> tag with question text should not be deleted
|
||||
self.assertEqual(problem.tree.xpath("string(p[text()='{}'])".format(question)), question)
|
||||
assert problem.tree.xpath("string(p[text()='{}'])".format(question)) == question
|
||||
|
||||
def test_label_is_empty_if_no_label_attribute(self):
|
||||
"""
|
||||
@@ -252,16 +197,7 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
""".format(question)
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': '',
|
||||
'descriptions': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
assert problem.problem_data == {'1_2_1': {'label': '', 'descriptions': {}}}
|
||||
|
||||
def test_multiple_questions_problem(self):
|
||||
"""
|
||||
@@ -294,22 +230,12 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
"""
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': 'Select the correct synonym of paranoid?',
|
||||
'descriptions': {'description_1_1_1': 'Only the paranoid survive.'}
|
||||
},
|
||||
'1_3_1':
|
||||
{
|
||||
'label': 'What Apple device competed with the portable CD player?',
|
||||
'descriptions': {'description_1_2_1': 'Device looks like an egg plant.'}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.assertEqual(len(problem.tree.xpath('//label')), 0)
|
||||
assert problem.problem_data ==\
|
||||
{'1_2_1': {'label': 'Select the correct synonym of paranoid?',
|
||||
'descriptions': {'description_1_1_1': 'Only the paranoid survive.'}},
|
||||
'1_3_1': {'label': 'What Apple device competed with the portable CD player?',
|
||||
'descriptions': {'description_1_2_1': 'Device looks like an egg plant.'}}}
|
||||
assert len(problem.tree.xpath('//label')) == 0
|
||||
|
||||
def test_question_title_not_removed_got_children(self):
|
||||
"""
|
||||
@@ -334,20 +260,8 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</problem>
|
||||
""".format(question)
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': '',
|
||||
'descriptions': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
len(problem.tree.xpath('//p/img')),
|
||||
1
|
||||
)
|
||||
assert problem.problem_data == {'1_2_1': {'label': '', 'descriptions': {}}}
|
||||
assert len(problem.tree.xpath('//p/img')) == 1
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -371,23 +285,9 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
""".format(group_label, input1_label, input2_label)
|
||||
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'group_label': group_label,
|
||||
'label': input1_label,
|
||||
'descriptions': {}
|
||||
},
|
||||
'1_2_2':
|
||||
{
|
||||
'group_label': group_label,
|
||||
'label': input2_label,
|
||||
'descriptions': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
assert problem.problem_data ==\
|
||||
{'1_2_1': {'group_label': group_label, 'label': input1_label, 'descriptions': {}},
|
||||
'1_2_2': {'group_label': group_label, 'label': input2_label, 'descriptions': {}}}
|
||||
|
||||
def test_single_inputtypes(self):
|
||||
"""
|
||||
@@ -411,11 +311,11 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
|
||||
# verify that only no multi input group div is present
|
||||
multi_inputs_group = problem_html.xpath('//div[@class="multi-inputs-group"]')
|
||||
self.assertEqual(len(multi_inputs_group), 0)
|
||||
assert len(multi_inputs_group) == 0
|
||||
|
||||
# verify that question is rendered only once
|
||||
question = problem_html.xpath("//*[normalize-space(text())='{}']".format(question))
|
||||
self.assertEqual(len(question), 1)
|
||||
assert len(question) == 1
|
||||
|
||||
def assert_question_tag(self, question1, question2, tag, label_attr=False):
|
||||
"""
|
||||
@@ -449,22 +349,9 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
question2_label_attr=question2_label_attr,
|
||||
)
|
||||
problem = new_loncapa_problem(xml)
|
||||
self.assertEqual(
|
||||
problem.problem_data,
|
||||
{
|
||||
'1_2_1':
|
||||
{
|
||||
'label': question1,
|
||||
'descriptions': {}
|
||||
},
|
||||
'1_3_1':
|
||||
{
|
||||
'label': question2,
|
||||
'descriptions': {}
|
||||
}
|
||||
}
|
||||
)
|
||||
self.assertEqual(len(problem.tree.xpath('//{}'.format(tag))), 0)
|
||||
assert problem.problem_data ==\
|
||||
{'1_2_1': {'label': question1, 'descriptions': {}}, '1_3_1': {'label': question2, 'descriptions': {}}}
|
||||
assert len(problem.tree.xpath('//{}'.format(tag))) == 0
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -505,10 +392,10 @@ class CAPAProblemTest(unittest.TestCase):
|
||||
</optionresponse>
|
||||
</problem>
|
||||
"""
|
||||
with self.assertRaises(LoncapaProblemError):
|
||||
with pytest.raises(LoncapaProblemError):
|
||||
new_loncapa_problem(xml.format(correctness=True))
|
||||
problem = new_loncapa_problem(xml.format(correctness=False))
|
||||
self.assertIsNotNone(problem)
|
||||
assert problem is not None
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -524,7 +411,7 @@ class CAPAMultiInputProblemTest(unittest.TestCase):
|
||||
def assert_problem_data(self, problem_data):
|
||||
"""Verify problem data is in expected state"""
|
||||
for problem_value in six.viewvalues(problem_data):
|
||||
self.assertIsInstance(problem_value['label'], Markup)
|
||||
assert isinstance(problem_value['label'], Markup)
|
||||
|
||||
def assert_problem_html(self, problem_html, group_label, *input_labels):
|
||||
"""
|
||||
@@ -541,24 +428,24 @@ class CAPAMultiInputProblemTest(unittest.TestCase):
|
||||
multi_inputs_group = html.xpath(
|
||||
'//div[@class="wrapper-problem-response"]/div[@class="multi-inputs-group"]'
|
||||
)
|
||||
self.assertEqual(len(multi_inputs_group), 1)
|
||||
assert len(multi_inputs_group) == 1
|
||||
|
||||
if group_label is None:
|
||||
# if multi inputs group label is not present then there shouldn't be `aria-labelledby` attribute
|
||||
self.assertEqual(multi_inputs_group[0].attrib.get('aria-labelledby'), None)
|
||||
assert multi_inputs_group[0].attrib.get('aria-labelledby') is None
|
||||
else:
|
||||
# verify that multi input group label <p> tag exists and its
|
||||
# id matches with correct multi input group aria-labelledby
|
||||
multi_inputs_group_label_id = multi_inputs_group[0].attrib.get('aria-labelledby')
|
||||
multi_inputs_group_label = html.xpath('//p[@id="{}"]'.format(multi_inputs_group_label_id))
|
||||
self.assertEqual(len(multi_inputs_group_label), 1)
|
||||
self.assertEqual(multi_inputs_group_label[0].text, group_label)
|
||||
assert len(multi_inputs_group_label) == 1
|
||||
assert multi_inputs_group_label[0].text == group_label
|
||||
|
||||
# verify that label for each input comes only once
|
||||
for input_label in input_labels:
|
||||
# normalize-space is used to remove whitespace around the text
|
||||
input_label_element = multi_inputs_group[0].xpath('//*[normalize-space(text())="{}"]'.format(input_label))
|
||||
self.assertEqual(len(input_label_element), 1)
|
||||
assert len(input_label_element) == 1
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -646,13 +533,13 @@ class CAPAMultiInputProblemTest(unittest.TestCase):
|
||||
description_ids = multi_inputs_group.attrib.get('aria-describedby', '').split()
|
||||
|
||||
# Verify that number of descriptions matches description_ids
|
||||
self.assertEqual(len(description_ids), len(descriptions))
|
||||
assert len(description_ids) == len(descriptions)
|
||||
|
||||
# For each description, check its order and text is correct
|
||||
for index, description_id in enumerate(description_ids):
|
||||
description_element = multi_inputs_group.xpath('//p[@id="{}"]'.format(description_id))
|
||||
self.assertEqual(len(description_element), 1)
|
||||
self.assertEqual(description_element[0].text, descriptions[index])
|
||||
assert len(description_element) == 1
|
||||
assert description_element[0].text == descriptions[index]
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -678,7 +565,7 @@ class CAPAProblemReportHelpersTest(unittest.TestCase):
|
||||
}
|
||||
}
|
||||
with patch.object(problem, 'problem_data', mock_problem_data):
|
||||
self.assertEqual(problem.find_question_label(answer_id), stripped_label)
|
||||
assert problem.find_question_label(answer_id) == stripped_label
|
||||
|
||||
@ddt.data(None, dict(), [None])
|
||||
def test_find_answer_test_not_implemented(self, current_answer):
|
||||
@@ -718,7 +605,7 @@ class CAPAProblemReportHelpersTest(unittest.TestCase):
|
||||
</problem>
|
||||
"""
|
||||
)
|
||||
self.assertEqual(problem.find_answer_text(answer_id, choice_id), answer_text)
|
||||
assert problem.find_answer_text(answer_id, choice_id) == answer_text
|
||||
|
||||
@ddt.data(
|
||||
# Test for ChoiceResponse
|
||||
@@ -756,7 +643,7 @@ class CAPAProblemReportHelpersTest(unittest.TestCase):
|
||||
</problem>
|
||||
"""
|
||||
)
|
||||
self.assertEqual(problem.find_correct_answer_text(answer_id), answer_text)
|
||||
assert problem.find_correct_answer_text(answer_id) == answer_text
|
||||
|
||||
def test_find_answer_text_textinput(self):
|
||||
problem = new_loncapa_problem(
|
||||
@@ -768,7 +655,7 @@ class CAPAProblemReportHelpersTest(unittest.TestCase):
|
||||
</problem>
|
||||
"""
|
||||
)
|
||||
self.assertEqual(problem.find_answer_text('1_2_1', 'hide'), 'hide')
|
||||
assert problem.find_answer_text('1_2_1', 'hide') == 'hide'
|
||||
|
||||
def test_get_question_answer(self):
|
||||
problem = new_loncapa_problem(
|
||||
@@ -789,4 +676,4 @@ class CAPAProblemReportHelpersTest(unittest.TestCase):
|
||||
|
||||
# Ensure that the answer is a string so that the dict returned from this
|
||||
# function can eventualy be serialized to json without issues.
|
||||
self.assertIsInstance(problem.get_question_answers()['1_solution_1'], six.text_type)
|
||||
assert isinstance(problem.get_question_answers()['1_solution_1'], six.text_type)
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests to verify that CorrectMap behaves correctly
|
||||
|
||||
import datetime
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
from capa.correctmap import CorrectMap
|
||||
|
||||
|
||||
@@ -54,48 +54,48 @@ class CorrectMapTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
# Assert that each input has the expected properties
|
||||
self.assertTrue(self.cmap.is_correct('1_2_1'))
|
||||
self.assertFalse(self.cmap.is_correct('2_2_1'))
|
||||
self.assertTrue(self.cmap.is_correct('3_2_1'))
|
||||
assert self.cmap.is_correct('1_2_1')
|
||||
assert not self.cmap.is_correct('2_2_1')
|
||||
assert self.cmap.is_correct('3_2_1')
|
||||
|
||||
self.assertTrue(self.cmap.is_partially_correct('3_2_1'))
|
||||
self.assertFalse(self.cmap.is_partially_correct('2_2_1'))
|
||||
assert self.cmap.is_partially_correct('3_2_1')
|
||||
assert not self.cmap.is_partially_correct('2_2_1')
|
||||
|
||||
# Intentionally testing an item that's not in cmap.
|
||||
self.assertFalse(self.cmap.is_partially_correct('9_2_1'))
|
||||
assert not self.cmap.is_partially_correct('9_2_1')
|
||||
|
||||
self.assertEqual(self.cmap.get_correctness('1_2_1'), 'correct')
|
||||
self.assertEqual(self.cmap.get_correctness('2_2_1'), 'incorrect')
|
||||
self.assertEqual(self.cmap.get_correctness('3_2_1'), 'partially-correct')
|
||||
assert self.cmap.get_correctness('1_2_1') == 'correct'
|
||||
assert self.cmap.get_correctness('2_2_1') == 'incorrect'
|
||||
assert self.cmap.get_correctness('3_2_1') == 'partially-correct'
|
||||
|
||||
self.assertEqual(self.cmap.get_npoints('1_2_1'), 5)
|
||||
self.assertEqual(self.cmap.get_npoints('2_2_1'), 0)
|
||||
self.assertEqual(self.cmap.get_npoints('3_2_1'), 3)
|
||||
assert self.cmap.get_npoints('1_2_1') == 5
|
||||
assert self.cmap.get_npoints('2_2_1') == 0
|
||||
assert self.cmap.get_npoints('3_2_1') == 3
|
||||
|
||||
self.assertEqual(self.cmap.get_msg('1_2_1'), 'Test message')
|
||||
self.assertEqual(self.cmap.get_msg('2_2_1'), None)
|
||||
assert self.cmap.get_msg('1_2_1') == 'Test message'
|
||||
assert self.cmap.get_msg('2_2_1') is None
|
||||
|
||||
self.assertEqual(self.cmap.get_hint('1_2_1'), 'Test hint')
|
||||
self.assertEqual(self.cmap.get_hint('2_2_1'), None)
|
||||
assert self.cmap.get_hint('1_2_1') == 'Test hint'
|
||||
assert self.cmap.get_hint('2_2_1') is None
|
||||
|
||||
self.assertEqual(self.cmap.get_hintmode('1_2_1'), 'always')
|
||||
self.assertEqual(self.cmap.get_hintmode('2_2_1'), None)
|
||||
assert self.cmap.get_hintmode('1_2_1') == 'always'
|
||||
assert self.cmap.get_hintmode('2_2_1') is None
|
||||
|
||||
self.assertTrue(self.cmap.is_queued('1_2_1'))
|
||||
self.assertFalse(self.cmap.is_queued('2_2_1'))
|
||||
assert self.cmap.is_queued('1_2_1')
|
||||
assert not self.cmap.is_queued('2_2_1')
|
||||
|
||||
self.assertEqual(self.cmap.get_queuetime_str('1_2_1'), '20130228100026')
|
||||
self.assertEqual(self.cmap.get_queuetime_str('2_2_1'), None)
|
||||
assert self.cmap.get_queuetime_str('1_2_1') == '20130228100026'
|
||||
assert self.cmap.get_queuetime_str('2_2_1') is None
|
||||
|
||||
self.assertTrue(self.cmap.is_right_queuekey('1_2_1', 'secretstring'))
|
||||
self.assertFalse(self.cmap.is_right_queuekey('1_2_1', 'invalidstr'))
|
||||
self.assertFalse(self.cmap.is_right_queuekey('1_2_1', ''))
|
||||
self.assertFalse(self.cmap.is_right_queuekey('1_2_1', None))
|
||||
assert self.cmap.is_right_queuekey('1_2_1', 'secretstring')
|
||||
assert not self.cmap.is_right_queuekey('1_2_1', 'invalidstr')
|
||||
assert not self.cmap.is_right_queuekey('1_2_1', '')
|
||||
assert not self.cmap.is_right_queuekey('1_2_1', None)
|
||||
|
||||
self.assertFalse(self.cmap.is_right_queuekey('2_2_1', 'secretstring'))
|
||||
self.assertFalse(self.cmap.is_right_queuekey('2_2_1', 'invalidstr'))
|
||||
self.assertFalse(self.cmap.is_right_queuekey('2_2_1', ''))
|
||||
self.assertFalse(self.cmap.is_right_queuekey('2_2_1', None))
|
||||
assert not self.cmap.is_right_queuekey('2_2_1', 'secretstring')
|
||||
assert not self.cmap.is_right_queuekey('2_2_1', 'invalidstr')
|
||||
assert not self.cmap.is_right_queuekey('2_2_1', '')
|
||||
assert not self.cmap.is_right_queuekey('2_2_1', None)
|
||||
|
||||
def test_get_npoints(self):
|
||||
# Set the correctmap properties for 4 inputs
|
||||
@@ -153,28 +153,28 @@ class CorrectMapTest(unittest.TestCase):
|
||||
# If no points assigned and correct --> 1 point
|
||||
# If no points assigned and partially correct --> 1 point
|
||||
# If no points assigned and incorrect --> 0 points
|
||||
self.assertEqual(self.cmap.get_npoints('1_2_1'), 5.3)
|
||||
self.assertEqual(self.cmap.get_npoints('2_2_1'), 1)
|
||||
self.assertEqual(self.cmap.get_npoints('3_2_1'), 5)
|
||||
self.assertEqual(self.cmap.get_npoints('4_2_1'), 0)
|
||||
self.assertEqual(self.cmap.get_npoints('5_2_1'), 0)
|
||||
self.assertEqual(self.cmap.get_npoints('6_2_1'), 2.5)
|
||||
self.assertEqual(self.cmap.get_npoints('7_2_1'), 1)
|
||||
assert self.cmap.get_npoints('1_2_1') == 5.3
|
||||
assert self.cmap.get_npoints('2_2_1') == 1
|
||||
assert self.cmap.get_npoints('3_2_1') == 5
|
||||
assert self.cmap.get_npoints('4_2_1') == 0
|
||||
assert self.cmap.get_npoints('5_2_1') == 0
|
||||
assert self.cmap.get_npoints('6_2_1') == 2.5
|
||||
assert self.cmap.get_npoints('7_2_1') == 1
|
||||
|
||||
def test_set_overall_message(self):
|
||||
|
||||
# Default is an empty string string
|
||||
self.assertEqual(self.cmap.get_overall_message(), "")
|
||||
assert self.cmap.get_overall_message() == ''
|
||||
|
||||
# Set a message that applies to the whole question
|
||||
self.cmap.set_overall_message("Test message")
|
||||
|
||||
# Retrieve the message
|
||||
self.assertEqual(self.cmap.get_overall_message(), "Test message")
|
||||
assert self.cmap.get_overall_message() == 'Test message'
|
||||
|
||||
# Setting the message to None --> empty string
|
||||
self.cmap.set_overall_message(None)
|
||||
self.assertEqual(self.cmap.get_overall_message(), "")
|
||||
assert self.cmap.get_overall_message() == ''
|
||||
|
||||
def test_update_from_correctmap(self):
|
||||
# Initialize a CorrectMap with some properties
|
||||
@@ -199,15 +199,9 @@ class CorrectMapTest(unittest.TestCase):
|
||||
other_cmap.update(self.cmap)
|
||||
|
||||
# Assert that it has all the same properties
|
||||
self.assertEqual(
|
||||
other_cmap.get_overall_message(),
|
||||
self.cmap.get_overall_message()
|
||||
)
|
||||
assert other_cmap.get_overall_message() == self.cmap.get_overall_message()
|
||||
|
||||
self.assertEqual(
|
||||
other_cmap.get_dict(),
|
||||
self.cmap.get_dict()
|
||||
)
|
||||
assert other_cmap.get_dict() == self.cmap.get_dict()
|
||||
|
||||
def test_update_from_invalid(self):
|
||||
# Should get an exception if we try to update() a CorrectMap
|
||||
@@ -215,7 +209,7 @@ class CorrectMapTest(unittest.TestCase):
|
||||
invalid_list = [None, "string", 5, datetime.datetime.today()]
|
||||
|
||||
for invalid in invalid_list:
|
||||
with self.assertRaises(Exception):
|
||||
with pytest.raises(Exception):
|
||||
self.cmap.update(invalid)
|
||||
|
||||
def test_set_none_state(self):
|
||||
@@ -226,4 +220,4 @@ class CorrectMapTest(unittest.TestCase):
|
||||
invalid_list = [None, "", False, 0]
|
||||
for invalid in invalid_list:
|
||||
self.cmap.set_dict(invalid)
|
||||
self.assertEqual(self.cmap.get_dict(), {})
|
||||
assert self.cmap.get_dict() == {}
|
||||
|
||||
@@ -30,7 +30,7 @@ class HelperTest(unittest.TestCase):
|
||||
'''
|
||||
def check(self, d):
|
||||
xml = etree.XML(test_capa_system().render_template('blah', d))
|
||||
self.assertEqual(d, extract_context(xml))
|
||||
assert d == extract_context(xml)
|
||||
|
||||
def test_extract_context(self):
|
||||
self.check({})
|
||||
@@ -51,12 +51,12 @@ class SolutionRenderTest(unittest.TestCase):
|
||||
|
||||
renderer = lookup_tag('solution')(test_capa_system(), element)
|
||||
|
||||
self.assertEqual(renderer.id, 'solution_12')
|
||||
assert renderer.id == 'solution_12'
|
||||
|
||||
# Our test_capa_system "renders" templates to a div with the repr of the context.
|
||||
xml = renderer.get_html()
|
||||
context = extract_context(xml)
|
||||
self.assertEqual(context, {'id': 'solution_12'})
|
||||
assert context == {'id': 'solution_12'}
|
||||
|
||||
|
||||
class MathRenderTest(unittest.TestCase):
|
||||
@@ -70,7 +70,7 @@ class MathRenderTest(unittest.TestCase):
|
||||
|
||||
renderer = lookup_tag('math')(test_capa_system(), element)
|
||||
|
||||
self.assertEqual(renderer.mathstr, mathjax_out)
|
||||
assert renderer.mathstr == mathjax_out
|
||||
|
||||
def test_parsing(self):
|
||||
self.check_parse('$abc$', '[mathjaxinline]abc[/mathjaxinline]')
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests of extended hints
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
from ddt import data, ddt, unpack
|
||||
|
||||
from capa.tests.helpers import load_fixture, new_loncapa_problem
|
||||
@@ -89,7 +89,7 @@ class TextInputHintsTest(HintTest):
|
||||
@unpack
|
||||
def test_text_input_hints(self, problem_id, choice, expected_string):
|
||||
hint = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(hint, expected_string)
|
||||
assert hint == expected_string
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -121,7 +121,7 @@ class TextInputExtendedHintsCaseInsensitive(HintTest):
|
||||
@unpack
|
||||
def test_text_input_hints(self, problem_id, choice, expected_string):
|
||||
hint = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(hint, expected_string)
|
||||
assert hint == expected_string
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -149,7 +149,7 @@ class TextInputExtendedHintsCaseSensitive(HintTest):
|
||||
@unpack
|
||||
def test_text_input_hints(self, problem_id, choice, expected_string):
|
||||
message_text = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(message_text, expected_string)
|
||||
assert message_text == expected_string
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -173,8 +173,8 @@ class TextInputExtendedHintsCompatible(HintTest):
|
||||
@unpack
|
||||
def test_text_input_hints(self, problem_id, choice, correct, expected_string):
|
||||
message_text = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(message_text, expected_string)
|
||||
self.assertEqual(self.correctness(problem_id, choice), correct)
|
||||
assert message_text == expected_string
|
||||
assert self.correctness(problem_id, choice) == correct
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -209,8 +209,8 @@ class TextInputExtendedHintsRegex(HintTest):
|
||||
@unpack
|
||||
def test_text_input_hints(self, problem_id, choice, correct, expected_string):
|
||||
message_text = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(message_text, expected_string)
|
||||
self.assertEqual(self.correctness(problem_id, choice), correct)
|
||||
assert message_text == expected_string
|
||||
assert self.correctness(problem_id, choice) == correct
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -250,7 +250,7 @@ class NumericInputHintsTest(HintTest):
|
||||
@unpack
|
||||
def test_numeric_input_hints(self, problem_id, choice, expected_string):
|
||||
hint = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(hint, expected_string)
|
||||
assert hint == expected_string
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -329,7 +329,7 @@ class CheckboxHintsTest(HintTest):
|
||||
def test_checkbox_hints(self, problem_id, choice, expected_string):
|
||||
self.maxDiff = None # pylint: disable=invalid-name
|
||||
hint = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(hint, expected_string)
|
||||
assert hint == expected_string
|
||||
|
||||
|
||||
class CheckboxHintsTestTracking(HintTest):
|
||||
@@ -449,7 +449,7 @@ class MultpleChoiceHintsTest(HintTest):
|
||||
@unpack
|
||||
def test_multiplechoice_hints(self, problem_id, choice, expected_string):
|
||||
hint = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(hint, expected_string)
|
||||
assert hint == expected_string
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -483,7 +483,7 @@ class MultpleChoiceHintsWithHtmlTest(HintTest):
|
||||
@unpack
|
||||
def test_multiplechoice_hints(self, problem_id, choice, expected_string):
|
||||
hint = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(hint, expected_string)
|
||||
assert hint == expected_string
|
||||
|
||||
|
||||
@ddt
|
||||
@@ -530,7 +530,7 @@ class DropdownHintsTest(HintTest):
|
||||
@unpack
|
||||
def test_dropdown_hints(self, problem_id, choice, expected_string):
|
||||
hint = self.get_hint(problem_id, choice)
|
||||
self.assertEqual(hint, expected_string)
|
||||
assert hint == expected_string
|
||||
|
||||
|
||||
class ErrorConditionsTest(HintTest):
|
||||
@@ -539,5 +539,5 @@ class ErrorConditionsTest(HintTest):
|
||||
"""
|
||||
def test_error_conditions_illegal_element(self):
|
||||
xml_with_errors = load_fixture('extended_hints_with_errors.xml')
|
||||
with self.assertRaises(Exception):
|
||||
with pytest.raises(Exception):
|
||||
new_loncapa_problem(xml_with_errors) # this problem is improperly constructed
|
||||
|
||||
@@ -65,8 +65,8 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
|
||||
# Expect that the include file was embedded in the problem
|
||||
test_element = rendered_html.find("test")
|
||||
self.assertEqual(test_element.tag, "test")
|
||||
self.assertEqual(test_element.text, "Test include")
|
||||
assert test_element.tag == 'test'
|
||||
assert test_element.text == 'Test include'
|
||||
|
||||
def test_process_outtext(self):
|
||||
# Generate some XML with <startouttext /> and <endouttext />
|
||||
@@ -85,7 +85,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
# Expect that the <startouttext /> and <endouttext />
|
||||
# were converted to <span></span> tags
|
||||
span_element = rendered_html.find('span')
|
||||
self.assertEqual(span_element.text, 'Test text')
|
||||
assert span_element.text == 'Test text'
|
||||
|
||||
def test_anonymous_student_id(self):
|
||||
# make sure anonymous_student_id is rendered properly as a context variable
|
||||
@@ -103,7 +103,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
|
||||
# Expect that the anonymous_student_id was converted to "student"
|
||||
span_element = rendered_html.find('span')
|
||||
self.assertEqual(span_element.text, 'Welcome student')
|
||||
assert span_element.text == 'Welcome student'
|
||||
|
||||
def test_render_script(self):
|
||||
# Generate some XML with a <script> tag
|
||||
@@ -121,7 +121,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
|
||||
# Expect that the script element has been removed from the rendered HTML
|
||||
script_element = rendered_html.find('script')
|
||||
self.assertEqual(None, script_element)
|
||||
assert script_element is None
|
||||
|
||||
def test_render_javascript(self):
|
||||
# Generate some XML with a <script> tag
|
||||
@@ -138,10 +138,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
rendered_html = etree.XML(problem.get_html())
|
||||
|
||||
# expect the javascript is still present in the rendered html
|
||||
self.assertIn(
|
||||
"<script type=\"text/javascript\">function(){}</script>",
|
||||
etree.tostring(rendered_html).decode('utf-8')
|
||||
)
|
||||
assert '<script type="text/javascript">function(){}</script>' in etree.tostring(rendered_html).decode('utf-8')
|
||||
|
||||
def test_render_response_xml(self):
|
||||
# Generate some XML for a string response
|
||||
@@ -162,23 +159,23 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
problem = new_loncapa_problem(xml_str, capa_system=the_system)
|
||||
rendered_html = etree.XML(problem.get_html())
|
||||
# Expect problem has been turned into a <div>
|
||||
self.assertEqual(rendered_html.tag, "div")
|
||||
assert rendered_html.tag == 'div'
|
||||
|
||||
# Expect that the response has been turned into a <div> with correct attributes
|
||||
response_element = rendered_html.find('div')
|
||||
|
||||
self.assertEqual(response_element.tag, "div")
|
||||
self.assertEqual(response_element.attrib["aria-label"], "Question 1")
|
||||
assert response_element.tag == 'div'
|
||||
assert response_element.attrib['aria-label'] == 'Question 1'
|
||||
|
||||
# Expect that the response div.wrapper-problem-response
|
||||
# that contains a <div> for the textline
|
||||
textline_element = response_element.find('div')
|
||||
self.assertEqual(textline_element.text, 'Input Template Render')
|
||||
assert textline_element.text == 'Input Template Render'
|
||||
|
||||
# Expect a child <div> for the solution
|
||||
# with the rendered template
|
||||
solution_element = rendered_html.xpath('//div[@class="input-template-render"]')[0]
|
||||
self.assertEqual(solution_element.text, 'Input Template Render')
|
||||
assert solution_element.text == 'Input Template Render'
|
||||
|
||||
# Expect that the template renderer was called with the correct
|
||||
# arguments, once for the textline input and once for
|
||||
@@ -208,10 +205,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
mock.call('solutionspan.html', expected_solution_context)
|
||||
]
|
||||
|
||||
self.assertEqual(
|
||||
the_system.render_template.call_args_list,
|
||||
expected_calls
|
||||
)
|
||||
assert the_system.render_template.call_args_list == expected_calls
|
||||
|
||||
def test_correct_aria_label(self):
|
||||
xml = """
|
||||
@@ -233,8 +227,8 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
problem = new_loncapa_problem(xml)
|
||||
rendered_html = etree.XML(problem.get_html())
|
||||
response_elements = rendered_html.findall('div')
|
||||
self.assertEqual(response_elements[0].attrib['aria-label'], 'Question 1')
|
||||
self.assertEqual(response_elements[1].attrib['aria-label'], 'Question 2')
|
||||
assert response_elements[0].attrib['aria-label'] == 'Question 1'
|
||||
assert response_elements[1].attrib['aria-label'] == 'Question 2'
|
||||
|
||||
def test_render_response_with_overall_msg(self):
|
||||
# CustomResponse script that sets an overall_message
|
||||
@@ -261,16 +255,16 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
# Expect that there is a <div> within the response <div>
|
||||
# with css class response_message
|
||||
msg_div_element = rendered_html.find(".//div[@class='response_message']")
|
||||
self.assertEqual(msg_div_element.tag, "div")
|
||||
self.assertEqual(msg_div_element.get('class'), "response_message")
|
||||
assert msg_div_element.tag == 'div'
|
||||
assert msg_div_element.get('class') == 'response_message'
|
||||
|
||||
# Expect that the <div> contains our message (as part of the XML tree)
|
||||
msg_p_elements = msg_div_element.findall('p')
|
||||
self.assertEqual(msg_p_elements[0].tag, "p")
|
||||
self.assertEqual(msg_p_elements[0].text, "Test message 1")
|
||||
assert msg_p_elements[0].tag == 'p'
|
||||
assert msg_p_elements[0].text == 'Test message 1'
|
||||
|
||||
self.assertEqual(msg_p_elements[1].tag, "p")
|
||||
self.assertEqual(msg_p_elements[1].text, "Test message 2")
|
||||
assert msg_p_elements[1].tag == 'p'
|
||||
assert msg_p_elements[1].text == 'Test message 2'
|
||||
|
||||
def test_substitute_python_vars(self):
|
||||
# Generate some XML with Python variables defined in a script
|
||||
@@ -288,7 +282,7 @@ class CapaHtmlRenderTest(unittest.TestCase):
|
||||
|
||||
# Expect that the variable $test has been replaced with its value
|
||||
span_element = rendered_html.find('span')
|
||||
self.assertEqual(span_element.get('attr'), "TEST")
|
||||
assert span_element.get('attr') == 'TEST'
|
||||
|
||||
def test_xml_comments_and_other_odd_things(self):
|
||||
# Comments and processing instructions should be skipped.
|
||||
|
||||
@@ -91,7 +91,7 @@ class TemplateTestCase(unittest.TestCase):
|
||||
message = ("XML does not have %d match(es) for xpath '%s'\nXML: %s\nContext: %s"
|
||||
% (exact_num, str(xpath), etree.tostring(xml_root), str(context_dict)))
|
||||
|
||||
self.assertEqual(len(xml_root.xpath(xpath)), exact_num, msg=message)
|
||||
assert len(xml_root.xpath(xpath)) == exact_num, message
|
||||
|
||||
def assert_no_xpath(self, xml_root, xpath, context_dict):
|
||||
"""
|
||||
@@ -117,12 +117,11 @@ class TemplateTestCase(unittest.TestCase):
|
||||
If no elements are found, the assertion fails.
|
||||
"""
|
||||
element_list = xml_root.xpath(xpath)
|
||||
self.assertGreater(len(element_list), 0, "Could not find element at '%s'\n%s" %
|
||||
(str(xpath), etree.tostring(xml_root)))
|
||||
assert len(element_list) > 0, ("Could not find element at '%s'\n%s" % (str(xpath), etree.tostring(xml_root)))
|
||||
if exact:
|
||||
self.assertEqual(text, element_list[0].text.strip())
|
||||
assert text == element_list[0].text.strip()
|
||||
else:
|
||||
self.assertIn(text, element_list[0].text.strip())
|
||||
assert text in element_list[0].text.strip()
|
||||
|
||||
def assert_description(self, describedby_xpaths):
|
||||
"""
|
||||
@@ -137,17 +136,17 @@ class TemplateTestCase(unittest.TestCase):
|
||||
descriptions = OrderedDict(
|
||||
(tag.get('id'), stringify_children(tag)) for tag in xml.xpath('//p[@class="question-description"]')
|
||||
)
|
||||
self.assertEqual(self.DESCRIPTIONS, descriptions)
|
||||
assert self.DESCRIPTIONS == descriptions
|
||||
|
||||
# for each xpath verify that description_ids are set correctly
|
||||
for describedby_xpath in describedby_xpaths:
|
||||
describedbys = xml.xpath(describedby_xpath)
|
||||
|
||||
# aria-describedby attributes must have ids
|
||||
self.assertTrue(describedbys)
|
||||
assert describedbys
|
||||
|
||||
for describedby in describedbys:
|
||||
self.assertEqual(describedby, self.DESCRIPTION_IDS)
|
||||
assert describedby == self.DESCRIPTION_IDS
|
||||
|
||||
def assert_describedby_attribute(self, describedby_xpaths):
|
||||
"""
|
||||
@@ -162,7 +161,7 @@ class TemplateTestCase(unittest.TestCase):
|
||||
# for each xpath verify that description_ids are set correctly
|
||||
for describedby_xpath in describedby_xpaths:
|
||||
describedbys = xml.xpath(describedby_xpath)
|
||||
self.assertFalse(describedbys)
|
||||
assert not describedbys
|
||||
|
||||
def assert_status(self, status_div=False, status_class=False):
|
||||
"""
|
||||
@@ -234,8 +233,8 @@ class TemplateTestCase(unittest.TestCase):
|
||||
self.assert_has_xpath(xml, "//*[@aria-label='%s']" % label['expected'], self.context)
|
||||
else:
|
||||
element_list = xml.xpath(xpath)
|
||||
self.assertEqual(len(element_list), 1)
|
||||
self.assertEqual(stringify_children(element_list[0]), label['actual'])
|
||||
assert len(element_list) == 1
|
||||
assert stringify_children(element_list[0]) == label['actual']
|
||||
|
||||
|
||||
class ChoiceGroupTemplateTest(TemplateTestCase):
|
||||
|
||||
@@ -24,6 +24,7 @@ import unittest
|
||||
import xml.sax.saxutils as saxutils
|
||||
from collections import OrderedDict
|
||||
|
||||
import pytest
|
||||
import six
|
||||
from lxml import etree
|
||||
from lxml.html import fromstring
|
||||
@@ -88,7 +89,7 @@ class OptionInputTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id='sky_input')
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_option_parsing(self):
|
||||
f = inputtypes.OptionInput.parse_options
|
||||
@@ -98,7 +99,7 @@ class OptionInputTest(unittest.TestCase):
|
||||
Take list of options, confirm that output is in the silly doubled format
|
||||
"""
|
||||
expected = [(o, o) for o in options]
|
||||
self.assertEqual(f(input), expected)
|
||||
assert f(input) == expected
|
||||
|
||||
check("('a','b')", ['a', 'b'])
|
||||
check("('a', 'b')", ['a', 'b'])
|
||||
@@ -159,7 +160,7 @@ class ChoiceGroupTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id='sky_input')
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_choicegroup(self):
|
||||
self.check_group('choicegroup', 'radio', '')
|
||||
@@ -251,7 +252,7 @@ class JSInputTest(unittest.TestCase):
|
||||
}
|
||||
full_expected_context.update(expected_context)
|
||||
|
||||
self.assertEqual(full_expected_context, context)
|
||||
assert full_expected_context == context
|
||||
|
||||
|
||||
class TextLineTest(unittest.TestCase):
|
||||
@@ -288,7 +289,7 @@ class TextLineTest(unittest.TestCase):
|
||||
'response_data': RESPONSE_DATA,
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_math_rendering(self):
|
||||
size = "42"
|
||||
@@ -327,7 +328,7 @@ class TextLineTest(unittest.TestCase):
|
||||
'response_data': RESPONSE_DATA,
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_trailing_text_rendering(self):
|
||||
size = "42"
|
||||
@@ -372,7 +373,7 @@ class TextLineTest(unittest.TestCase):
|
||||
'response_data': RESPONSE_DATA,
|
||||
'describedby_html': TRAILING_TEXT_DESCRIBEDBY.format(trailing_text_id=prob_id, status_id=prob_id)
|
||||
}
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
|
||||
class FileSubmissionTest(unittest.TestCase):
|
||||
@@ -416,7 +417,7 @@ class FileSubmissionTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
|
||||
class CodeInputTest(unittest.TestCase):
|
||||
@@ -472,7 +473,7 @@ class CodeInputTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
|
||||
class MatlabTest(unittest.TestCase):
|
||||
@@ -534,7 +535,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'describedby_html': HTML('aria-describedby="status_prob_1_2"')
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_rendering_with_state(self):
|
||||
state = {
|
||||
@@ -569,7 +570,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_rendering_when_completed(self):
|
||||
for status in ['correct', 'incorrect']:
|
||||
@@ -603,7 +604,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
@patch('capa.inputtypes.time.time', return_value=10)
|
||||
def test_rendering_while_queued(self, time): # lint-amnesty, pylint: disable=unused-argument
|
||||
@@ -637,7 +638,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_plot_data(self):
|
||||
data = {'submission': 'x = 1234;'}
|
||||
@@ -645,19 +646,19 @@ class MatlabTest(unittest.TestCase):
|
||||
|
||||
test_capa_system().xqueue['interface'].send_to_queue.assert_called_with(header=ANY, body=ANY)
|
||||
|
||||
self.assertTrue(response['success'])
|
||||
self.assertIsNotNone(self.the_input.input_state['queuekey'])
|
||||
self.assertEqual(self.the_input.input_state['queuestate'], 'queued')
|
||||
assert response['success']
|
||||
assert self.the_input.input_state['queuekey'] is not None
|
||||
assert self.the_input.input_state['queuestate'] == 'queued'
|
||||
|
||||
def test_plot_data_failure(self):
|
||||
data = {'submission': 'x = 1234;'}
|
||||
error_message = 'Error message!'
|
||||
test_capa_system().xqueue['interface'].send_to_queue.return_value = (1, error_message)
|
||||
response = self.the_input.handle_ajax("plot", data)
|
||||
self.assertFalse(response['success'])
|
||||
self.assertEqual(response['message'], error_message)
|
||||
self.assertNotIn('queuekey', self.the_input.input_state)
|
||||
self.assertNotIn('queuestate', self.the_input.input_state)
|
||||
assert not response['success']
|
||||
assert response['message'] == error_message
|
||||
assert 'queuekey' not in self.the_input.input_state
|
||||
assert 'queuestate' not in self.the_input.input_state
|
||||
|
||||
@patch('capa.inputtypes.time.time', return_value=10)
|
||||
def test_ungraded_response_success(self, time): # lint-amnesty, pylint: disable=unused-argument
|
||||
@@ -674,9 +675,9 @@ class MatlabTest(unittest.TestCase):
|
||||
queue_msg = json.dumps({'msg': inner_msg})
|
||||
|
||||
the_input.ungraded_response(queue_msg, queuekey)
|
||||
self.assertIsNone(input_state['queuekey'])
|
||||
self.assertIsNone(input_state['queuestate'])
|
||||
self.assertEqual(input_state['queue_msg'], inner_msg)
|
||||
assert input_state['queuekey'] is None
|
||||
assert input_state['queuestate'] is None
|
||||
assert input_state['queue_msg'] == inner_msg
|
||||
|
||||
@patch('capa.inputtypes.time.time', return_value=10)
|
||||
def test_ungraded_response_key_mismatch(self, time): # lint-amnesty, pylint: disable=unused-argument
|
||||
@@ -693,9 +694,9 @@ class MatlabTest(unittest.TestCase):
|
||||
queue_msg = json.dumps({'msg': inner_msg})
|
||||
|
||||
the_input.ungraded_response(queue_msg, 'abc')
|
||||
self.assertEqual(input_state['queuekey'], queuekey)
|
||||
self.assertEqual(input_state['queuestate'], 'queued')
|
||||
self.assertNotIn('queue_msg', input_state)
|
||||
assert input_state['queuekey'] == queuekey
|
||||
assert input_state['queuestate'] == 'queued'
|
||||
assert 'queue_msg' not in input_state
|
||||
|
||||
@patch('capa.inputtypes.time.time', return_value=20)
|
||||
def test_matlab_response_timeout_not_exceeded(self, time): # lint-amnesty, pylint: disable=unused-argument
|
||||
@@ -704,7 +705,7 @@ class MatlabTest(unittest.TestCase):
|
||||
elt = etree.fromstring(self.xml)
|
||||
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
self.assertEqual(the_input.status, 'queued')
|
||||
assert the_input.status == 'queued'
|
||||
|
||||
@patch('capa.inputtypes.time.time', return_value=45)
|
||||
def test_matlab_response_timeout_exceeded(self, time): # lint-amnesty, pylint: disable=unused-argument
|
||||
@@ -713,8 +714,8 @@ class MatlabTest(unittest.TestCase):
|
||||
elt = etree.fromstring(self.xml)
|
||||
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
self.assertEqual(the_input.status, 'unsubmitted')
|
||||
self.assertEqual(the_input.msg, 'No response from Xqueue within {} seconds. Aborted.'.format(XQUEUE_TIMEOUT))
|
||||
assert the_input.status == 'unsubmitted'
|
||||
assert the_input.msg == 'No response from Xqueue within {} seconds. Aborted.'.format(XQUEUE_TIMEOUT)
|
||||
|
||||
@patch('capa.inputtypes.time.time', return_value=20)
|
||||
def test_matlab_response_migration_of_queuetime(self, time): # lint-amnesty, pylint: disable=unused-argument
|
||||
@@ -725,7 +726,7 @@ class MatlabTest(unittest.TestCase):
|
||||
elt = etree.fromstring(self.xml)
|
||||
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
self.assertEqual(the_input.status, 'unsubmitted')
|
||||
assert the_input.status == 'unsubmitted'
|
||||
|
||||
def test_matlab_api_key(self):
|
||||
"""
|
||||
@@ -741,8 +742,8 @@ class MatlabTest(unittest.TestCase):
|
||||
|
||||
body = system.xqueue['interface'].send_to_queue.call_args[1]['body']
|
||||
payload = json.loads(body)
|
||||
self.assertEqual('test_api_key', payload['token'])
|
||||
self.assertEqual('2', payload['endpoint_version'])
|
||||
assert 'test_api_key' == payload['token']
|
||||
assert '2' == payload['endpoint_version']
|
||||
|
||||
def test_get_html(self):
|
||||
# usual output
|
||||
@@ -791,17 +792,17 @@ class MatlabTest(unittest.TestCase):
|
||||
audio_index = element_tags.index('audio')
|
||||
|
||||
six.assertCountEqual(self, element_keys[audio_index], ['autobuffer', 'controls', 'autoplay', 'src'])
|
||||
self.assertEqual(elements[audio_index].get('src'), 'data:audio/wav;base64=')
|
||||
self.assertEqual(elements[audio_index].text, 'Audio is not supported on this browser.')
|
||||
assert elements[audio_index].get('src') == 'data:audio/wav;base64='
|
||||
assert elements[audio_index].text == 'Audio is not supported on this browser.'
|
||||
href_index = element_keys.index(['href'])
|
||||
self.assertEqual(elements[href_index].get('href'), 'https://endpoint.mss-mathworks.com/media/filename.wav')
|
||||
assert elements[href_index].get('href') == 'https://endpoint.mss-mathworks.com/media/filename.wav'
|
||||
id_index = element_keys.index(['id'])
|
||||
self.assertEqual(elements[id_index].get('id'), 'mwAudioPlaceHolder')
|
||||
assert elements[id_index].get('id') == 'mwAudioPlaceHolder'
|
||||
output_string = etree.tostring(output).decode('utf-8')
|
||||
|
||||
# check that exception is raised during parsing for html.
|
||||
self.the_input.capa_system.render_template = lambda *args: "<aaa"
|
||||
with self.assertRaises(etree.XMLSyntaxError):
|
||||
with pytest.raises(etree.XMLSyntaxError):
|
||||
self.the_input.get_html()
|
||||
|
||||
self.the_input.capa_system.render_template = old_render_template
|
||||
@@ -886,7 +887,7 @@ class MatlabTest(unittest.TestCase):
|
||||
'response_data': {},
|
||||
'describedby_html': 'aria-describedby="status_{id}"'.format(id=prob_id)
|
||||
}
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
self.the_input.capa_system.render_template = DemoSystem().render_template
|
||||
self.the_input.get_html() # Should not raise an exception
|
||||
|
||||
@@ -903,7 +904,7 @@ class MatlabTest(unittest.TestCase):
|
||||
}
|
||||
elt = etree.fromstring(self.xml)
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
self.assertEqual(the_input.queue_msg, queue_msg)
|
||||
assert the_input.queue_msg == queue_msg
|
||||
|
||||
def test_matlab_queue_message_not_allowed_tag(self):
|
||||
"""
|
||||
@@ -918,7 +919,7 @@ class MatlabTest(unittest.TestCase):
|
||||
elt = etree.fromstring(self.xml)
|
||||
the_input = self.input_class(test_capa_system(), elt, state)
|
||||
expected = "<script>Test message</script>"
|
||||
self.assertEqual(the_input.queue_msg, expected)
|
||||
assert the_input.queue_msg == expected
|
||||
|
||||
def test_matlab_sanitize_msg(self):
|
||||
"""
|
||||
@@ -927,7 +928,7 @@ class MatlabTest(unittest.TestCase):
|
||||
not_allowed_tag = 'script'
|
||||
self.the_input.msg = "<{0}>Test message</{0}>".format(not_allowed_tag)
|
||||
expected = "<script>Test message</script>"
|
||||
self.assertEqual(self.the_input._get_render_context()['msg'], expected) # pylint: disable=protected-access
|
||||
assert self.the_input._get_render_context()['msg'] == expected # pylint: disable=protected-access
|
||||
|
||||
|
||||
def html_tree_equal(received, expected):
|
||||
@@ -996,7 +997,7 @@ class SchematicTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
|
||||
class ImageInputTest(unittest.TestCase):
|
||||
@@ -1041,7 +1042,7 @@ class ImageInputTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_with_value(self):
|
||||
# Check that compensating for the dot size works properly.
|
||||
@@ -1096,7 +1097,7 @@ class CrystallographyTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
|
||||
class VseprTest(unittest.TestCase):
|
||||
@@ -1143,7 +1144,7 @@ class VseprTest(unittest.TestCase):
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
|
||||
class ChemicalEquationTest(unittest.TestCase):
|
||||
@@ -1180,7 +1181,7 @@ class ChemicalEquationTest(unittest.TestCase):
|
||||
'response_data': RESPONSE_DATA,
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_chemcalc_ajax_sucess(self):
|
||||
"""
|
||||
@@ -1189,24 +1190,24 @@ class ChemicalEquationTest(unittest.TestCase):
|
||||
data = {'formula': "H"}
|
||||
response = self.the_input.handle_ajax("preview_chemcalc", data)
|
||||
|
||||
self.assertIn('preview', response)
|
||||
self.assertNotEqual(response['preview'], '')
|
||||
self.assertEqual(response['error'], "")
|
||||
assert 'preview' in response
|
||||
assert response['preview'] != ''
|
||||
assert response['error'] == ''
|
||||
|
||||
def test_ajax_bad_method(self):
|
||||
"""
|
||||
With a bad dispatch, we shouldn't receive anything
|
||||
"""
|
||||
response = self.the_input.handle_ajax("obviously_not_real", {})
|
||||
self.assertEqual(response, {})
|
||||
assert response == {}
|
||||
|
||||
def test_ajax_no_formula(self):
|
||||
"""
|
||||
When we ask for a formula rendering, there should be an error if no formula
|
||||
"""
|
||||
response = self.the_input.handle_ajax("preview_chemcalc", {})
|
||||
self.assertIn('error', response)
|
||||
self.assertEqual(response['error'], "No formula specified.")
|
||||
assert 'error' in response
|
||||
assert response['error'] == 'No formula specified.'
|
||||
|
||||
def test_ajax_parse_err(self):
|
||||
"""
|
||||
@@ -1220,8 +1221,8 @@ class ChemicalEquationTest(unittest.TestCase):
|
||||
{'formula': 'H2O + invalid chemistry'}
|
||||
)
|
||||
|
||||
self.assertIn('error', response)
|
||||
self.assertIn("Couldn't parse formula", response['error'])
|
||||
assert 'error' in response
|
||||
assert "Couldn't parse formula" in response['error']
|
||||
|
||||
@patch('capa.inputtypes.log')
|
||||
def test_ajax_other_err(self, mock_log):
|
||||
@@ -1237,8 +1238,8 @@ class ChemicalEquationTest(unittest.TestCase):
|
||||
mock_log.warning.assert_called_once_with(
|
||||
"Error while previewing chemical formula", exc_info=True
|
||||
)
|
||||
self.assertIn('error', response)
|
||||
self.assertEqual(response['error'], "Error while rendering preview")
|
||||
assert 'error' in response
|
||||
assert response['error'] == 'Error while rendering preview'
|
||||
|
||||
|
||||
class FormulaEquationTest(unittest.TestCase):
|
||||
@@ -1277,7 +1278,7 @@ class FormulaEquationTest(unittest.TestCase):
|
||||
'response_data': RESPONSE_DATA,
|
||||
'describedby_html': DESCRIBEDBY.format(status_id=prob_id)
|
||||
}
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_trailing_text_rendering(self):
|
||||
"""
|
||||
@@ -1324,7 +1325,7 @@ class FormulaEquationTest(unittest.TestCase):
|
||||
'describedby_html': TRAILING_TEXT_DESCRIBEDBY.format(trailing_text_id=prob_id, status_id=prob_id)
|
||||
}
|
||||
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_formcalc_ajax_sucess(self):
|
||||
"""
|
||||
@@ -1333,17 +1334,17 @@ class FormulaEquationTest(unittest.TestCase):
|
||||
data = {'formula': "x^2+1/2", 'request_start': 0}
|
||||
response = self.the_input.handle_ajax("preview_formcalc", data)
|
||||
|
||||
self.assertIn('preview', response)
|
||||
self.assertNotEqual(response['preview'], '')
|
||||
self.assertEqual(response['error'], "")
|
||||
self.assertEqual(response['request_start'], data['request_start'])
|
||||
assert 'preview' in response
|
||||
assert response['preview'] != ''
|
||||
assert response['error'] == ''
|
||||
assert response['request_start'] == data['request_start']
|
||||
|
||||
def test_ajax_bad_method(self):
|
||||
"""
|
||||
With a bad dispatch, we shouldn't receive anything
|
||||
"""
|
||||
response = self.the_input.handle_ajax("obviously_not_real", {})
|
||||
self.assertEqual(response, {})
|
||||
assert response == {}
|
||||
|
||||
def test_ajax_no_formula(self):
|
||||
"""
|
||||
@@ -1353,8 +1354,8 @@ class FormulaEquationTest(unittest.TestCase):
|
||||
"preview_formcalc",
|
||||
{'request_start': 1, }
|
||||
)
|
||||
self.assertIn('error', response)
|
||||
self.assertEqual(response['error'], "No formula specified.")
|
||||
assert 'error' in response
|
||||
assert response['error'] == 'No formula specified.'
|
||||
|
||||
def test_ajax_parse_err(self):
|
||||
"""
|
||||
@@ -1368,8 +1369,8 @@ class FormulaEquationTest(unittest.TestCase):
|
||||
{'formula': 'x^2+1/2', 'request_start': 1, }
|
||||
)
|
||||
|
||||
self.assertIn('error', response)
|
||||
self.assertEqual(response['error'], "Sorry, couldn't parse formula")
|
||||
assert 'error' in response
|
||||
assert response['error'] == "Sorry, couldn't parse formula"
|
||||
|
||||
@patch('capa.inputtypes.log')
|
||||
def test_ajax_other_err(self, mock_log):
|
||||
@@ -1385,8 +1386,8 @@ class FormulaEquationTest(unittest.TestCase):
|
||||
mock_log.warning.assert_called_once_with(
|
||||
"Error while previewing formula", exc_info=True
|
||||
)
|
||||
self.assertIn('error', response)
|
||||
self.assertEqual(response['error'], "Error while rendering preview")
|
||||
assert 'error' in response
|
||||
assert response['error'] == 'Error while rendering preview'
|
||||
|
||||
|
||||
class DragAndDropTest(unittest.TestCase):
|
||||
@@ -1457,10 +1458,10 @@ class DragAndDropTest(unittest.TestCase):
|
||||
|
||||
# as we are dumping 'draggables' dicts while dumping user_input, string
|
||||
# comparison will fail, as order of keys is random.
|
||||
self.assertEqual(json.loads(context['drag_and_drop_json']), user_input)
|
||||
assert json.loads(context['drag_and_drop_json']) == user_input
|
||||
context.pop('drag_and_drop_json')
|
||||
expected.pop('drag_and_drop_json')
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
|
||||
class AnnotationInputTest(unittest.TestCase):
|
||||
@@ -1591,7 +1592,7 @@ class TestChoiceText(unittest.TestCase):
|
||||
expected.update(state)
|
||||
the_input = lookup_tag(tag)(test_capa_system(), element, state)
|
||||
context = the_input._get_render_context() # pylint: disable=protected-access
|
||||
self.assertEqual(context, expected)
|
||||
assert context == expected
|
||||
|
||||
def test_radiotextgroup(self):
|
||||
"""
|
||||
@@ -1611,7 +1612,7 @@ class TestChoiceText(unittest.TestCase):
|
||||
"""
|
||||
Test to ensure that an unrecognized inputtype tag causes an error
|
||||
"""
|
||||
with self.assertRaises(Exception):
|
||||
with pytest.raises(Exception):
|
||||
self.check_group('invalid', 'choice', 'checkbox')
|
||||
|
||||
def test_invalid_input_tag(self):
|
||||
@@ -1632,8 +1633,8 @@ class TestStatus(unittest.TestCase):
|
||||
Test stringifing Status objects
|
||||
"""
|
||||
statobj = inputtypes.Status('test')
|
||||
self.assertEqual(str(statobj), 'test')
|
||||
self.assertEqual(six.text_type(statobj), u'test')
|
||||
assert str(statobj) == 'test'
|
||||
assert six.text_type(statobj) == u'test'
|
||||
|
||||
def test_classes(self):
|
||||
"""
|
||||
@@ -1648,7 +1649,7 @@ class TestStatus(unittest.TestCase):
|
||||
]
|
||||
for status, classname in css_classes:
|
||||
statobj = inputtypes.Status(status)
|
||||
self.assertEqual(statobj.classname, classname)
|
||||
assert statobj.classname == classname
|
||||
|
||||
def test_display_names(self):
|
||||
"""
|
||||
@@ -1665,7 +1666,7 @@ class TestStatus(unittest.TestCase):
|
||||
]
|
||||
for status, display_name in names:
|
||||
statobj = inputtypes.Status(status)
|
||||
self.assertEqual(statobj.display_name, display_name)
|
||||
assert statobj.display_name == display_name
|
||||
|
||||
def test_translated_names(self):
|
||||
"""
|
||||
@@ -1674,10 +1675,10 @@ class TestStatus(unittest.TestCase):
|
||||
func = lambda t: t.upper()
|
||||
# status is in the mapping
|
||||
statobj = inputtypes.Status('queued', func)
|
||||
self.assertEqual(statobj.display_name, u'PROCESSING')
|
||||
assert statobj.display_name == u'PROCESSING'
|
||||
|
||||
# status is not in the mapping
|
||||
statobj = inputtypes.Status('test', func)
|
||||
self.assertEqual(statobj.display_name, u'test')
|
||||
self.assertEqual(str(statobj), 'test')
|
||||
self.assertEqual(statobj.classname, 'test')
|
||||
assert statobj.display_name == u'test'
|
||||
assert str(statobj) == 'test'
|
||||
assert statobj.classname == 'test'
|
||||
|
||||
@@ -12,6 +12,7 @@ import unittest
|
||||
import zipfile
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
import calc
|
||||
import mock
|
||||
import pyparsing
|
||||
@@ -66,23 +67,23 @@ class ResponseTest(unittest.TestCase):
|
||||
input_dict = {'1_2_1': submission}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
if msg is None:
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), expected_correctness)
|
||||
assert correct_map.get_correctness('1_2_1') == expected_correctness
|
||||
else:
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), expected_correctness, msg)
|
||||
assert correct_map.get_correctness('1_2_1') == expected_correctness, msg
|
||||
|
||||
def assert_answer_format(self, problem):
|
||||
answers = problem.get_question_answers()
|
||||
self.assertIsNotNone(answers['1_2_1'])
|
||||
assert answers['1_2_1'] is not None
|
||||
|
||||
# pylint: disable=missing-function-docstring
|
||||
def assert_multiple_grade(self, problem, correct_answers, incorrect_answers):
|
||||
for input_str in correct_answers:
|
||||
result = problem.grade_answers({'1_2_1': input_str}).get_correctness('1_2_1')
|
||||
self.assertEqual(result, 'correct')
|
||||
assert result == 'correct'
|
||||
|
||||
for input_str in incorrect_answers:
|
||||
result = problem.grade_answers({'1_2_1': input_str}).get_correctness('1_2_1')
|
||||
self.assertEqual(result, 'incorrect')
|
||||
assert result == 'incorrect'
|
||||
|
||||
def assert_multiple_partial(self, problem, correct_answers, incorrect_answers, partial_answers):
|
||||
"""
|
||||
@@ -91,15 +92,15 @@ class ResponseTest(unittest.TestCase):
|
||||
"""
|
||||
for input_str in correct_answers:
|
||||
result = problem.grade_answers({'1_2_1': input_str}).get_correctness('1_2_1')
|
||||
self.assertEqual(result, 'correct')
|
||||
assert result == 'correct'
|
||||
|
||||
for input_str in incorrect_answers:
|
||||
result = problem.grade_answers({'1_2_1': input_str}).get_correctness('1_2_1')
|
||||
self.assertEqual(result, 'incorrect')
|
||||
assert result == 'incorrect'
|
||||
|
||||
for input_str in partial_answers:
|
||||
result = problem.grade_answers({'1_2_1': input_str}).get_correctness('1_2_1')
|
||||
self.assertEqual(result, 'partially-correct')
|
||||
assert result == 'partially-correct'
|
||||
|
||||
def _get_random_number_code(self):
|
||||
"""Returns code to be used to generate a random result."""
|
||||
@@ -143,13 +144,13 @@ class MultiChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-do
|
||||
# Multiple Choice problems only allow one partial credit scheme.
|
||||
# Change this test if that changes.
|
||||
problem = self.build_problem(choices=[False, True, 'partial'], credit_type='points,points')
|
||||
with self.assertRaises(LoncapaProblemError):
|
||||
with pytest.raises(LoncapaProblemError):
|
||||
input_dict = {'1_2_1': 'choice_1'}
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
# 'bongo' is not a valid grading scheme.
|
||||
problem = self.build_problem(choices=[False, True, 'partial'], credit_type='bongo')
|
||||
with self.assertRaises(LoncapaProblemError):
|
||||
with pytest.raises(LoncapaProblemError):
|
||||
input_dict = {'1_2_1': 'choice_1'}
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
@@ -163,13 +164,13 @@ class MultiChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-do
|
||||
# Ensure that we get the expected number of points
|
||||
# Using assertAlmostEqual to avoid floating point issues
|
||||
correct_map = problem.grade_answers({'1_2_1': 'choice_0'})
|
||||
self.assertAlmostEqual(correct_map.get_npoints('1_2_1'), 1)
|
||||
assert round(correct_map.get_npoints('1_2_1') - 1, 7) >= 0
|
||||
|
||||
correct_map = problem.grade_answers({'1_2_1': 'choice_1'})
|
||||
self.assertAlmostEqual(correct_map.get_npoints('1_2_1'), 0.6)
|
||||
assert round(correct_map.get_npoints('1_2_1') - 0.6, 7) >= 0
|
||||
|
||||
correct_map = problem.grade_answers({'1_2_1': 'choice_2'})
|
||||
self.assertAlmostEqual(correct_map.get_npoints('1_2_1'), 0)
|
||||
assert round(correct_map.get_npoints('1_2_1') - 0, 7) >= 0
|
||||
|
||||
def test_contextualized_choices(self):
|
||||
script = textwrap.dedent("""
|
||||
@@ -350,7 +351,7 @@ class SymbolicResponseTest(ResponseTest): # pylint: disable=missing-class-docst
|
||||
|
||||
# Should not allow multiple inputs, since we specify
|
||||
# only one "expect" value
|
||||
with self.assertRaises(Exception):
|
||||
with pytest.raises(Exception):
|
||||
self.build_problem(math_display=True, expect="2*x+3*y", num_inputs=3)
|
||||
|
||||
def _assert_symbolic_grade(
|
||||
@@ -375,9 +376,7 @@ class SymbolicResponseTest(ResponseTest): # pylint: disable=missing-class-docst
|
||||
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
self.assertEqual(
|
||||
correct_map.get_correctness('1_2_1'), expected_correctness
|
||||
)
|
||||
assert correct_map.get_correctness('1_2_1') == expected_correctness
|
||||
|
||||
|
||||
class OptionResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
@@ -423,8 +422,8 @@ class OptionResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
|
||||
input_dict = {'1_2_1': '1000'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
|
||||
self.assertEqual(correct_map.get_property('1_2_1', 'answervariable'), '$a')
|
||||
assert correct_map.get_correctness('1_2_1') == 'correct'
|
||||
assert correct_map.get_property('1_2_1', 'answervariable') == '$a'
|
||||
|
||||
|
||||
class FormulaResponseTest(ResponseTest):
|
||||
@@ -480,14 +479,12 @@ class FormulaResponseTest(ResponseTest):
|
||||
# Expect to receive a hint if we add an extra y
|
||||
input_dict = {'1_2_1': "x + 2*y + y"}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'),
|
||||
'Check the coefficient of y')
|
||||
assert correct_map.get_hint('1_2_1') == 'Check the coefficient of y'
|
||||
|
||||
# Expect to receive a hint if we leave out x
|
||||
input_dict = {'1_2_1': "2*y"}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'),
|
||||
'Try including the variable x')
|
||||
assert correct_map.get_hint('1_2_1') == 'Try including the variable x'
|
||||
|
||||
def test_script(self):
|
||||
"""
|
||||
@@ -574,8 +571,8 @@ class FormulaResponseTest(ResponseTest):
|
||||
tolerance="1%",
|
||||
answer="x"
|
||||
)
|
||||
self.assertTrue(list(problem.responders.values())[0].validate_answer('14*x'))
|
||||
self.assertFalse(list(problem.responders.values())[0].validate_answer('3*y+2*x'))
|
||||
assert list(problem.responders.values())[0].validate_answer('14*x')
|
||||
assert not list(problem.responders.values())[0].validate_answer('3*y+2*x')
|
||||
|
||||
|
||||
class StringResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
@@ -799,10 +796,10 @@ class StringResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
|
||||
def test_exception(self):
|
||||
problem = self.build_problem(answer="a2", case_sensitive=False, regexp=True, additional_answers=['?\\d?'])
|
||||
with self.assertRaises(Exception) as cm:
|
||||
with pytest.raises(Exception) as cm:
|
||||
self.assert_grade(problem, "a3", "correct")
|
||||
exception_message = text_type(cm.exception)
|
||||
self.assertIn("nothing to repeat", exception_message)
|
||||
assert 'nothing to repeat' in exception_message
|
||||
|
||||
def test_hints(self):
|
||||
|
||||
@@ -818,24 +815,22 @@ class StringResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
# We should get a hint for Wisconsin
|
||||
input_dict = {'1_2_1': 'Wisconsin'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'),
|
||||
"The state capital of Wisconsin is Madison")
|
||||
assert correct_map.get_hint('1_2_1') == 'The state capital of Wisconsin is Madison'
|
||||
|
||||
# We should get a hint for Minnesota
|
||||
input_dict = {'1_2_1': 'Minnesota'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'),
|
||||
"The state capital of Minnesota is St. Paul")
|
||||
assert correct_map.get_hint('1_2_1') == 'The state capital of Minnesota is St. Paul'
|
||||
|
||||
# We should NOT get a hint for Michigan (the correct answer)
|
||||
input_dict = {'1_2_1': 'Michigan'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'), "")
|
||||
assert correct_map.get_hint('1_2_1') == ''
|
||||
|
||||
# We should NOT get a hint for any other string
|
||||
input_dict = {'1_2_1': 'California'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'), "")
|
||||
assert correct_map.get_hint('1_2_1') == ''
|
||||
|
||||
def test_hints_regexp_and_answer_regexp(self):
|
||||
different_student_answers = [
|
||||
@@ -867,38 +862,36 @@ class StringResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
# We should get a hint for Wisconsin
|
||||
input_dict = {'1_2_1': 'Wisconsin'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'),
|
||||
"The state capital of Wisconsin is Madison")
|
||||
assert correct_map.get_hint('1_2_1') == 'The state capital of Wisconsin is Madison'
|
||||
|
||||
# We should get a hint for Minnesota
|
||||
input_dict = {'1_2_1': 'Minnesota'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'),
|
||||
"The state capital of Minnesota is St. Paul")
|
||||
assert correct_map.get_hint('1_2_1') == 'The state capital of Minnesota is St. Paul'
|
||||
|
||||
# We should NOT get a hint for Michigan (the correct answer)
|
||||
input_dict = {'1_2_1': 'Michigan'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'), "")
|
||||
assert correct_map.get_hint('1_2_1') == ''
|
||||
|
||||
# We should NOT get a hint for any other string
|
||||
input_dict = {'1_2_1': 'California'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'), "")
|
||||
assert correct_map.get_hint('1_2_1') == ''
|
||||
|
||||
# We should get the same hint for each answer
|
||||
for answer in different_student_answers:
|
||||
input_dict = {'1_2_1': answer}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'), "First letter of correct answer is M.")
|
||||
assert correct_map.get_hint('1_2_1') == 'First letter of correct answer is M.'
|
||||
|
||||
input_dict = {'1_2_1': '59'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'), "Should not end with 9.")
|
||||
assert correct_map.get_hint('1_2_1') == 'Should not end with 9.'
|
||||
|
||||
input_dict = {'1_2_1': '57'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'), "")
|
||||
assert correct_map.get_hint('1_2_1') == ''
|
||||
|
||||
def test_computed_hints(self):
|
||||
problem = self.build_problem(
|
||||
@@ -914,7 +907,7 @@ class StringResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
|
||||
input_dict = {'1_2_1': 'Hello'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_hint('1_2_1'), "Hello??")
|
||||
assert correct_map.get_hint('1_2_1') == 'Hello??'
|
||||
|
||||
def test_hint_function_randomization(self):
|
||||
# The hint function should get the seed from the problem.
|
||||
@@ -930,7 +923,7 @@ class StringResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
)
|
||||
correct_map = problem.grade_answers({'1_2_1': '2'})
|
||||
hint = correct_map.get_hint('1_2_1')
|
||||
self.assertEqual(hint, self._get_random_number_result(problem.seed))
|
||||
assert hint == self._get_random_number_result(problem.seed)
|
||||
|
||||
def test_empty_answer_graded_as_incorrect(self):
|
||||
"""
|
||||
@@ -971,7 +964,7 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
cmap.update(CorrectMap(answer_id=answer_id, queuestate=None))
|
||||
self.problem.correct_map.update(cmap)
|
||||
|
||||
self.assertEqual(self.problem.is_queued(), False)
|
||||
assert self.problem.is_queued() is False
|
||||
|
||||
# Now we queue the LCP
|
||||
cmap = CorrectMap()
|
||||
@@ -980,7 +973,7 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
cmap.update(CorrectMap(answer_id=answer_ids[i], queuestate=queuestate))
|
||||
self.problem.correct_map.update(cmap)
|
||||
|
||||
self.assertEqual(self.problem.is_queued(), True)
|
||||
assert self.problem.is_queued() is True
|
||||
|
||||
def test_update_score(self):
|
||||
'''
|
||||
@@ -1009,10 +1002,12 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
self.problem.correct_map.update(old_cmap) # Deep copy
|
||||
|
||||
self.problem.update_score(xserver_msgs[correctness], queuekey=0)
|
||||
self.assertEqual(self.problem.correct_map.get_dict(), old_cmap.get_dict()) # Deep comparison
|
||||
assert self.problem.correct_map.get_dict() == old_cmap.get_dict()
|
||||
# Deep comparison
|
||||
|
||||
for answer_id in answer_ids:
|
||||
self.assertTrue(self.problem.correct_map.is_queued(answer_id)) # Should be still queued, since message undelivered # lint-amnesty, pylint: disable=line-too-long
|
||||
assert self.problem.correct_map.is_queued(answer_id)
|
||||
# Should be still queued, since message undelivered # lint-amnesty, pylint: disable=line-too-long
|
||||
|
||||
# Correct queuekey, state should be updated
|
||||
for correctness in ['correct', 'incorrect']:
|
||||
@@ -1026,13 +1021,15 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
new_cmap.set(answer_id=answer_id, npoints=npoints, correctness=correctness, msg=grader_msg, queuestate=None) # lint-amnesty, pylint: disable=line-too-long
|
||||
|
||||
self.problem.update_score(xserver_msgs[correctness], queuekey=1000 + i)
|
||||
self.assertEqual(self.problem.correct_map.get_dict(), new_cmap.get_dict())
|
||||
assert self.problem.correct_map.get_dict() == new_cmap.get_dict()
|
||||
|
||||
for j, test_id in enumerate(answer_ids):
|
||||
if j == i:
|
||||
self.assertFalse(self.problem.correct_map.is_queued(test_id)) # Should be dequeued, message delivered # lint-amnesty, pylint: disable=line-too-long
|
||||
assert not self.problem.correct_map.is_queued(test_id)
|
||||
# Should be dequeued, message delivered # lint-amnesty, pylint: disable=line-too-long
|
||||
else:
|
||||
self.assertTrue(self.problem.correct_map.is_queued(test_id)) # Should be queued, message undelivered # lint-amnesty, pylint: disable=line-too-long
|
||||
assert self.problem.correct_map.is_queued(test_id)
|
||||
# Should be queued, message undelivered # lint-amnesty, pylint: disable=line-too-long
|
||||
|
||||
def test_recentmost_queuetime(self):
|
||||
'''
|
||||
@@ -1046,7 +1043,7 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
cmap.update(CorrectMap(answer_id=answer_id, queuestate=None))
|
||||
self.problem.correct_map.update(cmap)
|
||||
|
||||
self.assertEqual(self.problem.get_recentmost_queuetime(), None)
|
||||
assert self.problem.get_recentmost_queuetime() is None
|
||||
|
||||
# CodeResponse requires internal CorrectMap state. Build it now in the queued state
|
||||
cmap = CorrectMap()
|
||||
@@ -1062,7 +1059,7 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
datetime.strftime(latest_timestamp, dateformat), dateformat
|
||||
).replace(tzinfo=UTC)
|
||||
|
||||
self.assertEqual(self.problem.get_recentmost_queuetime(), latest_timestamp)
|
||||
assert self.problem.get_recentmost_queuetime() == latest_timestamp
|
||||
|
||||
def test_convert_files_to_filenames(self):
|
||||
'''
|
||||
@@ -1074,9 +1071,9 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
'1_3_1': ['answer1', 'answer2', 'answer3'],
|
||||
'1_4_1': [fp, fp]}
|
||||
answers_converted = convert_files_to_filenames(answers_with_file)
|
||||
self.assertEqual(answers_converted['1_2_1'], 'String-based answer')
|
||||
self.assertEqual(answers_converted['1_3_1'], ['answer1', 'answer2', 'answer3'])
|
||||
self.assertEqual(answers_converted['1_4_1'], [fp.name, fp.name])
|
||||
assert answers_converted['1_2_1'] == 'String-based answer'
|
||||
assert answers_converted['1_3_1'] == ['answer1', 'answer2', 'answer3']
|
||||
assert answers_converted['1_4_1'] == [fp.name, fp.name]
|
||||
|
||||
def test_parse_score_msg_of_responder(self):
|
||||
"""
|
||||
@@ -1116,7 +1113,7 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
self.problem.correct_map = CorrectMap()
|
||||
self.problem.correct_map.update(old_cmap)
|
||||
output = self.problem.update_score(xserver_msgs['correct'], queuekey=1000 + i)
|
||||
self.assertEqual(output[answer_id]['msg'], grader_msg)
|
||||
assert output[answer_id]['msg'] == grader_msg
|
||||
|
||||
for grader_msg in invalid_grader_msgs:
|
||||
correct_score_msg = json.dumps({'correct': True, 'score': 1, 'msg': grader_msg})
|
||||
@@ -1128,7 +1125,7 @@ class CodeResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
self.problem.correct_map.update(old_cmap)
|
||||
|
||||
output = self.problem.update_score(xserver_msgs['correct'], queuekey=1000 + i)
|
||||
self.assertEqual(output[answer_id]['msg'], u'Invalid grader reply. Please contact the course staff.')
|
||||
assert output[answer_id]['msg'] == u'Invalid grader reply. Please contact the course staff.'
|
||||
|
||||
|
||||
class ChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
@@ -1169,7 +1166,7 @@ class ChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
choices=[False, False, True, True],
|
||||
credit_type='edc,halves,bongo'
|
||||
)
|
||||
with self.assertRaises(LoncapaProblemError):
|
||||
with pytest.raises(LoncapaProblemError):
|
||||
input_dict = {'1_2_1': 'choice_1'}
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
@@ -1179,7 +1176,7 @@ class ChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
choices=[False, False, True, True],
|
||||
credit_type='bongo'
|
||||
)
|
||||
with self.assertRaises(LoncapaProblemError):
|
||||
with pytest.raises(LoncapaProblemError):
|
||||
input_dict = {'1_2_1': 'choice_1'}
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
@@ -1245,7 +1242,7 @@ class ChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
)
|
||||
|
||||
correct_map = problem.grade_answers({'1_2_1': 'choice_2'})
|
||||
self.assertAlmostEqual(correct_map.get_npoints('1_2_1'), 0.75)
|
||||
assert round(correct_map.get_npoints('1_2_1') - 0.75, 7) >= 0
|
||||
|
||||
# Second: Halves grading style
|
||||
problem = self.build_problem(
|
||||
@@ -1255,7 +1252,7 @@ class ChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
)
|
||||
|
||||
correct_map = problem.grade_answers({'1_2_1': 'choice_2'})
|
||||
self.assertAlmostEqual(correct_map.get_npoints('1_2_1'), 0.5)
|
||||
assert round(correct_map.get_npoints('1_2_1') - 0.5, 7) >= 0
|
||||
|
||||
# Third: Halves grading style with more options
|
||||
problem = self.build_problem(
|
||||
@@ -1265,7 +1262,7 @@ class ChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
)
|
||||
|
||||
correct_map = problem.grade_answers({'1_2_1': 'choice_2,choice4'})
|
||||
self.assertAlmostEqual(correct_map.get_npoints('1_2_1'), 0.25)
|
||||
assert round(correct_map.get_npoints('1_2_1') - 0.25, 7) >= 0
|
||||
|
||||
def test_grade_with_no_checkbox_selected(self):
|
||||
"""
|
||||
@@ -1276,7 +1273,7 @@ class ChoiceResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
)
|
||||
|
||||
correct_map = problem.grade_answers({})
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'incorrect')
|
||||
assert correct_map.get_correctness('1_2_1') == 'incorrect'
|
||||
|
||||
def test_contextualized_choices(self):
|
||||
script = textwrap.dedent("""
|
||||
@@ -1337,14 +1334,14 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-class-docs
|
||||
|
||||
# Assert primary answer is graded correctly.
|
||||
correct_map = problem.grade_answers({'1_2_1': primary_answer})
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
|
||||
self.assertIn(primary_correcthint, correct_map.get_msg('1_2_1'))
|
||||
assert correct_map.get_correctness('1_2_1') == 'correct'
|
||||
assert primary_correcthint in correct_map.get_msg('1_2_1')
|
||||
|
||||
# Assert additional answers are graded correct
|
||||
for answer, correcthint in additional_answers.items():
|
||||
correct_map = problem.grade_answers({'1_2_1': answer})
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
|
||||
self.assertIn(correcthint, correct_map.get_msg('1_2_1'))
|
||||
assert correct_map.get_correctness('1_2_1') == 'correct'
|
||||
assert correcthint in correct_map.get_msg('1_2_1')
|
||||
|
||||
def test_additional_answer_get_score(self):
|
||||
"""
|
||||
@@ -1355,15 +1352,15 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-class-docs
|
||||
|
||||
# Check primary answer.
|
||||
new_cmap = responder.get_score({'1_2_1': '100'})
|
||||
self.assertEqual(new_cmap.get_correctness('1_2_1'), 'correct')
|
||||
assert new_cmap.get_correctness('1_2_1') == 'correct'
|
||||
|
||||
# Check additional answer.
|
||||
new_cmap = responder.get_score({'1_2_1': '1'})
|
||||
self.assertEqual(new_cmap.get_correctness('1_2_1'), 'correct')
|
||||
assert new_cmap.get_correctness('1_2_1') == 'correct'
|
||||
|
||||
# Check any wrong answer.
|
||||
new_cmap = responder.get_score({'1_2_1': '2'})
|
||||
self.assertEqual(new_cmap.get_correctness('1_2_1'), 'incorrect')
|
||||
assert new_cmap.get_correctness('1_2_1') == 'incorrect'
|
||||
|
||||
def test_grade_range_tolerance_partial_credit(self):
|
||||
problem_setup = [
|
||||
@@ -1404,13 +1401,13 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-class-docs
|
||||
# no complex number in range tolerance staff answer
|
||||
problem = self.build_problem(answer='[1j, 5]')
|
||||
input_dict = {'1_2_1': '3'}
|
||||
with self.assertRaises(StudentInputError):
|
||||
with pytest.raises(StudentInputError):
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
# no complex numbers in student ansers to range tolerance problems
|
||||
problem = self.build_problem(answer='(1, 5)')
|
||||
input_dict = {'1_2_1': '1*J'}
|
||||
with self.assertRaises(StudentInputError):
|
||||
with pytest.raises(StudentInputError):
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
# test isnan student input: no exception,
|
||||
@@ -1419,16 +1416,16 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-class-docs
|
||||
input_dict = {'1_2_1': ''}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
self.assertEqual(correctness, 'incorrect')
|
||||
assert correctness == 'incorrect'
|
||||
|
||||
# test invalid range tolerance answer
|
||||
with self.assertRaises(StudentInputError):
|
||||
with pytest.raises(StudentInputError):
|
||||
problem = self.build_problem(answer='(1 5)')
|
||||
|
||||
# test empty boundaries
|
||||
problem = self.build_problem(answer='(1, ]')
|
||||
input_dict = {'1_2_1': '3'}
|
||||
with self.assertRaises(StudentInputError):
|
||||
with pytest.raises(StudentInputError):
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
def test_grade_exact(self):
|
||||
@@ -1489,7 +1486,7 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-class-docs
|
||||
# 'bongo' is not a valid grading scheme.
|
||||
problem = self.build_problem(answer=4, tolerance=0.1, credit_type='bongo')
|
||||
input_dict = {'1_2_1': '4'}
|
||||
with self.assertRaises(LoncapaProblemError):
|
||||
with pytest.raises(LoncapaProblemError):
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
def test_grade_decimal_tolerance(self):
|
||||
@@ -1556,7 +1553,7 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-class-docs
|
||||
"""See if division by zero is handled correctly."""
|
||||
problem = self.build_problem(answer="1") # Answer doesn't matter
|
||||
input_dict = {'1_2_1': '1/0'}
|
||||
with self.assertRaises(StudentInputError):
|
||||
with pytest.raises(StudentInputError):
|
||||
problem.grade_answers(input_dict)
|
||||
|
||||
def test_staff_inputs_expressions(self):
|
||||
@@ -1662,15 +1659,15 @@ class NumericalResponseTest(ResponseTest): # pylint: disable=missing-class-docs
|
||||
"""Tests the answer compare function."""
|
||||
problem = self.build_problem(answer="42")
|
||||
responder = list(problem.responders.values())[0]
|
||||
self.assertTrue(responder.compare_answer('48', '8*6'))
|
||||
self.assertFalse(responder.compare_answer('48', '9*5'))
|
||||
assert responder.compare_answer('48', '8*6')
|
||||
assert not responder.compare_answer('48', '9*5')
|
||||
|
||||
def test_validate_answer(self):
|
||||
"""Tests the answer validation function."""
|
||||
problem = self.build_problem(answer="42")
|
||||
responder = list(problem.responders.values())[0]
|
||||
self.assertTrue(responder.validate_answer('23.5'))
|
||||
self.assertFalse(responder.validate_answer('fish'))
|
||||
assert responder.validate_answer('23.5')
|
||||
assert not responder.validate_answer('fish')
|
||||
|
||||
|
||||
class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstring
|
||||
@@ -1704,11 +1701,11 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
|
||||
# Check that the message for the particular input was received
|
||||
input_msg = correctmap.get_msg('1_2_1')
|
||||
self.assertEqual(input_msg, "Test Message")
|
||||
assert input_msg == 'Test Message'
|
||||
|
||||
# Check that the overall message (for the whole response) was received
|
||||
overall_msg = correctmap.get_overall_message()
|
||||
self.assertEqual(overall_msg, "Overall message")
|
||||
assert overall_msg == 'Overall message'
|
||||
|
||||
def test_inline_randomization(self):
|
||||
# Make sure the seed from the problem gets fed into the script execution.
|
||||
@@ -1719,7 +1716,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correctmap = problem.grade_answers(input_dict)
|
||||
|
||||
input_msg = correctmap.get_msg('1_2_1')
|
||||
self.assertEqual(input_msg, self._get_random_number_result(problem.seed))
|
||||
assert input_msg == self._get_random_number_result(problem.seed)
|
||||
|
||||
def test_function_code_single_input(self):
|
||||
# For function code, we pass in these arguments:
|
||||
@@ -1754,9 +1751,9 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
npoints = correct_map.get_npoints('1_2_1')
|
||||
|
||||
self.assertEqual(correctness, 'correct')
|
||||
self.assertEqual(msg, "Message text")
|
||||
self.assertEqual(npoints, 1)
|
||||
assert correctness == 'correct'
|
||||
assert msg == 'Message text'
|
||||
assert npoints == 1
|
||||
|
||||
# Partially Credit answer
|
||||
input_dict = {'1_2_1': '21'}
|
||||
@@ -1766,9 +1763,9 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
npoints = correct_map.get_npoints('1_2_1')
|
||||
|
||||
self.assertEqual(correctness, 'partially-correct')
|
||||
self.assertEqual(msg, "Message text")
|
||||
self.assertTrue(0 <= npoints <= 1)
|
||||
assert correctness == 'partially-correct'
|
||||
assert msg == 'Message text'
|
||||
assert 0 <= npoints <= 1
|
||||
|
||||
# Incorrect answer
|
||||
input_dict = {'1_2_1': '0'}
|
||||
@@ -1778,9 +1775,9 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
npoints = correct_map.get_npoints('1_2_1')
|
||||
|
||||
self.assertEqual(correctness, 'incorrect')
|
||||
self.assertEqual(msg, "Message text")
|
||||
self.assertEqual(npoints, 0)
|
||||
assert correctness == 'incorrect'
|
||||
assert msg == 'Message text'
|
||||
assert npoints == 0
|
||||
|
||||
def test_function_code_single_input_decimal_score(self):
|
||||
# For function code, we pass in these arguments:
|
||||
@@ -1817,20 +1814,20 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
# Correct answer
|
||||
input_dict = {'1_2_1': '42'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_npoints('1_2_1'), 0.9)
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
|
||||
assert correct_map.get_npoints('1_2_1') == 0.9
|
||||
assert correct_map.get_correctness('1_2_1') == 'correct'
|
||||
|
||||
# Incorrect answer
|
||||
input_dict = {'1_2_1': '43'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_npoints('1_2_1'), 0.1)
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'incorrect')
|
||||
assert correct_map.get_npoints('1_2_1') == 0.1
|
||||
assert correct_map.get_correctness('1_2_1') == 'incorrect'
|
||||
|
||||
# Partially Correct answer
|
||||
input_dict = {'1_2_1': '21'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
self.assertEqual(correct_map.get_npoints('1_2_1'), 0.5)
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'partially-correct')
|
||||
assert correct_map.get_npoints('1_2_1') == 0.5
|
||||
assert correct_map.get_correctness('1_2_1') == 'partially-correct'
|
||||
|
||||
def test_script_context(self):
|
||||
# Ensure that python script variables can be used in the "expect" and "answer" fields,
|
||||
@@ -1853,11 +1850,11 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correctmap = problem.grade_answers(input_dict)
|
||||
|
||||
# CustomResponse also adds 'expect' to the problem context; check that directly first:
|
||||
self.assertEqual(problem.context['expect'], '42')
|
||||
assert problem.context['expect'] == '42'
|
||||
|
||||
# Also make sure the problem was graded correctly:
|
||||
correctness = correctmap.get_correctness('1_2_1')
|
||||
self.assertEqual(correctness, 'correct')
|
||||
assert correctness == 'correct'
|
||||
|
||||
def test_function_code_multiple_input_no_msg(self):
|
||||
|
||||
@@ -1885,32 +1882,32 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
self.assertEqual(correctness, 'correct')
|
||||
assert correctness == 'correct'
|
||||
|
||||
correctness = correct_map.get_correctness('1_2_2')
|
||||
self.assertEqual(correctness, 'correct')
|
||||
assert correctness == 'correct'
|
||||
|
||||
# One answer incorrect -- expect both inputs marked partially correct
|
||||
input_dict = {'1_2_1': '0', '1_2_2': '42'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
self.assertEqual(correctness, 'partially-correct')
|
||||
self.assertTrue(0 <= correct_map.get_npoints('1_2_1') <= 1)
|
||||
assert correctness == 'partially-correct'
|
||||
assert 0 <= correct_map.get_npoints('1_2_1') <= 1
|
||||
|
||||
correctness = correct_map.get_correctness('1_2_2')
|
||||
self.assertEqual(correctness, 'partially-correct')
|
||||
self.assertTrue(0 <= correct_map.get_npoints('1_2_2') <= 1)
|
||||
assert correctness == 'partially-correct'
|
||||
assert 0 <= correct_map.get_npoints('1_2_2') <= 1
|
||||
|
||||
# Both answers incorrect -- expect both inputs marked incorrect
|
||||
input_dict = {'1_2_1': '0', '1_2_2': '0'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
self.assertEqual(correctness, 'incorrect')
|
||||
assert correctness == 'incorrect'
|
||||
|
||||
correctness = correct_map.get_correctness('1_2_2')
|
||||
self.assertEqual(correctness, 'incorrect')
|
||||
assert correctness == 'incorrect'
|
||||
|
||||
def test_function_code_multiple_inputs(self):
|
||||
|
||||
@@ -1950,25 +1947,25 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
# Expect that we receive the overall message (for the whole response)
|
||||
self.assertEqual(correct_map.get_overall_message(), "Overall message")
|
||||
assert correct_map.get_overall_message() == 'Overall message'
|
||||
|
||||
# Expect that the inputs were graded individually
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'incorrect')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_2'), 'correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_3'), 'correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_4'), 'partially-correct')
|
||||
assert correct_map.get_correctness('1_2_1') == 'incorrect'
|
||||
assert correct_map.get_correctness('1_2_2') == 'correct'
|
||||
assert correct_map.get_correctness('1_2_3') == 'correct'
|
||||
assert correct_map.get_correctness('1_2_4') == 'partially-correct'
|
||||
|
||||
# Expect that the inputs were given correct npoints
|
||||
self.assertEqual(correct_map.get_npoints('1_2_1'), 0)
|
||||
self.assertEqual(correct_map.get_npoints('1_2_2'), 1)
|
||||
self.assertEqual(correct_map.get_npoints('1_2_3'), 1)
|
||||
self.assertTrue(0 <= correct_map.get_npoints('1_2_4') <= 1)
|
||||
assert correct_map.get_npoints('1_2_1') == 0
|
||||
assert correct_map.get_npoints('1_2_2') == 1
|
||||
assert correct_map.get_npoints('1_2_3') == 1
|
||||
assert 0 <= correct_map.get_npoints('1_2_4') <= 1
|
||||
|
||||
# Expect that we received messages for each individual input
|
||||
self.assertEqual(correct_map.get_msg('1_2_1'), 'Feedback 1')
|
||||
self.assertEqual(correct_map.get_msg('1_2_2'), 'Feedback 2')
|
||||
self.assertEqual(correct_map.get_msg('1_2_3'), 'Feedback 3')
|
||||
self.assertEqual(correct_map.get_msg('1_2_4'), 'Feedback 4')
|
||||
assert correct_map.get_msg('1_2_1') == 'Feedback 1'
|
||||
assert correct_map.get_msg('1_2_2') == 'Feedback 2'
|
||||
assert correct_map.get_msg('1_2_3') == 'Feedback 3'
|
||||
assert correct_map.get_msg('1_2_4') == 'Feedback 4'
|
||||
|
||||
def test_function_code_multiple_inputs_decimal_score(self):
|
||||
|
||||
@@ -2008,16 +2005,16 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
# Expect that the inputs were graded individually
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'incorrect')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_2'), 'correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_3'), 'correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_4'), 'partially-correct')
|
||||
assert correct_map.get_correctness('1_2_1') == 'incorrect'
|
||||
assert correct_map.get_correctness('1_2_2') == 'correct'
|
||||
assert correct_map.get_correctness('1_2_3') == 'correct'
|
||||
assert correct_map.get_correctness('1_2_4') == 'partially-correct'
|
||||
|
||||
# Expect that the inputs were given correct npoints
|
||||
self.assertEqual(correct_map.get_npoints('1_2_1'), 0.1)
|
||||
self.assertEqual(correct_map.get_npoints('1_2_2'), 0.9)
|
||||
self.assertEqual(correct_map.get_npoints('1_2_3'), 0.9)
|
||||
self.assertEqual(correct_map.get_npoints('1_2_4'), 0.7)
|
||||
assert correct_map.get_npoints('1_2_1') == 0.1
|
||||
assert correct_map.get_npoints('1_2_2') == 0.9
|
||||
assert correct_map.get_npoints('1_2_3') == 0.9
|
||||
assert correct_map.get_npoints('1_2_4') == 0.7
|
||||
|
||||
def test_function_code_with_extra_args(self):
|
||||
script = textwrap.dedent("""\
|
||||
@@ -2048,8 +2045,8 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
|
||||
self.assertEqual(correctness, 'correct')
|
||||
self.assertEqual(msg, "Message text")
|
||||
assert correctness == 'correct'
|
||||
assert msg == 'Message text'
|
||||
|
||||
# Partially Correct answer
|
||||
input_dict = {'1_2_1': '21'}
|
||||
@@ -2058,8 +2055,8 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
|
||||
self.assertEqual(correctness, 'partially-correct')
|
||||
self.assertEqual(msg, "Message text")
|
||||
assert correctness == 'partially-correct'
|
||||
assert msg == 'Message text'
|
||||
|
||||
# Incorrect answer
|
||||
input_dict = {'1_2_1': '0'}
|
||||
@@ -2068,8 +2065,8 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
|
||||
self.assertEqual(correctness, 'incorrect')
|
||||
self.assertEqual(msg, "Message text")
|
||||
assert correctness == 'incorrect'
|
||||
assert msg == 'Message text'
|
||||
|
||||
def test_function_code_with_attempt_number(self):
|
||||
script = textwrap.dedent("""\
|
||||
@@ -2098,8 +2095,8 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
|
||||
self.assertEqual(correctness, 'correct')
|
||||
self.assertEqual(msg, "This is attempt number 1")
|
||||
assert correctness == 'correct'
|
||||
assert msg == 'This is attempt number 1'
|
||||
|
||||
# second attempt
|
||||
problem.context['attempt'] = 2
|
||||
@@ -2108,8 +2105,8 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correctness = correct_map.get_correctness('1_2_1')
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
|
||||
self.assertEqual(correctness, 'correct')
|
||||
self.assertEqual(msg, "This is attempt number 2")
|
||||
assert correctness == 'correct'
|
||||
assert msg == 'This is attempt number 2'
|
||||
|
||||
def test_multiple_inputs_return_one_status(self):
|
||||
# When given multiple inputs, the 'answer_given' argument
|
||||
@@ -2143,30 +2140,30 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
# Everything marked incorrect
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'incorrect')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_2'), 'incorrect')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_3'), 'incorrect')
|
||||
assert correct_map.get_correctness('1_2_1') == 'incorrect'
|
||||
assert correct_map.get_correctness('1_2_2') == 'incorrect'
|
||||
assert correct_map.get_correctness('1_2_3') == 'incorrect'
|
||||
|
||||
# Grade the inputs (one input partially correct)
|
||||
input_dict = {'1_2_1': '-1', '1_2_2': '2', '1_2_3': '3'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
# Everything marked partially correct
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'partially-correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_2'), 'partially-correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_3'), 'partially-correct')
|
||||
assert correct_map.get_correctness('1_2_1') == 'partially-correct'
|
||||
assert correct_map.get_correctness('1_2_2') == 'partially-correct'
|
||||
assert correct_map.get_correctness('1_2_3') == 'partially-correct'
|
||||
|
||||
# Grade the inputs (everything correct)
|
||||
input_dict = {'1_2_1': '1', '1_2_2': '2', '1_2_3': '3'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
# Everything marked incorrect
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_2'), 'correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_3'), 'correct')
|
||||
assert correct_map.get_correctness('1_2_1') == 'correct'
|
||||
assert correct_map.get_correctness('1_2_2') == 'correct'
|
||||
assert correct_map.get_correctness('1_2_3') == 'correct'
|
||||
|
||||
# Message is interpreted as an "overall message"
|
||||
self.assertEqual(correct_map.get_overall_message(), 'Message text')
|
||||
assert correct_map.get_overall_message() == 'Message text'
|
||||
|
||||
def test_script_exception_function(self):
|
||||
|
||||
@@ -2179,7 +2176,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
problem = self.build_problem(script=script, cfn="check_func")
|
||||
|
||||
# Expect that an exception gets raised when we check the answer
|
||||
with self.assertRaises(ResponseError):
|
||||
with pytest.raises(ResponseError):
|
||||
problem.grade_answers({'1_2_1': '42'})
|
||||
|
||||
def test_script_exception_inline(self):
|
||||
@@ -2189,7 +2186,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
problem = self.build_problem(answer=script)
|
||||
|
||||
# Expect that an exception gets raised when we check the answer
|
||||
with self.assertRaises(ResponseError):
|
||||
with pytest.raises(ResponseError):
|
||||
problem.grade_answers({'1_2_1': '42'})
|
||||
|
||||
def test_invalid_dict_exception(self):
|
||||
@@ -2203,7 +2200,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
problem = self.build_problem(script=script, cfn="check_func")
|
||||
|
||||
# Expect that an exception gets raised when we check the answer
|
||||
with self.assertRaises(ResponseError):
|
||||
with pytest.raises(ResponseError):
|
||||
problem.grade_answers({'1_2_1': '42'})
|
||||
|
||||
def test_setup_randomization(self):
|
||||
@@ -2212,7 +2209,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
num = {code}
|
||||
""".format(code=self._get_random_number_code()))
|
||||
problem = self.build_problem(script=script)
|
||||
self.assertEqual(problem.context['num'], self._get_random_number_result(problem.seed))
|
||||
assert problem.context['num'] == self._get_random_number_result(problem.seed)
|
||||
|
||||
def test_check_function_randomization(self):
|
||||
# The check function should get random-seeded from the problem.
|
||||
@@ -2225,7 +2222,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
input_dict = {'1_2_1': '42'}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
msg = correct_map.get_msg('1_2_1')
|
||||
self.assertEqual(msg, self._get_random_number_result(problem.seed))
|
||||
assert msg == self._get_random_number_result(problem.seed)
|
||||
|
||||
def test_random_isnt_none(self):
|
||||
# Bug LMS-500 says random.seed(10) fails with:
|
||||
@@ -2243,7 +2240,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
num = random.randint(0, 1e9)
|
||||
""")
|
||||
problem = self.build_problem(script=script)
|
||||
self.assertEqual(problem.context['num'], num)
|
||||
assert problem.context['num'] == num
|
||||
|
||||
def test_module_imports_inline(self):
|
||||
'''
|
||||
@@ -2322,7 +2319,7 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
capa_system = test_capa_system()
|
||||
capa_system.get_python_lib_zip = lambda: zipstring.getvalue() # lint-amnesty, pylint: disable=unnecessary-lambda
|
||||
problem = self.build_problem(script=script, capa_system=capa_system)
|
||||
self.assertEqual(problem.context['num'], 17)
|
||||
assert problem.context['num'] == 17
|
||||
|
||||
def test_function_code_multiple_inputs_order(self):
|
||||
# Ensure that order must be correct according to sub-problem position
|
||||
@@ -2378,18 +2375,18 @@ class CustomResponseTest(ResponseTest): # pylint: disable=missing-class-docstri
|
||||
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
self.assertNotEqual(list(problem.student_answers.keys()), correct_order)
|
||||
assert list(problem.student_answers.keys()) != correct_order
|
||||
|
||||
# euqal to correct order after sorting at get_score
|
||||
self.assertListEqual(list(problem.responders.values())[0].context['idset'], correct_order)
|
||||
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_9'), 'correct')
|
||||
self.assertEqual(correct_map.get_correctness('1_2_11'), 'incorrect')
|
||||
assert correct_map.get_correctness('1_2_1') == 'correct'
|
||||
assert correct_map.get_correctness('1_2_9') == 'correct'
|
||||
assert correct_map.get_correctness('1_2_11') == 'incorrect'
|
||||
|
||||
self.assertEqual(correct_map.get_msg('1_2_1'), '1')
|
||||
self.assertEqual(correct_map.get_msg('1_2_9'), '9')
|
||||
self.assertEqual(correct_map.get_msg('1_2_11'), '11')
|
||||
assert correct_map.get_msg('1_2_1') == '1'
|
||||
assert correct_map.get_msg('1_2_9') == '9'
|
||||
assert correct_map.get_msg('1_2_11') == '11'
|
||||
|
||||
|
||||
class SchematicResponseTest(ResponseTest):
|
||||
@@ -2420,7 +2417,7 @@ class SchematicResponseTest(ResponseTest):
|
||||
# Expect that the problem is graded as true
|
||||
# (That is, our script verifies that the context
|
||||
# is what we expect)
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
|
||||
assert correct_map.get_correctness('1_2_1') == 'correct'
|
||||
|
||||
def test_check_function_randomization(self):
|
||||
# The check function should get a random seed from the problem.
|
||||
@@ -2431,7 +2428,7 @@ class SchematicResponseTest(ResponseTest):
|
||||
input_dict = {'1_2_1': json.dumps(submission_dict)}
|
||||
correct_map = problem.grade_answers(input_dict)
|
||||
|
||||
self.assertEqual(correct_map.get_correctness('1_2_1'), 'correct')
|
||||
assert correct_map.get_correctness('1_2_1') == 'correct'
|
||||
|
||||
def test_script_exception(self):
|
||||
# Construct a script that will raise an exception
|
||||
@@ -2439,7 +2436,7 @@ class SchematicResponseTest(ResponseTest):
|
||||
problem = self.build_problem(answer=script)
|
||||
|
||||
# Expect that an exception gets raised when we check the answer
|
||||
with self.assertRaises(ResponseError):
|
||||
with pytest.raises(ResponseError):
|
||||
submission_dict = {'test': 'test'}
|
||||
input_dict = {'1_2_1': json.dumps(submission_dict)}
|
||||
problem.grade_answers(input_dict)
|
||||
@@ -2476,10 +2473,9 @@ class AnnotationResponseTest(ResponseTest): # lint-amnesty, pylint: disable=mis
|
||||
actual_correctness = correct_map.get_correctness(answer_id)
|
||||
actual_points = correct_map.get_npoints(answer_id)
|
||||
|
||||
self.assertEqual(expected_correctness, actual_correctness,
|
||||
msg="%s should be marked %s" % (answer_id, expected_correctness))
|
||||
self.assertEqual(expected_points, actual_points,
|
||||
msg="%s should have %d points" % (answer_id, expected_points))
|
||||
assert expected_correctness == actual_correctness,\
|
||||
('%s should be marked %s' % (answer_id, expected_correctness))
|
||||
assert expected_points == actual_points, ('%s should have %d points' % (answer_id, expected_points))
|
||||
|
||||
|
||||
class ChoiceTextResponseTest(ResponseTest):
|
||||
@@ -2654,7 +2650,7 @@ class ChoiceTextResponseTest(ResponseTest):
|
||||
"""
|
||||
Test that build problem raises errors for invalid options
|
||||
"""
|
||||
with self.assertRaises(Exception):
|
||||
with pytest.raises(Exception):
|
||||
self.build_problem(type="invalidtextgroup")
|
||||
|
||||
def test_unchecked_input_not_validated(self):
|
||||
|
||||
@@ -35,9 +35,9 @@ class CapaShuffleTest(unittest.TestCase):
|
||||
self.assertRegex(the_html, r"<div>.*\[.*'Banana'.*'Apple'.*'Chocolate'.*'Donut'.*\].*</div>")
|
||||
# Check that choice name masking is enabled and that unmasking works
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertEqual(response.unmask_order(), ['choice_1', 'choice_0', 'choice_2', 'choice_3'])
|
||||
self.assertEqual(the_html, problem.get_html(), 'should be able to call get_html() twice')
|
||||
assert not response.has_mask()
|
||||
assert response.unmask_order() == ['choice_1', 'choice_0', 'choice_2', 'choice_3']
|
||||
assert the_html == problem.get_html(), 'should be able to call get_html() twice'
|
||||
|
||||
def test_shuffle_custom_names(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
@@ -56,9 +56,9 @@ class CapaShuffleTest(unittest.TestCase):
|
||||
# B A C D
|
||||
# Check that the custom name= names come through
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertTrue(response.has_shuffle())
|
||||
self.assertEqual(response.unmask_order(), ['choice_0', 'choice_aaa', 'choice_1', 'choice_ddd'])
|
||||
assert not response.has_mask()
|
||||
assert response.has_shuffle()
|
||||
assert response.unmask_order() == ['choice_0', 'choice_aaa', 'choice_1', 'choice_ddd']
|
||||
|
||||
def test_shuffle_different_seed(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
@@ -91,9 +91,9 @@ class CapaShuffleTest(unittest.TestCase):
|
||||
the_html = problem.get_html()
|
||||
self.assertRegex(the_html, r"<div>.*\[.*'Apple'.*\].*</div>")
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertTrue(response.has_shuffle())
|
||||
self.assertEqual(response.unmask_order(), ['choice_0'])
|
||||
assert not response.has_mask()
|
||||
assert response.has_shuffle()
|
||||
assert response.unmask_order() == ['choice_0']
|
||||
|
||||
def test_shuffle_6_choices(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
@@ -132,8 +132,8 @@ class CapaShuffleTest(unittest.TestCase):
|
||||
the_html = problem.get_html()
|
||||
self.assertRegex(the_html, r"<div>.*\[.*'Apple'.*'Banana'.*'Chocolate'.*'Donut'.*\].*</div>")
|
||||
response = list(problem.responders.values())[0]
|
||||
self.assertFalse(response.has_mask())
|
||||
self.assertFalse(response.has_shuffle())
|
||||
assert not response.has_mask()
|
||||
assert not response.has_shuffle()
|
||||
|
||||
def test_shuffle_fixed_head_end(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
@@ -275,18 +275,18 @@ class CapaShuffleTest(unittest.TestCase):
|
||||
""")
|
||||
problem = new_loncapa_problem(xml_str, seed=0)
|
||||
orig_html = problem.get_html()
|
||||
self.assertEqual(orig_html, problem.get_html(), 'should be able to call get_html() twice')
|
||||
assert orig_html == problem.get_html(), 'should be able to call get_html() twice'
|
||||
html = orig_html.replace('\n', ' ') # avoid headaches with .* matching
|
||||
print(html)
|
||||
self.assertRegex(html, r"<div>.*\[.*'Banana'.*'Apple'.*'Chocolate'.*'Donut'.*\].*</div>.*" +
|
||||
r"<div>.*\[.*'C'.*'A'.*'D'.*'B'.*\].*</div>")
|
||||
# Look at the responses in their authored order
|
||||
responses = sorted(list(problem.responders.values()), key=lambda resp: int(resp.id[resp.id.rindex('_') + 1:]))
|
||||
self.assertFalse(responses[0].has_mask())
|
||||
self.assertTrue(responses[0].has_shuffle())
|
||||
self.assertTrue(responses[1].has_shuffle())
|
||||
self.assertEqual(responses[0].unmask_order(), ['choice_1', 'choice_0', 'choice_2', 'choice_3'])
|
||||
self.assertEqual(responses[1].unmask_order(), ['choice_2', 'choice_0', 'choice_3', 'choice_1'])
|
||||
assert not responses[0].has_mask()
|
||||
assert responses[0].has_shuffle()
|
||||
assert responses[1].has_shuffle()
|
||||
assert responses[0].unmask_order() == ['choice_1', 'choice_0', 'choice_2', 'choice_3']
|
||||
assert responses[1].unmask_order() == ['choice_2', 'choice_0', 'choice_3', 'choice_1']
|
||||
|
||||
def test_shuffle_not_with_answerpool(self):
|
||||
"""Raise error if shuffle and answer-pool are both used."""
|
||||
|
||||
@@ -91,7 +91,7 @@ class CapaTargetedFeedbackTest(unittest.TestCase):
|
||||
|
||||
self.assertRegex(without_new_lines, r"<div>.*'wrong-1'.*'wrong-2'.*'correct-1'.*'wrong-3'.*</div>")
|
||||
self.assertNotRegex(without_new_lines, r"feedback1|feedback2|feedback3|feedbackC")
|
||||
self.assertEqual(the_html, problem.get_html(), "Should be able to call get_html() twice")
|
||||
assert the_html == problem.get_html(), 'Should be able to call get_html() twice'
|
||||
|
||||
def test_targeted_feedback_student_answer1(self):
|
||||
problem = new_loncapa_problem(load_fixture('targeted_feedback.xml'))
|
||||
@@ -105,7 +105,7 @@ class CapaTargetedFeedbackTest(unittest.TestCase):
|
||||
self.assertNotRegex(without_new_lines, r"feedback1|feedback2|feedbackC")
|
||||
# Check that calling it multiple times yields the same thing
|
||||
the_html2 = problem.get_html()
|
||||
self.assertEqual(the_html, the_html2)
|
||||
assert the_html == the_html2
|
||||
|
||||
def test_targeted_feedback_student_answer2(self):
|
||||
problem = new_loncapa_problem(load_fixture('targeted_feedback.xml'))
|
||||
@@ -304,7 +304,7 @@ class CapaTargetedFeedbackTest(unittest.TestCase):
|
||||
self.assertNotRegex(without_new_lines, r"feedback2|feedback3")
|
||||
# Check that calling it multiple times yields the same thing
|
||||
the_html2 = problem.get_html()
|
||||
self.assertEqual(the_html, the_html2)
|
||||
assert the_html == the_html2
|
||||
|
||||
def test_targeted_feedback_no_show_solution_explanation(self):
|
||||
xml_str = textwrap.dedent("""
|
||||
|
||||
@@ -30,94 +30,94 @@ class UtilTest(unittest.TestCase):
|
||||
def test_compare_with_tolerance(self): # lint-amnesty, pylint: disable=too-many-statements
|
||||
# Test default tolerance '0.001%' (it is relative)
|
||||
result = compare_with_tolerance(100.0, 100.0)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(100.001, 100.0)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(101.0, 100.0)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
# Test absolute percentage tolerance
|
||||
result = compare_with_tolerance(109.9, 100.0, '10%', False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(110.1, 100.0, '10%', False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
# Test relative percentage tolerance
|
||||
result = compare_with_tolerance(111.0, 100.0, '10%', True)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(112.0, 100.0, '10%', True)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
# Test absolute tolerance (string)
|
||||
result = compare_with_tolerance(109.9, 100.0, '10.0', False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(110.1, 100.0, '10.0', False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
# Test relative tolerance (string)
|
||||
result = compare_with_tolerance(111.0, 100.0, '0.1', True)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(112.0, 100.0, '0.1', True)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
# Test absolute tolerance (float)
|
||||
result = compare_with_tolerance(109.9, 100.0, 10.0, False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(110.1, 100.0, 10.0, False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
# Test relative tolerance (float)
|
||||
result = compare_with_tolerance(111.0, 100.0, 0.1, True)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(112.0, 100.0, 0.1, True)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
##### Infinite values #####
|
||||
infinity = float('Inf')
|
||||
# Test relative tolerance (float)
|
||||
result = compare_with_tolerance(infinity, 100.0, 1.0, True)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(100.0, infinity, 1.0, True)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(infinity, infinity, 1.0, True)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
# Test absolute tolerance (float)
|
||||
result = compare_with_tolerance(infinity, 100.0, 1.0, False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(100.0, infinity, 1.0, False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(infinity, infinity, 1.0, False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
# Test relative tolerance (string)
|
||||
result = compare_with_tolerance(infinity, 100.0, '1.0', True)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(100.0, infinity, '1.0', True)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(infinity, infinity, '1.0', True)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
# Test absolute tolerance (string)
|
||||
result = compare_with_tolerance(infinity, 100.0, '1.0', False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(100.0, infinity, '1.0', False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(infinity, infinity, '1.0', False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
# Test absolute tolerance for smaller values
|
||||
result = compare_with_tolerance(100.01, 100.0, 0.01, False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(100.001, 100.0, 0.001, False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(100.01, 100.0, '0.01%', False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(100.002, 100.0, 0.001, False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(0.4, 0.44, 0.01, False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(100.01, 100.0, 0.010, False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
|
||||
# Test complex_number instructor_complex
|
||||
result = compare_with_tolerance(0.4, complex(0.44, 0), 0.01, False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(100.01, complex(100.0, 0), 0.010, False)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
result = compare_with_tolerance(110.1, complex(100.0, 0), '10.0', False)
|
||||
self.assertFalse(result)
|
||||
assert not result
|
||||
result = compare_with_tolerance(111.0, complex(100.0, 0), '10%', True)
|
||||
self.assertTrue(result)
|
||||
assert result
|
||||
|
||||
def test_sanitize_html(self):
|
||||
"""
|
||||
@@ -126,28 +126,26 @@ class UtilTest(unittest.TestCase):
|
||||
allowed_tags = ['div', 'p', 'audio', 'pre', 'span']
|
||||
for tag in allowed_tags:
|
||||
queue_msg = "<{0}>Test message</{0}>".format(tag)
|
||||
self.assertEqual(sanitize_html(queue_msg), queue_msg)
|
||||
assert sanitize_html(queue_msg) == queue_msg
|
||||
|
||||
not_allowed_tag = 'script'
|
||||
queue_msg = "<{0}>Test message</{0}>".format(not_allowed_tag)
|
||||
expected = "<script>Test message</script>"
|
||||
self.assertEqual(sanitize_html(queue_msg), 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('<hint style="smtng">aa<a href="#">bb</a>cc</hint>')
|
||||
self.assertEqual(get_inner_html_from_xpath(xpath_node), 'aa<a href="#">bb</a>cc')
|
||||
assert get_inner_html_from_xpath(xpath_node) == 'aa<a href="#">bb</a>cc'
|
||||
|
||||
def test_remove_markup(self):
|
||||
"""
|
||||
Test for markup removal with bleach.
|
||||
"""
|
||||
self.assertEqual(
|
||||
remove_markup("The <mark>Truth</mark> is <em>Out There</em> & you need to <strong>find</strong> it"),
|
||||
"The Truth is Out There & you need to find it"
|
||||
)
|
||||
assert remove_markup('The <mark>Truth</mark> is <em>Out There</em> & you need to <strong>find</strong> 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.',
|
||||
@@ -159,7 +157,7 @@ class UtilTest(unittest.TestCase):
|
||||
text = '$answer0'
|
||||
context = {key: context_value}
|
||||
contextual_text = contextualize_text(text, context)
|
||||
self.assertEqual(context_value, contextual_text)
|
||||
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."""
|
||||
@@ -168,4 +166,4 @@ class UtilTest(unittest.TestCase):
|
||||
context = {'a': u'あなたあなたあなた', 'b': u'あなたhi'}
|
||||
expected_text = '$あなたあなたあなたあなた あなたhi'
|
||||
contextual_text = contextualize_text(text, context)
|
||||
self.assertEqual(expected_text, contextual_text)
|
||||
assert expected_text == contextual_text
|
||||
|
||||
@@ -12,34 +12,34 @@ class Test_PositionsCompare(unittest.TestCase):
|
||||
""" describe"""
|
||||
|
||||
def test_nested_list_and_list1(self):
|
||||
self.assertEqual(PositionsCompare([[1, 2], 40]), PositionsCompare([1, 3]))
|
||||
assert PositionsCompare([[1, 2], 40]) == PositionsCompare([1, 3])
|
||||
|
||||
def test_nested_list_and_list2(self):
|
||||
self.assertNotEqual(PositionsCompare([1, 12]), PositionsCompare([1, 1]))
|
||||
assert PositionsCompare([1, 12]) != PositionsCompare([1, 1])
|
||||
|
||||
def test_list_and_list1(self):
|
||||
self.assertNotEqual(PositionsCompare([[1, 2], 12]), PositionsCompare([1, 15]))
|
||||
assert PositionsCompare([[1, 2], 12]) != PositionsCompare([1, 15])
|
||||
|
||||
def test_list_and_list2(self):
|
||||
self.assertEqual(PositionsCompare([1, 11]), PositionsCompare([1, 1]))
|
||||
assert PositionsCompare([1, 11]) == PositionsCompare([1, 1])
|
||||
|
||||
def test_numerical_list_and_string_list(self):
|
||||
self.assertNotEqual(PositionsCompare([1, 2]), PositionsCompare(["1"]))
|
||||
assert PositionsCompare([1, 2]) != PositionsCompare(['1'])
|
||||
|
||||
def test_string_and_string_list1(self):
|
||||
self.assertEqual(PositionsCompare("1"), PositionsCompare(["1"]))
|
||||
assert PositionsCompare('1') == PositionsCompare(['1'])
|
||||
|
||||
def test_string_and_string_list2(self):
|
||||
self.assertEqual(PositionsCompare("abc"), PositionsCompare("abc"))
|
||||
assert PositionsCompare('abc') == PositionsCompare('abc')
|
||||
|
||||
def test_string_and_string_list3(self):
|
||||
self.assertNotEqual(PositionsCompare("abd"), PositionsCompare("abe"))
|
||||
assert PositionsCompare('abd') != PositionsCompare('abe')
|
||||
|
||||
def test_float_and_string(self):
|
||||
self.assertNotEqual(PositionsCompare([3.5, 5.7]), PositionsCompare(["1"]))
|
||||
assert PositionsCompare([3.5, 5.7]) != PositionsCompare(['1'])
|
||||
|
||||
def test_floats_and_ints(self):
|
||||
self.assertEqual(PositionsCompare([3.5, 4.5]), PositionsCompare([5, 7]))
|
||||
assert PositionsCompare([3.5, 4.5]) == PositionsCompare([5, 7])
|
||||
|
||||
|
||||
class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -64,7 +64,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'anyof'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_targets_are_draggable_2(self):
|
||||
user_input = json.dumps([
|
||||
@@ -107,7 +107,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'unordered_equal'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_targets_are_draggable_2_manual_parsing(self):
|
||||
user_input = json.dumps([
|
||||
@@ -150,7 +150,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'unordered_equal'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_targets_are_draggable_3_nested(self):
|
||||
user_input = json.dumps([
|
||||
@@ -209,7 +209,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'unordered_equal'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_targets_are_draggable_4_real_example(self):
|
||||
user_input = json.dumps([
|
||||
@@ -283,83 +283,83 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
},
|
||||
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_targets_true(self):
|
||||
user_input = '[{"1": "t1"}, \
|
||||
{"name_with_icon": "t2"}]'
|
||||
correct_answer = {'1': 't1', 'name_with_icon': 't2'}
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_expect_no_actions_wrong(self):
|
||||
user_input = '[{"1": "t1"}, \
|
||||
{"name_with_icon": "t2"}]'
|
||||
correct_answer = []
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_expect_no_actions_right(self):
|
||||
user_input = '[]'
|
||||
correct_answer = []
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_targets_false(self):
|
||||
user_input = '[{"1": "t1"}, \
|
||||
{"name_with_icon": "t2"}]'
|
||||
correct_answer = {'1': 't3', 'name_with_icon': 't2'}
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_multiple_images_per_target_true(self):
|
||||
user_input = '[{"1": "t1"}, {"name_with_icon": "t2"}, \
|
||||
{"2": "t1"}]'
|
||||
correct_answer = {'1': 't1', 'name_with_icon': 't2', '2': 't1'}
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_multiple_images_per_target_false(self):
|
||||
user_input = '[{"1": "t1"}, {"name_with_icon": "t2"}, \
|
||||
{"2": "t1"}]'
|
||||
correct_answer = {'1': 't2', 'name_with_icon': 't2', '2': 't1'}
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_targets_and_positions(self):
|
||||
user_input = '[{"1": [10,10]}, \
|
||||
{"name_with_icon": [[10,10],4]}]'
|
||||
correct_answer = {'1': [10, 10], 'name_with_icon': [[10, 10], 4]}
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_position_and_targets(self):
|
||||
user_input = '[{"1": "t1"}, {"name_with_icon": "t2"}]'
|
||||
correct_answer = {'1': 't1', 'name_with_icon': 't2'}
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_positions_exact(self):
|
||||
user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]'
|
||||
correct_answer = {'1': [10, 10], 'name_with_icon': [20, 20]}
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_positions_false(self):
|
||||
user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]'
|
||||
correct_answer = {'1': [25, 25], 'name_with_icon': [20, 20]}
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_positions_true_in_radius(self):
|
||||
user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]'
|
||||
correct_answer = {'1': [14, 14], 'name_with_icon': [20, 20]}
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_positions_true_in_manual_radius(self):
|
||||
user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]'
|
||||
correct_answer = {'1': [[40, 10], 30], 'name_with_icon': [20, 20]}
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_positions_false_in_manual_radius(self):
|
||||
user_input = '[{"1": [10, 10]}, {"name_with_icon": [20, 20]}]'
|
||||
correct_answer = {'1': [[40, 10], 29], 'name_with_icon': [20, 20]}
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_correct_answer_not_has_key_from_user_answer(self):
|
||||
user_input = '[{"1": "t1"}, {"name_with_icon": "t2"}]'
|
||||
correct_answer = {'3': 't3', 'name_with_icon': 't2'}
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_anywhere(self):
|
||||
"""Draggables can be places anywhere on base image.
|
||||
@@ -369,7 +369,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
{"grass":[322.5,199.449951171875]}]'
|
||||
|
||||
correct_answer = {'grass': [[300, 200], 200], 'ant': [[500, 0], 200]}
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_lcao_correct(self):
|
||||
"""Describe carbon molecule in LCAO-MO"""
|
||||
@@ -408,7 +408,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'anyof'
|
||||
}]
|
||||
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_lcao_extra_element_incorrect(self):
|
||||
"""Describe carbon molecule in LCAO-MO"""
|
||||
@@ -447,7 +447,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'anyof'
|
||||
}]
|
||||
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_reuse_draggable_no_mupliples(self):
|
||||
"""Test reusable draggables (no mupltiple draggables per target)"""
|
||||
@@ -471,7 +471,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'anyof'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_reuse_draggable_with_mupliples(self):
|
||||
"""Test reusable draggables with mupltiple draggables per target"""
|
||||
@@ -495,7 +495,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'anyof'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_reuse_many_draggable_with_mupliples(self):
|
||||
"""Test reusable draggables with mupltiple draggables per target"""
|
||||
@@ -525,7 +525,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'anyof'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_reuse_many_draggable_with_mupliples_wrong(self):
|
||||
"""Test reusable draggables with mupltiple draggables per target"""
|
||||
@@ -556,7 +556,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'targets': ['target6'],
|
||||
'rule': 'anyof'
|
||||
}]
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_label_10_targets_with_a_b_c_false(self):
|
||||
"""Test reusable draggables (no mupltiple draggables per target)"""
|
||||
@@ -581,7 +581,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'unordered_equal'
|
||||
}
|
||||
]
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_label_10_targets_with_a_b_c_(self):
|
||||
"""Test reusable draggables (no mupltiple draggables per target)"""
|
||||
@@ -606,7 +606,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'unordered_equal'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_label_10_targets_with_a_b_c_multiple(self):
|
||||
"""Test reusable draggables (mupltiple draggables per target)"""
|
||||
@@ -631,7 +631,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'anyof+number'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_label_10_targets_with_a_b_c_multiple_false(self):
|
||||
"""Test reusable draggables (mupltiple draggables per target)"""
|
||||
@@ -656,7 +656,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'anyof+number'
|
||||
}
|
||||
]
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_label_10_targets_with_a_b_c_reused(self):
|
||||
"""Test a b c in 10 labels reused"""
|
||||
@@ -681,7 +681,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'unordered_equal+number'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_label_10_targets_with_a_b_c_reused_false(self):
|
||||
"""Test a b c in 10 labels reused false"""
|
||||
@@ -706,7 +706,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'unordered_equal+number'
|
||||
}
|
||||
]
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_mixed_reuse_and_not_reuse(self):
|
||||
"""Test reusable draggables """
|
||||
@@ -725,7 +725,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'exact'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_mixed_reuse_and_not_reuse_number(self):
|
||||
"""Test reusable draggables with number """
|
||||
@@ -743,7 +743,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'exact'
|
||||
}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_mixed_reuse_and_not_reuse_number_false(self):
|
||||
"""Test reusable draggables with numbers, but wrong"""
|
||||
@@ -761,7 +761,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
'rule': 'exact'
|
||||
}
|
||||
]
|
||||
self.assertFalse(draganddrop.grade(user_input, correct_answer))
|
||||
assert not draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
def test_alternative_correct_answer(self):
|
||||
user_input = '[{"name_with_icon":"t1"},\
|
||||
@@ -772,7 +772,7 @@ class Test_DragAndDrop_Grade(unittest.TestCase): # lint-amnesty, pylint: disabl
|
||||
{'draggables': ['name_with_icon'], 'targets': ['t1', 't1', 't1'],
|
||||
'rule': 'exact'}
|
||||
]
|
||||
self.assertTrue(draganddrop.grade(user_input, correct_answer))
|
||||
assert draganddrop.grade(user_input, correct_answer)
|
||||
|
||||
|
||||
class Test_DragAndDrop_Populate(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -787,61 +787,45 @@ class Test_DragAndDrop_Populate(unittest.TestCase): # lint-amnesty, pylint: dis
|
||||
user_groups = [['1'], ['name_with_icon']]
|
||||
user_positions = [{'user': [[10, 10]]}, {'user': [[20, 20]]}]
|
||||
|
||||
self.assertEqual(correct_groups, dnd.correct_groups)
|
||||
self.assertEqual(correct_positions, dnd.correct_positions)
|
||||
self.assertEqual(user_groups, dnd.user_groups)
|
||||
self.assertEqual(user_positions, dnd.user_positions)
|
||||
assert correct_groups == dnd.correct_groups
|
||||
assert correct_positions == dnd.correct_positions
|
||||
assert user_groups == dnd.user_groups
|
||||
assert user_positions == dnd.user_positions
|
||||
|
||||
|
||||
class Test_DraAndDrop_Compare_Positions(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
|
||||
def test_1(self):
|
||||
dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]')
|
||||
self.assertTrue(dnd.compare_positions(correct=[[1, 1], [2, 3]],
|
||||
user=[[2, 3], [1, 1]],
|
||||
flag='anyof'))
|
||||
assert dnd.compare_positions(correct=[[1, 1], [2, 3]], user=[[2, 3], [1, 1]], flag='anyof')
|
||||
|
||||
def test_2a(self):
|
||||
dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]')
|
||||
self.assertTrue(dnd.compare_positions(correct=[[1, 1], [2, 3]],
|
||||
user=[[2, 3], [1, 1]],
|
||||
flag='exact'))
|
||||
assert dnd.compare_positions(correct=[[1, 1], [2, 3]], user=[[2, 3], [1, 1]], flag='exact')
|
||||
|
||||
def test_2b(self):
|
||||
dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]')
|
||||
self.assertFalse(dnd.compare_positions(correct=[[1, 1], [2, 3]],
|
||||
user=[[2, 13], [1, 1]],
|
||||
flag='exact'))
|
||||
assert not dnd.compare_positions(correct=[[1, 1], [2, 3]], user=[[2, 13], [1, 1]], flag='exact')
|
||||
|
||||
def test_3(self):
|
||||
dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]')
|
||||
self.assertFalse(dnd.compare_positions(correct=["a", "b"],
|
||||
user=["a", "b", "c"],
|
||||
flag='anyof'))
|
||||
assert not dnd.compare_positions(correct=['a', 'b'], user=['a', 'b', 'c'], flag='anyof')
|
||||
|
||||
def test_4(self):
|
||||
dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]')
|
||||
self.assertTrue(dnd.compare_positions(correct=["a", "b", "c"],
|
||||
user=["a", "b"],
|
||||
flag='anyof'))
|
||||
assert dnd.compare_positions(correct=['a', 'b', 'c'], user=['a', 'b'], flag='anyof')
|
||||
|
||||
def test_5(self):
|
||||
dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]')
|
||||
self.assertFalse(dnd.compare_positions(correct=["a", "b", "c"],
|
||||
user=["a", "c", "b"],
|
||||
flag='exact'))
|
||||
assert not dnd.compare_positions(correct=['a', 'b', 'c'], user=['a', 'c', 'b'], flag='exact')
|
||||
|
||||
def test_6(self):
|
||||
dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]')
|
||||
self.assertTrue(dnd.compare_positions(correct=["a", "b", "c"],
|
||||
user=["a", "c", "b"],
|
||||
flag='anyof'))
|
||||
assert dnd.compare_positions(correct=['a', 'b', 'c'], user=['a', 'c', 'b'], flag='anyof')
|
||||
|
||||
def test_7(self):
|
||||
dnd = draganddrop.DragAndDrop({'1': 't1'}, '[{"1": "t1"}]')
|
||||
self.assertFalse(dnd.compare_positions(correct=["a", "b", "b"],
|
||||
user=["a", "c", "b"],
|
||||
flag='anyof'))
|
||||
assert not dnd.compare_positions(correct=['a', 'b', 'b'], user=['a', 'c', 'b'], flag='anyof')
|
||||
|
||||
|
||||
def suite(): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
|
||||
@@ -43,7 +43,7 @@ class FormulaTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
test = etree.tostring(xml)
|
||||
|
||||
# success?
|
||||
self.assertEqual(test.decode('utf-8'), expected)
|
||||
assert test.decode('utf-8') == expected
|
||||
|
||||
def test_fix_simple_superscripts(self):
|
||||
expr = '''
|
||||
@@ -67,7 +67,7 @@ class FormulaTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
test = etree.tostring(xml)
|
||||
|
||||
# success?
|
||||
self.assertEqual(test.decode('utf-8'), expected)
|
||||
assert test.decode('utf-8') == expected
|
||||
|
||||
def test_fix_complex_superscripts(self):
|
||||
expr = '''
|
||||
@@ -92,7 +92,7 @@ class FormulaTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
test = etree.tostring(xml)
|
||||
|
||||
# success?
|
||||
self.assertEqual(test.decode('utf-8'), expected)
|
||||
assert test.decode('utf-8') == expected
|
||||
|
||||
def test_fix_msubsup(self):
|
||||
expr = '''
|
||||
@@ -114,4 +114,4 @@ class FormulaTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
test = etree.tostring(xml)
|
||||
|
||||
# success?
|
||||
self.assertEqual(test.decode('utf-8'), expected)
|
||||
assert test.decode('utf-8') == expected
|
||||
|
||||
@@ -32,7 +32,7 @@ class SymmathCheckTest(TestCase): # lint-amnesty, pylint: disable=missing-class
|
||||
|
||||
# Expect that the exact same symbolic string is marked correct
|
||||
result = symmath_check(expected_str, expected_str, dynamath=[dynamath])
|
||||
self.assertTrue('ok' in result and result['ok'])
|
||||
assert (('ok' in result) and result['ok'])
|
||||
|
||||
def test_symmath_check_equivalent_symbols(self):
|
||||
expected_str = "x+2*y"
|
||||
@@ -52,7 +52,7 @@ class SymmathCheckTest(TestCase): # lint-amnesty, pylint: disable=missing-class
|
||||
|
||||
# Expect that equivalent symbolic strings are marked correct
|
||||
result = symmath_check(expected_str, input_str, dynamath=[dynamath])
|
||||
self.assertTrue('ok' in result and result['ok'])
|
||||
assert (('ok' in result) and result['ok'])
|
||||
|
||||
def test_symmath_check_different_symbols(self):
|
||||
expected_str = "0"
|
||||
@@ -70,8 +70,8 @@ class SymmathCheckTest(TestCase): # lint-amnesty, pylint: disable=missing-class
|
||||
|
||||
# Expect that an incorrect response is marked incorrect
|
||||
result = symmath_check(expected_str, input_str, dynamath=[dynamath])
|
||||
self.assertTrue('ok' in result and not result['ok'])
|
||||
self.assertNotIn('fail', result['msg'])
|
||||
assert (('ok' in result) and (not result['ok']))
|
||||
assert 'fail' not in result['msg']
|
||||
|
||||
def _symmath_check_numbers(self, number_list): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
|
||||
@@ -81,11 +81,9 @@ class SymmathCheckTest(TestCase): # lint-amnesty, pylint: disable=missing-class
|
||||
expect = n
|
||||
ans = n
|
||||
result = symmath_check(str(expect), str(ans))
|
||||
self.assertTrue('ok' in result and result['ok'],
|
||||
"%f should == %f" % (expect, ans))
|
||||
assert (('ok' in result) and result['ok']), ('%f should == %f' % (expect, ans))
|
||||
|
||||
# Change expect so that it != ans
|
||||
expect += 0.1
|
||||
result = symmath_check(str(expect), str(ans))
|
||||
self.assertTrue('ok' in result and not result['ok'],
|
||||
"%f should != %f" % (expect, ans))
|
||||
assert (('ok' in result) and (not result['ok'])), ('%f should != %f' % (expect, ans))
|
||||
|
||||
@@ -4,6 +4,7 @@ Test for asset XML generation / parsing.
|
||||
|
||||
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
from contracts import ContractNotRespected
|
||||
from lxml import etree
|
||||
@@ -59,7 +60,7 @@ class TestAssetXml(unittest.TestCase):
|
||||
continue
|
||||
orig_value = getattr(asset_md, attr)
|
||||
new_value = getattr(new_asset_md, attr)
|
||||
self.assertEqual(orig_value, new_value)
|
||||
assert orig_value == new_value
|
||||
|
||||
def test_export_with_None_value(self):
|
||||
"""
|
||||
@@ -87,7 +88,7 @@ class TestAssetXml(unittest.TestCase):
|
||||
Ensure full asset sections with the wrong tag are detected.
|
||||
"""
|
||||
root = etree.Element("glassets")
|
||||
with self.assertRaises(ContractNotRespected):
|
||||
with pytest.raises(ContractNotRespected):
|
||||
AssetMetadata.add_all_assets_as_xml(root, self.course_assets)
|
||||
|
||||
def test_wrong_node_type_single(self):
|
||||
@@ -97,5 +98,5 @@ class TestAssetXml(unittest.TestCase):
|
||||
asset_md = self.course_assets[0]
|
||||
root = etree.Element("assets")
|
||||
asset = etree.SubElement(root, "smashset")
|
||||
with self.assertRaises(ContractNotRespected):
|
||||
with pytest.raises(ContractNotRespected):
|
||||
asset_md.to_xml(asset)
|
||||
|
||||
@@ -4,6 +4,7 @@ Simple test to ensure that modulestore base classes remain abstract
|
||||
|
||||
|
||||
from unittest import TestCase
|
||||
import pytest
|
||||
|
||||
from xmodule.modulestore import ModuleStoreRead, ModuleStoreWrite
|
||||
|
||||
@@ -14,5 +15,6 @@ class AbstractionTest(TestCase):
|
||||
"""
|
||||
|
||||
def test_cant_instantiate_abstract_class(self):
|
||||
self.assertRaises(TypeError, ModuleStoreRead) # Cannot be instantiated due to explicit abstraction
|
||||
self.assertRaises(TypeError, ModuleStoreWrite)
|
||||
pytest.raises(TypeError, ModuleStoreRead)
|
||||
# Cannot be instantiated due to explicit abstraction
|
||||
pytest.raises(TypeError, ModuleStoreWrite)
|
||||
|
||||
@@ -45,11 +45,11 @@ class TestAsidesXmlStore(TestCase):
|
||||
Check whether block has the expected aside w/ its fields and then recurse to the block's children
|
||||
"""
|
||||
asides = block.runtime.get_asides(block)
|
||||
self.assertEqual(len(asides), 1, "Found {} asides but expected only test_aside".format(asides))
|
||||
self.assertIsInstance(asides[0], AsideTestType)
|
||||
assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides)
|
||||
assert isinstance(asides[0], AsideTestType)
|
||||
category = block.scope_ids.block_type
|
||||
self.assertEqual(asides[0].data_field, "{} aside data".format(category))
|
||||
self.assertEqual(asides[0].content, "{} Aside".format(category.capitalize()))
|
||||
assert asides[0].data_field == '{} aside data'.format(category)
|
||||
assert asides[0].content == '{} Aside'.format(category.capitalize())
|
||||
|
||||
for child in block.get_children():
|
||||
check_block(child)
|
||||
|
||||
@@ -6,7 +6,7 @@ too.
|
||||
|
||||
import unittest
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import pytz
|
||||
import six
|
||||
@@ -83,16 +83,14 @@ class TestSortedAssetList(unittest.TestCase):
|
||||
|
||||
def test_exception_on_bad_sort(self):
|
||||
asset_key = self.course_key.make_asset_key('asset', 'pic1.jpg')
|
||||
with self.assertRaises(IncorrectlySortedList):
|
||||
with pytest.raises(IncorrectlySortedList):
|
||||
__ = self.sorted_asset_list_by_last_edit.find(asset_key)
|
||||
|
||||
def test_find(self):
|
||||
asset_key = self.course_key.make_asset_key('asset', 'asset.txt')
|
||||
self.assertEqual(self.sorted_asset_list_by_filename.find(asset_key), 0)
|
||||
assert self.sorted_asset_list_by_filename.find(asset_key) == 0
|
||||
asset_key_last = self.course_key.make_asset_key('asset', 'weather_patterns.bmp')
|
||||
self.assertEqual(
|
||||
self.sorted_asset_list_by_filename.find(asset_key_last), len(AssetStoreTestData.all_asset_data) - 1
|
||||
)
|
||||
assert self.sorted_asset_list_by_filename.find(asset_key_last) == (len(AssetStoreTestData.all_asset_data) - 1)
|
||||
|
||||
|
||||
@attr('mongo')
|
||||
@@ -126,7 +124,7 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
if type(mdata1) != type(mdata2): # lint-amnesty, pylint: disable=unidiomatic-typecheck
|
||||
self.fail(self._formatMessage(msg, u"{} is not same type as {}".format(mdata1, mdata2)))
|
||||
for attr in mdata1.ATTRS_ALLOWED_TO_UPDATE: # lint-amnesty, pylint: disable=redefined-outer-name
|
||||
self.assertEqual(getattr(mdata1, attr), getattr(mdata2, attr), msg)
|
||||
assert getattr(mdata1, attr) == getattr(mdata2, attr), msg
|
||||
|
||||
def _compare_datetimes(self, datetime1, datetime2, msg=None):
|
||||
"""
|
||||
@@ -188,9 +186,9 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
# Find the asset's metadata and confirm it's the same.
|
||||
found_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(found_asset_md)
|
||||
self.assertEqual(new_asset_md, found_asset_md)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'asset')), 1)
|
||||
assert found_asset_md is not None
|
||||
assert new_asset_md == found_asset_md
|
||||
assert len(store.get_all_asset_metadata(course.id, 'asset')) == 1
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_delete(self, storebuilder):
|
||||
@@ -201,13 +199,13 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
# Attempt to delete an asset that doesn't exist.
|
||||
self.assertEqual(store.delete_asset_metadata(new_asset_loc, ModuleStoreEnum.UserID.test), 0)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'asset')), 0)
|
||||
assert store.delete_asset_metadata(new_asset_loc, ModuleStoreEnum.UserID.test) == 0
|
||||
assert len(store.get_all_asset_metadata(course.id, 'asset')) == 0
|
||||
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
self.assertEqual(store.delete_asset_metadata(new_asset_loc, ModuleStoreEnum.UserID.test), 1)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'asset')), 0)
|
||||
assert store.delete_asset_metadata(new_asset_loc, ModuleStoreEnum.UserID.test) == 1
|
||||
assert len(store.get_all_asset_metadata(course.id, 'asset')) == 0
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_find_non_existing_assets(self, storebuilder):
|
||||
@@ -219,7 +217,7 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
new_asset_loc = course.id.make_asset_key('asset', 'burnside.jpg')
|
||||
# Find existing asset metadata.
|
||||
asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNone(asset_md)
|
||||
assert asset_md is None
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_get_all_non_existing_assets(self, storebuilder):
|
||||
@@ -230,7 +228,7 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
course = CourseFactory.create(modulestore=store)
|
||||
# Find existing asset metadata.
|
||||
asset_md = store.get_all_asset_metadata(course.id, 'asset')
|
||||
self.assertEqual(asset_md, [])
|
||||
assert asset_md == []
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_find_assets_in_non_existent_course(self, storebuilder):
|
||||
@@ -244,9 +242,9 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
))
|
||||
new_asset_loc = fake_course_id.make_asset_key('asset', 'burnside.jpg')
|
||||
# Find asset metadata from non-existent course.
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
store.find_asset_metadata(new_asset_loc)
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
store.get_all_asset_metadata(fake_course_id, 'asset')
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
@@ -260,11 +258,11 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
# Add asset metadata.
|
||||
store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'asset')), 1)
|
||||
assert len(store.get_all_asset_metadata(course.id, 'asset')) == 1
|
||||
# Add *the same* asset metadata.
|
||||
store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
# Still one here?
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'asset')), 1)
|
||||
assert len(store.get_all_asset_metadata(course.id, 'asset')) == 1
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_different_asset_types(self, storebuilder):
|
||||
@@ -277,8 +275,8 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
# Add asset metadata.
|
||||
store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'vrml')), 1)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'asset')), 0)
|
||||
assert len(store.get_all_asset_metadata(course.id, 'vrml')) == 1
|
||||
assert len(store.get_all_asset_metadata(course.id, 'asset')) == 0
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_asset_types_with_other_field_names(self, storebuilder):
|
||||
@@ -291,10 +289,10 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
new_asset_md = self._make_asset_metadata(new_asset_loc)
|
||||
# Add asset metadata.
|
||||
store.save_asset_metadata(new_asset_md, ModuleStoreEnum.UserID.test)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'course_id')), 1)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'asset')), 0)
|
||||
assert len(store.get_all_asset_metadata(course.id, 'course_id')) == 1
|
||||
assert len(store.get_all_asset_metadata(course.id, 'asset')) == 0
|
||||
all_assets = store.get_all_asset_metadata(course.id, 'course_id')
|
||||
self.assertEqual(all_assets[0].asset_id.path, new_asset_loc.path)
|
||||
assert all_assets[0].asset_id.path == new_asset_loc.path
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_lock_unlock_assets(self, storebuilder):
|
||||
@@ -312,13 +310,13 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
store.set_asset_metadata_attr(new_asset_loc, "locked", not locked_state, ModuleStoreEnum.UserID.test)
|
||||
# Find the same course and check its locked status.
|
||||
updated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertEqual(updated_asset_md.locked, not locked_state)
|
||||
assert updated_asset_md is not None
|
||||
assert updated_asset_md.locked == (not locked_state)
|
||||
# Now flip it back.
|
||||
store.set_asset_metadata_attr(new_asset_loc, "locked", locked_state, ModuleStoreEnum.UserID.test)
|
||||
reupdated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(reupdated_asset_md)
|
||||
self.assertEqual(reupdated_asset_md.locked, locked_state)
|
||||
assert reupdated_asset_md is not None
|
||||
assert reupdated_asset_md.locked == locked_state
|
||||
|
||||
ALLOWED_ATTRS = (
|
||||
('pathname', '/new/path'),
|
||||
@@ -359,9 +357,9 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test)
|
||||
# Find the same course asset and check its changed attribute.
|
||||
updated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertIsNotNone(getattr(updated_asset_md, attribute, None))
|
||||
self.assertEqual(getattr(updated_asset_md, attribute, None), value)
|
||||
assert updated_asset_md is not None
|
||||
assert getattr(updated_asset_md, attribute, None) is not None
|
||||
assert getattr(updated_asset_md, attribute, None) == value
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_set_disallowed_attrs(self, storebuilder):
|
||||
@@ -379,10 +377,10 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test)
|
||||
# Find the same course and check its changed attribute.
|
||||
updated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
self.assertIsNotNone(getattr(updated_asset_md, attribute, None))
|
||||
assert updated_asset_md is not None
|
||||
assert getattr(updated_asset_md, attribute, None) is not None
|
||||
# Make sure that the attribute is unchanged from its original value.
|
||||
self.assertEqual(getattr(updated_asset_md, attribute, None), original_attr_val)
|
||||
assert getattr(updated_asset_md, attribute, None) == original_attr_val
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_set_unknown_attrs(self, storebuilder):
|
||||
@@ -399,10 +397,10 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
store.set_asset_metadata_attr(new_asset_loc, attribute, value, ModuleStoreEnum.UserID.test)
|
||||
# Find the same course and check its changed attribute.
|
||||
updated_asset_md = store.find_asset_metadata(new_asset_loc)
|
||||
self.assertIsNotNone(updated_asset_md)
|
||||
assert updated_asset_md is not None
|
||||
# Make sure the unknown field was *not* added.
|
||||
with self.assertRaises(AttributeError):
|
||||
self.assertEqual(getattr(updated_asset_md, attribute), value)
|
||||
with pytest.raises(AttributeError):
|
||||
assert getattr(updated_asset_md, attribute) == value
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_save_one_different_asset(self, storebuilder):
|
||||
@@ -416,9 +414,9 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
self._make_asset_metadata(asset_key)
|
||||
)
|
||||
store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'different')), 1)
|
||||
self.assertEqual(store.delete_asset_metadata(asset_key, ModuleStoreEnum.UserID.test), 1)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'different')), 0)
|
||||
assert len(store.get_all_asset_metadata(course.id, 'different')) == 1
|
||||
assert store.delete_asset_metadata(asset_key, ModuleStoreEnum.UserID.test) == 1
|
||||
assert len(store.get_all_asset_metadata(course.id, 'different')) == 0
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_find_different(self, storebuilder):
|
||||
@@ -433,17 +431,17 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
)
|
||||
store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test)
|
||||
|
||||
self.assertIsNotNone(store.find_asset_metadata(asset_key))
|
||||
assert store.find_asset_metadata(asset_key) is not None
|
||||
unknown_asset_key = course.id.make_asset_key('different', 'nosuchfile.jpg')
|
||||
self.assertIsNone(store.find_asset_metadata(unknown_asset_key))
|
||||
assert store.find_asset_metadata(unknown_asset_key) is None
|
||||
|
||||
def _check_asset_values(self, assets, orig):
|
||||
"""
|
||||
Check asset type/path values.
|
||||
"""
|
||||
for idx, asset in enumerate(orig):
|
||||
self.assertEqual(assets[idx].asset_id.asset_type, asset[0])
|
||||
self.assertEqual(assets[idx].asset_id.path, asset[1])
|
||||
assert assets[idx].asset_id.asset_type == asset[0]
|
||||
assert assets[idx].asset_id.path == asset[1]
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_get_multiple_types(self, storebuilder):
|
||||
@@ -468,17 +466,17 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
('asset', self.regular_assets),
|
||||
):
|
||||
assets = store.get_all_asset_metadata(course.id, asset_type)
|
||||
self.assertEqual(len(assets), len(asset_list))
|
||||
assert len(assets) == len(asset_list)
|
||||
self._check_asset_values(assets, asset_list)
|
||||
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'not_here')), 0)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, None)), 4)
|
||||
assert len(store.get_all_asset_metadata(course.id, 'not_here')) == 0
|
||||
assert len(store.get_all_asset_metadata(course.id, None)) == 4
|
||||
|
||||
assets = store.get_all_asset_metadata(
|
||||
course.id, None, start=0, maxresults=-1,
|
||||
sort=('displayname', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(assets), len(self.alls))
|
||||
assert len(assets) == len(self.alls)
|
||||
self._check_asset_values(assets, self.alls)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
@@ -507,17 +505,17 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
('asset', self.regular_assets),
|
||||
):
|
||||
assets = store.get_all_asset_metadata(course.id, asset_type)
|
||||
self.assertEqual(len(assets), len(asset_list))
|
||||
assert len(assets) == len(asset_list)
|
||||
self._check_asset_values(assets, asset_list)
|
||||
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'not_here')), 0)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, None)), 4)
|
||||
assert len(store.get_all_asset_metadata(course.id, 'not_here')) == 0
|
||||
assert len(store.get_all_asset_metadata(course.id, None)) == 4
|
||||
|
||||
assets = store.get_all_asset_metadata(
|
||||
course.id, None, start=0, maxresults=-1,
|
||||
sort=('displayname', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(assets), len(self.alls))
|
||||
assert len(assets) == len(self.alls)
|
||||
self._check_asset_values(assets, self.alls)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
@@ -549,17 +547,17 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
('vrml', self.vrmls),
|
||||
):
|
||||
assets = store.get_all_asset_metadata(course1.id, asset_type)
|
||||
self.assertEqual(len(assets), len(asset_list))
|
||||
assert len(assets) == len(asset_list)
|
||||
self._check_asset_values(assets, asset_list)
|
||||
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course1.id, 'asset')), 0)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course1.id, None)), 3)
|
||||
assert len(store.get_all_asset_metadata(course1.id, 'asset')) == 0
|
||||
assert len(store.get_all_asset_metadata(course1.id, None)) == 3
|
||||
|
||||
assets = store.get_all_asset_metadata(
|
||||
course1.id, None, start=0, maxresults=-1,
|
||||
sort=('displayname', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(assets), len(self.differents + self.vrmls))
|
||||
assert len(assets) == len((self.differents + self.vrmls))
|
||||
self._check_asset_values(assets, self.differents + self.vrmls)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
@@ -575,7 +573,7 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
)
|
||||
store.save_asset_metadata(new_asset_thumbnail, ModuleStoreEnum.UserID.test)
|
||||
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course.id, 'different')), 1)
|
||||
assert len(store.get_all_asset_metadata(course.id, 'different')) == 1
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_get_all_assets_with_paging(self, storebuilder):
|
||||
@@ -617,38 +615,38 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
)
|
||||
num_expected_results = sort_test[2][i]
|
||||
expected_filename = sort_test[1][2 * i]
|
||||
self.assertEqual(len(asset_page), num_expected_results)
|
||||
self.assertEqual(asset_page[0].asset_id.path, expected_filename)
|
||||
assert len(asset_page) == num_expected_results
|
||||
assert asset_page[0].asset_id.path == expected_filename
|
||||
if num_expected_results == 2:
|
||||
expected_filename = sort_test[1][(2 * i) + 1]
|
||||
self.assertEqual(asset_page[1].asset_id.path, expected_filename)
|
||||
assert asset_page[1].asset_id.path == expected_filename
|
||||
|
||||
# Now fetch everything.
|
||||
asset_page = store.get_all_asset_metadata(
|
||||
course2.id, 'asset', start=0, sort=('displayname', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(asset_page), 5)
|
||||
self.assertEqual(asset_page[0].asset_id.path, 'code.tgz')
|
||||
self.assertEqual(asset_page[1].asset_id.path, 'demo.swf')
|
||||
self.assertEqual(asset_page[2].asset_id.path, 'dog.png')
|
||||
self.assertEqual(asset_page[3].asset_id.path, 'roman_history.pdf')
|
||||
self.assertEqual(asset_page[4].asset_id.path, 'weather_patterns.bmp')
|
||||
assert len(asset_page) == 5
|
||||
assert asset_page[0].asset_id.path == 'code.tgz'
|
||||
assert asset_page[1].asset_id.path == 'demo.swf'
|
||||
assert asset_page[2].asset_id.path == 'dog.png'
|
||||
assert asset_page[3].asset_id.path == 'roman_history.pdf'
|
||||
assert asset_page[4].asset_id.path == 'weather_patterns.bmp'
|
||||
|
||||
# Some odd conditions.
|
||||
asset_page = store.get_all_asset_metadata(
|
||||
course2.id, 'asset', start=100, sort=('uploadDate', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(asset_page), 0)
|
||||
assert len(asset_page) == 0
|
||||
asset_page = store.get_all_asset_metadata(
|
||||
course2.id, 'asset', start=3, maxresults=0,
|
||||
sort=('displayname', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(asset_page), 0)
|
||||
assert len(asset_page) == 0
|
||||
asset_page = store.get_all_asset_metadata(
|
||||
course2.id, 'asset', start=3, maxresults=-12345,
|
||||
sort=('displayname', ModuleStoreEnum.SortOrder.descending)
|
||||
)
|
||||
self.assertEqual(len(asset_page), 2)
|
||||
assert len(asset_page) == 2
|
||||
|
||||
@ddt.data('XML_MODULESTORE_BUILDER', 'MIXED_MODULESTORE_BUILDER')
|
||||
def test_xml_not_yet_implemented(self, storebuilderName):
|
||||
@@ -659,8 +657,8 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
with storebuilder.build(contentstore=None) as (__, store):
|
||||
course_key = store.make_course_key("org", "course", "run")
|
||||
asset_key = course_key.make_asset_key('asset', 'foo.jpg')
|
||||
self.assertEqual(store.find_asset_metadata(asset_key), None)
|
||||
self.assertEqual(store.get_all_asset_metadata(course_key, 'asset'), [])
|
||||
assert store.find_asset_metadata(asset_key) is None
|
||||
assert store.get_all_asset_metadata(course_key, 'asset') == []
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_copy_all_assets_same_modulestore(self, storebuilder):
|
||||
@@ -671,16 +669,16 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
course1 = CourseFactory.create(modulestore=store)
|
||||
course2 = CourseFactory.create(modulestore=store)
|
||||
self.setup_assets(course1.id, None, store)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course1.id, 'asset')), 2)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course2.id, 'asset')), 0)
|
||||
assert len(store.get_all_asset_metadata(course1.id, 'asset')) == 2
|
||||
assert len(store.get_all_asset_metadata(course2.id, 'asset')) == 0
|
||||
store.copy_all_asset_metadata(course1.id, course2.id, ModuleStoreEnum.UserID.test * 101)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course1.id, 'asset')), 2)
|
||||
assert len(store.get_all_asset_metadata(course1.id, 'asset')) == 2
|
||||
all_assets = store.get_all_asset_metadata(
|
||||
course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(all_assets), 2)
|
||||
self.assertEqual(all_assets[0].asset_id.path, 'pic1.jpg')
|
||||
self.assertEqual(all_assets[1].asset_id.path, 'shout.ogg')
|
||||
assert len(all_assets) == 2
|
||||
assert all_assets[0].asset_id.path == 'pic1.jpg'
|
||||
assert all_assets[1].asset_id.path == 'shout.ogg'
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
def test_copy_all_assets_from_course_with_no_assets(self, storebuilder):
|
||||
@@ -691,12 +689,12 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
course1 = CourseFactory.create(modulestore=store)
|
||||
course2 = CourseFactory.create(modulestore=store)
|
||||
store.copy_all_asset_metadata(course1.id, course2.id, ModuleStoreEnum.UserID.test * 101)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course1.id, 'asset')), 0)
|
||||
self.assertEqual(len(store.get_all_asset_metadata(course2.id, 'asset')), 0)
|
||||
assert len(store.get_all_asset_metadata(course1.id, 'asset')) == 0
|
||||
assert len(store.get_all_asset_metadata(course2.id, 'asset')) == 0
|
||||
all_assets = store.get_all_asset_metadata(
|
||||
course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(all_assets), 0)
|
||||
assert len(all_assets) == 0
|
||||
|
||||
@ddt.data(
|
||||
('mongo', 'split'),
|
||||
@@ -714,12 +712,12 @@ class TestMongoAssetMetadataStorage(TestCase):
|
||||
with mixed_store.default_store(to_store):
|
||||
course2 = CourseFactory.create(modulestore=mixed_store)
|
||||
self.setup_assets(course1.id, None, mixed_store)
|
||||
self.assertEqual(len(mixed_store.get_all_asset_metadata(course1.id, 'asset')), 2)
|
||||
self.assertEqual(len(mixed_store.get_all_asset_metadata(course2.id, 'asset')), 0)
|
||||
assert len(mixed_store.get_all_asset_metadata(course1.id, 'asset')) == 2
|
||||
assert len(mixed_store.get_all_asset_metadata(course2.id, 'asset')) == 0
|
||||
mixed_store.copy_all_asset_metadata(course1.id, course2.id, ModuleStoreEnum.UserID.test * 102)
|
||||
all_assets = mixed_store.get_all_asset_metadata(
|
||||
course2.id, 'asset', sort=('displayname', ModuleStoreEnum.SortOrder.ascending)
|
||||
)
|
||||
self.assertEqual(len(all_assets), 2)
|
||||
self.assertEqual(all_assets[0].asset_id.path, 'pic1.jpg')
|
||||
self.assertEqual(all_assets[1].asset_id.path, 'shout.ogg')
|
||||
assert len(all_assets) == 2
|
||||
assert all_assets[0].asset_id.path == 'pic1.jpg'
|
||||
assert all_assets[1].asset_id.path == 'shout.ogg'
|
||||
|
||||
@@ -10,6 +10,7 @@ import unittest
|
||||
from tempfile import mkdtemp
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import path
|
||||
from opaque_keys.edx.keys import AssetKey
|
||||
@@ -101,7 +102,7 @@ class TestContentstore(unittest.TestCase):
|
||||
asset_key = self.course1_key.make_asset_key('asset', self.course1_files[0])
|
||||
self.contentstore.delete(asset_key)
|
||||
|
||||
with self.assertRaises(NotFoundError):
|
||||
with pytest.raises(NotFoundError):
|
||||
self.contentstore.find(asset_key)
|
||||
|
||||
# ensure deleting a non-existent file is a noop
|
||||
@@ -114,17 +115,15 @@ class TestContentstore(unittest.TestCase):
|
||||
"""
|
||||
self.set_up_assets(deprecated)
|
||||
asset_key = self.course1_key.make_asset_key('asset', self.course1_files[0])
|
||||
self.assertIsNotNone(self.contentstore.find(asset_key), "Could not find {}".format(asset_key))
|
||||
assert self.contentstore.find(asset_key) is not None, 'Could not find {}'.format(asset_key)
|
||||
|
||||
self.assertIsNotNone(self.contentstore.find(asset_key, as_stream=True), "Could not find {}".format(asset_key))
|
||||
assert self.contentstore.find(asset_key, as_stream=True) is not None, 'Could not find {}'.format(asset_key)
|
||||
|
||||
unknown_asset = self.course1_key.make_asset_key('asset', 'no_such_file.gif')
|
||||
with self.assertRaises(NotFoundError):
|
||||
with pytest.raises(NotFoundError):
|
||||
self.contentstore.find(unknown_asset)
|
||||
self.assertIsNone(
|
||||
self.contentstore.find(unknown_asset, throw_on_not_found=False),
|
||||
"Found unknown asset {}".format(unknown_asset)
|
||||
)
|
||||
assert self.contentstore.find(unknown_asset, throw_on_not_found=False) is None,\
|
||||
f'Found unknown asset {unknown_asset}'
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_export_for_course(self, deprecated):
|
||||
@@ -140,11 +139,11 @@ class TestContentstore(unittest.TestCase):
|
||||
)
|
||||
for filename in self.course1_files:
|
||||
filepath = path.Path(root_dir / filename)
|
||||
self.assertTrue(filepath.isfile(), "{} is not a file".format(filepath))
|
||||
assert filepath.isfile(), '{} is not a file'.format(filepath)
|
||||
for filename in self.course2_files:
|
||||
if filename not in self.course1_files:
|
||||
filepath = path.Path(root_dir / filename)
|
||||
self.assertFalse(filepath.isfile(), "{} is unexpected exported a file".format(filepath))
|
||||
assert not filepath.isfile(), '{} is unexpected exported a file'.format(filepath)
|
||||
finally:
|
||||
shutil.rmtree(root_dir)
|
||||
|
||||
@@ -155,18 +154,18 @@ class TestContentstore(unittest.TestCase):
|
||||
"""
|
||||
self.set_up_assets(deprecated)
|
||||
course1_assets, count = self.contentstore.get_all_content_for_course(self.course1_key)
|
||||
self.assertEqual(count, len(self.course1_files), course1_assets)
|
||||
assert count == len(self.course1_files), course1_assets
|
||||
for asset in course1_assets:
|
||||
parsed = AssetKey.from_string(asset['filename'])
|
||||
self.assertIn(parsed.block_id, self.course1_files)
|
||||
assert parsed.block_id in self.course1_files
|
||||
|
||||
course1_assets, __ = self.contentstore.get_all_content_for_course(self.course1_key, 1, 1)
|
||||
self.assertEqual(len(course1_assets), 1, course1_assets)
|
||||
assert len(course1_assets) == 1, course1_assets
|
||||
|
||||
fake_course = CourseLocator('test', 'fake', 'non')
|
||||
course_assets, count = self.contentstore.get_all_content_for_course(fake_course)
|
||||
self.assertEqual(count, 0)
|
||||
self.assertEqual(course_assets, [])
|
||||
assert count == 0
|
||||
assert course_assets == []
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_attrs(self, deprecated):
|
||||
@@ -178,7 +177,7 @@ class TestContentstore(unittest.TestCase):
|
||||
asset_key = self.course1_key.make_asset_key('asset', filename)
|
||||
prelocked = self.contentstore.get_attr(asset_key, 'locked', False)
|
||||
self.contentstore.set_attr(asset_key, 'locked', not prelocked)
|
||||
self.assertEqual(self.contentstore.get_attr(asset_key, 'locked', False), not prelocked)
|
||||
assert self.contentstore.get_attr(asset_key, 'locked', False) == (not prelocked)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_copy_assets(self, deprecated):
|
||||
@@ -194,10 +193,10 @@ class TestContentstore(unittest.TestCase):
|
||||
source = self.contentstore.find(asset_key)
|
||||
copied = self.contentstore.find(dest_key)
|
||||
for propname in ['name', 'content_type', 'length', 'locked']:
|
||||
self.assertEqual(getattr(source, propname), getattr(copied, propname))
|
||||
assert getattr(source, propname) == getattr(copied, propname)
|
||||
|
||||
__, count = self.contentstore.get_all_content_for_course(dest_course)
|
||||
self.assertEqual(count, len(self.course1_files))
|
||||
assert count == len(self.course1_files)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_copy_assets_with_duplicates(self, deprecated):
|
||||
@@ -209,7 +208,7 @@ class TestContentstore(unittest.TestCase):
|
||||
self.contentstore.copy_all_course_assets(self.course1_key, dest_course)
|
||||
|
||||
__, count = self.contentstore.get_all_content_for_course(dest_course)
|
||||
self.assertEqual(count, 5)
|
||||
assert count == 5
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_delete_assets(self, deprecated):
|
||||
@@ -219,7 +218,7 @@ class TestContentstore(unittest.TestCase):
|
||||
self.set_up_assets(deprecated)
|
||||
self.contentstore.delete_all_course_assets(self.course1_key)
|
||||
__, count = self.contentstore.get_all_content_for_course(self.course1_key)
|
||||
self.assertEqual(count, 0)
|
||||
assert count == 0
|
||||
# ensure it didn't remove any from other course
|
||||
__, count = self.contentstore.get_all_content_for_course(self.course2_key)
|
||||
self.assertEqual(count, len(self.course2_files))
|
||||
assert count == len(self.course2_files)
|
||||
|
||||
@@ -188,12 +188,12 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest, PartitionTestCase):
|
||||
|
||||
source_course = source_store.get_course(source_course_key, depth=None, lazy=False) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
self.assertEqual(source_course.url_name, 'course')
|
||||
assert source_course.url_name == 'course'
|
||||
|
||||
export_dir_path = path(self.export_dir)
|
||||
policy_dir = export_dir_path / 'exported_source_course' / 'policies' / source_course_key.run
|
||||
policy_path = policy_dir / 'policy.json'
|
||||
self.assertTrue(os.path.exists(policy_path))
|
||||
assert os.path.exists(policy_path)
|
||||
|
||||
import_course_from_xml(
|
||||
dest_store,
|
||||
@@ -208,4 +208,4 @@ class CrossStoreXMLRoundtrip(CourseComparisonTest, PartitionTestCase):
|
||||
|
||||
dest_course = dest_store.get_course(dest_course_key, depth=None, lazy=False) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
self.assertEqual(dest_course.url_name, 'course')
|
||||
assert dest_course.url_name == 'course'
|
||||
|
||||
@@ -64,4 +64,4 @@ class TestInheritanceMixin(unittest.TestCase):
|
||||
confirm if the submission deadline has passed or not.
|
||||
"""
|
||||
self.add_submission_deadline_information(due_date, graceperiod, self_paced)
|
||||
self.assertEqual(is_past_deadline, self.xblock.has_deadline_passed())
|
||||
assert is_past_deadline == self.xblock.has_deadline_passed()
|
||||
|
||||
@@ -5,7 +5,7 @@ Basic unit tests related to content libraries.
|
||||
Higher-level tests are in `cms/djangoapps/contentstore`.
|
||||
"""
|
||||
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import six
|
||||
from bson.objectid import ObjectId
|
||||
@@ -45,7 +45,7 @@ class TestLibraries(MixedSplitTestCase):
|
||||
"""
|
||||
org, lib_code = ('DuplicateX', "DUP")
|
||||
LibraryFactory.create(org=org, library=lib_code, modulestore=self.store)
|
||||
with self.assertRaises(DuplicateCourseError):
|
||||
with pytest.raises(DuplicateCourseError):
|
||||
LibraryFactory.create(org=org, library=lib_code, modulestore=self.store)
|
||||
|
||||
@ddt.data(
|
||||
@@ -57,9 +57,9 @@ class TestLibraries(MixedSplitTestCase):
|
||||
Test __unicode__() and __str__() methods of libraries
|
||||
"""
|
||||
library = LibraryFactory.create(metadata={"display_name": name}, modulestore=self.store)
|
||||
self.assertIn(name, six.text_type(library))
|
||||
assert name in six.text_type(library)
|
||||
if not isinstance(name, six.text_type):
|
||||
self.assertIn(name, str(library))
|
||||
assert name in str(library)
|
||||
|
||||
def test_display_with_default_methods(self):
|
||||
"""
|
||||
@@ -69,8 +69,8 @@ class TestLibraries(MixedSplitTestCase):
|
||||
org = 'TestOrgX'
|
||||
lib_code = 'LC101'
|
||||
library = LibraryFactory.create(org=org, library=lib_code, modulestore=self.store)
|
||||
self.assertEqual(library.display_org_with_default, org)
|
||||
self.assertEqual(library.display_number_with_default, lib_code)
|
||||
assert library.display_org_with_default == org
|
||||
assert library.display_number_with_default == lib_code
|
||||
|
||||
def test_block_with_children(self):
|
||||
"""
|
||||
@@ -94,7 +94,7 @@ class TestLibraries(MixedSplitTestCase):
|
||||
metadata={"data": "Hello world", },
|
||||
modulestore=self.store,
|
||||
)
|
||||
self.assertEqual(child_block.parent.replace(version_guid=None, branch=None), vert_block.location)
|
||||
assert child_block.parent.replace(version_guid=None, branch=None) == vert_block.location
|
||||
|
||||
def test_update_item(self):
|
||||
"""
|
||||
@@ -116,10 +116,10 @@ class TestLibraries(MixedSplitTestCase):
|
||||
self.store.update_item(block, self.user_id)
|
||||
# Reload block from the modulestore
|
||||
block = self.store.get_item(block_key)
|
||||
self.assertEqual(block.data, "NEW")
|
||||
self.assertEqual(block.location, block_key)
|
||||
assert block.data == 'NEW'
|
||||
assert block.location == block_key
|
||||
new_version = self.store.get_item(block_key, remove_version=False, remove_branch=False).location.version_guid
|
||||
self.assertNotEqual(old_version, new_version)
|
||||
assert old_version != new_version
|
||||
|
||||
def test_delete_item(self):
|
||||
"""
|
||||
@@ -135,15 +135,15 @@ class TestLibraries(MixedSplitTestCase):
|
||||
modulestore=self.store,
|
||||
)
|
||||
library = self.store.get_library(lib_key)
|
||||
self.assertEqual(len(library.children), 1)
|
||||
assert len(library.children) == 1
|
||||
self.store.delete_item(block.location, self.user_id)
|
||||
library = self.store.get_library(lib_key)
|
||||
self.assertEqual(len(library.children), 0)
|
||||
assert len(library.children) == 0
|
||||
|
||||
def test_get_library_non_existent(self):
|
||||
""" Test get_library() with non-existent key """
|
||||
result = self.store.get_library(LibraryLocator("non", "existent"))
|
||||
self.assertEqual(result, None)
|
||||
assert result is None
|
||||
|
||||
def test_get_library_keys(self):
|
||||
""" Test get_library_keys() """
|
||||
@@ -159,9 +159,9 @@ class TestLibraries(MixedSplitTestCase):
|
||||
|
||||
lib_list = self.store.get_libraries()
|
||||
|
||||
self.assertEqual(len(lib_list), len(libraries))
|
||||
assert len(lib_list) == len(libraries)
|
||||
for lib in lib_list:
|
||||
self.assertIn(lib.location.library_key, lib_dict)
|
||||
assert lib.location.library_key in lib_dict
|
||||
|
||||
def test_strip(self):
|
||||
"""
|
||||
@@ -172,10 +172,10 @@ class TestLibraries(MixedSplitTestCase):
|
||||
lib_key = LibraryFactory.create(modulestore=self.store).location.library_key
|
||||
# Re-load the library from the modulestore, explicitly including version information:
|
||||
lib = self.store.get_library(lib_key)
|
||||
self.assertEqual(lib.location.version_guid, None)
|
||||
self.assertEqual(lib.location.branch, None)
|
||||
self.assertEqual(lib.location.library_key.version_guid, None)
|
||||
self.assertEqual(lib.location.library_key.branch, None)
|
||||
assert lib.location.version_guid is None
|
||||
assert lib.location.branch is None
|
||||
assert lib.location.library_key.version_guid is None
|
||||
assert lib.location.library_key.branch is None
|
||||
|
||||
def test_get_lib_version(self):
|
||||
"""
|
||||
@@ -186,7 +186,7 @@ class TestLibraries(MixedSplitTestCase):
|
||||
# Re-load the library from the modulestore, explicitly including version information:
|
||||
lib = self.store.get_library(lib_key, remove_version=False, remove_branch=False)
|
||||
version = lib.location.library_key.version_guid
|
||||
self.assertIsInstance(version, ObjectId)
|
||||
assert isinstance(version, ObjectId)
|
||||
|
||||
def test_xblock_in_lib_have_published_version_returns_false(self):
|
||||
library = LibraryFactory.create(modulestore=self.store)
|
||||
@@ -197,4 +197,4 @@ class TestLibraries(MixedSplitTestCase):
|
||||
publish_item=False,
|
||||
modulestore=self.store,
|
||||
)
|
||||
self.assertFalse(self.store.has_published_version(block))
|
||||
assert not self.store.has_published_version(block)
|
||||
|
||||
@@ -166,7 +166,7 @@ class CommonMixedModuleStoreSetup(CourseComparisonTest):
|
||||
if isinstance(self.course.id, CourseLocator):
|
||||
self.course_locations[self.MONGO_COURSEID] = self.course.location
|
||||
else:
|
||||
self.assertEqual(self.course.id, course_key)
|
||||
assert self.course.id == course_key
|
||||
|
||||
# create chapter
|
||||
chapter = self.store.create_child(self.user_id, self.course.location, 'chapter',
|
||||
@@ -283,7 +283,7 @@ class CommonMixedModuleStoreSetup(CourseComparisonTest):
|
||||
).make_usage_key('vertical', 'fake')
|
||||
self._create_course(test_course_key)
|
||||
|
||||
self.assertEqual(default, self.store.get_modulestore_type(self.course.id))
|
||||
assert default == self.store.get_modulestore_type(self.course.id)
|
||||
|
||||
|
||||
class AsideFoo(XBlockAside):
|
||||
@@ -328,13 +328,9 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
Make sure we get back the store type we expect for given mappings
|
||||
"""
|
||||
self.initdb(default_ms)
|
||||
self.assertEqual(self.store.get_modulestore_type(
|
||||
self._course_key_from_string(self.MONGO_COURSEID)), default_ms
|
||||
)
|
||||
assert self.store.get_modulestore_type(self._course_key_from_string(self.MONGO_COURSEID)) == default_ms
|
||||
# try an unknown mapping, it should be the 'default' store
|
||||
self.assertEqual(self.store.get_modulestore_type(
|
||||
CourseKey.from_string('foo/bar/2012_Fall')), default_ms
|
||||
)
|
||||
assert self.store.get_modulestore_type(CourseKey.from_string('foo/bar/2012_Fall')) == default_ms
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_get_modulestore_cache(self, default_ms):
|
||||
@@ -346,9 +342,9 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.mappings = {}
|
||||
course_key = self.course_locations[self.MONGO_COURSEID].course_key
|
||||
with check_exact_number_of_calls(self.store.default_modulestore, 'has_course', 1):
|
||||
self.assertEqual(self.store.default_modulestore, self.store._get_modulestore_for_courselike(course_key)) # pylint: disable=protected-access
|
||||
self.assertIn(course_key, self.store.mappings)
|
||||
self.assertEqual(self.store.default_modulestore, self.store._get_modulestore_for_courselike(course_key)) # pylint: disable=protected-access
|
||||
assert self.store.default_modulestore == self.store._get_modulestore_for_courselike(course_key) # pylint: disable=protected-access, line-too-long
|
||||
assert course_key in self.store.mappings
|
||||
assert self.store.default_modulestore == self.store._get_modulestore_for_courselike(course_key) # pylint: disable=protected-access, line-too-long
|
||||
|
||||
@ddt.data(*itertools.product(
|
||||
(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split),
|
||||
@@ -364,7 +360,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.create_course('org_x', 'course_y', 'run_z', self.user_id)
|
||||
if reset_mixed_mappings:
|
||||
self.store.mappings = {}
|
||||
with self.assertRaises(DuplicateCourseError):
|
||||
with pytest.raises(DuplicateCourseError):
|
||||
self.store.create_course('org_x', 'course_y', 'run_z', self.user_id)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.split, ModuleStoreEnum.Type.mongo)
|
||||
@@ -376,7 +372,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
with self.store.default_store(default_store):
|
||||
self.store.create_course('org_x', 'course_y', 'run_z', self.user_id)
|
||||
|
||||
with self.assertRaises(DuplicateCourseError):
|
||||
with pytest.raises(DuplicateCourseError):
|
||||
self.store.create_course('ORG_X', 'COURSE_Y', 'RUN_Z', self.user_id)
|
||||
|
||||
# Draft:
|
||||
@@ -390,14 +386,14 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self._create_block_hierarchy()
|
||||
|
||||
with check_mongo_calls(max_find.pop(0), max_send):
|
||||
self.assertTrue(self.store.has_item(self.problem_x1a_1)) # lint-amnesty, pylint: disable=no-member
|
||||
assert self.store.has_item(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
# try negative cases
|
||||
with check_mongo_calls(max_find.pop(0), max_send):
|
||||
self.assertFalse(self.store.has_item(self.fake_location))
|
||||
assert not self.store.has_item(self.fake_location)
|
||||
|
||||
# verify that an error is raised when the revision is not valid
|
||||
with self.assertRaises(UnsupportedRevisionError):
|
||||
with pytest.raises(UnsupportedRevisionError):
|
||||
self.store.has_item(self.fake_location, revision=ModuleStoreEnum.RevisionOption.draft_preferred)
|
||||
|
||||
# draft queries:
|
||||
@@ -413,15 +409,15 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self._create_block_hierarchy()
|
||||
|
||||
with check_mongo_calls(max_find.pop(0), max_send):
|
||||
self.assertIsNotNone(self.store.get_item(self.problem_x1a_1)) # lint-amnesty, pylint: disable=no-member
|
||||
assert self.store.get_item(self.problem_x1a_1) is not None # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
# try negative cases
|
||||
with check_mongo_calls(max_find.pop(0), max_send):
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.store.get_item(self.fake_location)
|
||||
|
||||
# verify that an error is raised when the revision is not valid
|
||||
with self.assertRaises(UnsupportedRevisionError):
|
||||
with pytest.raises(UnsupportedRevisionError):
|
||||
self.store.get_item(self.fake_location, revision=ModuleStoreEnum.RevisionOption.draft_preferred)
|
||||
|
||||
# Draft:
|
||||
@@ -437,10 +433,10 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
course_locn = self.course_locations[self.MONGO_COURSEID]
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
modules = self.store.get_items(course_locn.course_key, qualifiers={'category': 'problem'})
|
||||
self.assertEqual(len(modules), 6)
|
||||
assert len(modules) == 6
|
||||
|
||||
# verify that an error is raised when the revision is not valid
|
||||
with self.assertRaises(UnsupportedRevisionError):
|
||||
with pytest.raises(UnsupportedRevisionError):
|
||||
self.store.get_items(
|
||||
self.course_locations[self.MONGO_COURSEID].course_key,
|
||||
revision=ModuleStoreEnum.RevisionOption.draft_preferred
|
||||
@@ -455,19 +451,19 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
course_version = course.course_version
|
||||
|
||||
if default_ms == ModuleStoreEnum.Type.split:
|
||||
self.assertIsNotNone(course_version)
|
||||
assert course_version is not None
|
||||
else:
|
||||
self.assertIsNone(course_version)
|
||||
assert course_version is None
|
||||
|
||||
blocks = self.store.get_items(self.course.id, qualifiers={'category': 'problem'})
|
||||
blocks.append(self.store.get_item(self.problem_x1a_1)) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(len(blocks), 7)
|
||||
assert len(blocks) == 7
|
||||
for block in blocks:
|
||||
self.assertEqual(block.course_version, course_version)
|
||||
assert block.course_version == course_version
|
||||
# ensure that when the block is retrieved from the runtime cache,
|
||||
# the course version is still present
|
||||
cached_block = course.runtime.load_item(block.location)
|
||||
self.assertEqual(cached_block.course_version, block.course_version)
|
||||
assert cached_block.course_version == block.course_version
|
||||
|
||||
@ddt.data((ModuleStoreEnum.Type.split, 2, False), (ModuleStoreEnum.Type.mongo, 3, True))
|
||||
@ddt.unpack
|
||||
@@ -496,17 +492,15 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
items = self.store.get_items(course_key)
|
||||
# Check items found are either course or about type
|
||||
self.assertTrue(set(['course', 'about']).issubset(set([item.location.block_type for item in items]))) # lint-amnesty, pylint: disable=consider-using-set-comprehension
|
||||
assert set(['course', 'about']).issubset(set([item.location.block_type for item in items])) # pylint: disable=consider-using-set-comprehension, line-too-long
|
||||
# Assert that about is a detached category found in get_items
|
||||
self.assertIn(
|
||||
[item.location.block_type for item in items if item.location.block_type == 'about'][0],
|
||||
DETACHED_XBLOCK_TYPES
|
||||
)
|
||||
self.assertEqual(len(items), 2)
|
||||
assert [item.location.block_type for item in items if item.location.block_type == 'about'][0]\
|
||||
in DETACHED_XBLOCK_TYPES
|
||||
assert len(items) == 2
|
||||
|
||||
# Check that orphans are not found
|
||||
orphans = self.store.get_orphans(course_key)
|
||||
self.assertEqual(len(orphans), 0)
|
||||
assert len(orphans) == 0
|
||||
|
||||
# Add an orphan to test course
|
||||
orphan = course_key.make_usage_key('chapter', 'OrphanChapter')
|
||||
@@ -514,22 +508,22 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Check that now an orphan is found
|
||||
orphans = self.store.get_orphans(course_key)
|
||||
self.assertIn(orphan, orphans)
|
||||
self.assertEqual(len(orphans), 1)
|
||||
assert orphan in orphans
|
||||
assert len(orphans) == 1
|
||||
|
||||
# Check now `get_items` retrieves an extra item added above which is an orphan.
|
||||
items = self.store.get_items(course_key)
|
||||
self.assertIn(orphan, [item.location for item in items])
|
||||
self.assertEqual(len(items), 3)
|
||||
assert orphan in [item.location for item in items]
|
||||
assert len(items) == 3
|
||||
|
||||
# Check now `get_items` with `include_orphans` kwarg does not retrieves an orphan block.
|
||||
items_in_tree = self.store.get_items(course_key, include_orphans=False)
|
||||
|
||||
# Check that course and about blocks are found in get_items
|
||||
self.assertTrue(set(['course', 'about']).issubset(set([item.location.block_type for item in items_in_tree]))) # lint-amnesty, pylint: disable=consider-using-set-comprehension
|
||||
assert set(['course', 'about']).issubset({item.location.block_type for item in items_in_tree})
|
||||
# Check orphan is found or not - this is based on mongo/split modulestore. It should be found in mongo.
|
||||
self.assertEqual(orphan in [item.location for item in items_in_tree], orphan_in_items)
|
||||
self.assertEqual(len(items_in_tree), expected_items_in_tree)
|
||||
assert (orphan in [item.location for item in items_in_tree]) == orphan_in_items
|
||||
assert len(items_in_tree) == expected_items_in_tree
|
||||
|
||||
# draft: get draft, get ancestors up to course (2-6), compute inheritance
|
||||
# sends: update problem and then each ancestor up to course (edit info)
|
||||
@@ -545,12 +539,12 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self._create_block_hierarchy()
|
||||
problem = self.store.get_item(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
# if following raised, then the test is really a noop, change it
|
||||
self.assertNotEqual(problem.max_attempts, 2, "Default changed making test meaningless")
|
||||
assert problem.max_attempts != 2, 'Default changed making test meaningless'
|
||||
problem.max_attempts = 2
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
problem = self.store.update_item(problem, self.user_id)
|
||||
|
||||
self.assertEqual(problem.max_attempts, 2, "Update didn't persist")
|
||||
assert problem.max_attempts == 2, "Update didn't persist"
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_has_changes_direct_only(self, default_ms):
|
||||
@@ -570,8 +564,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
)
|
||||
|
||||
# Check that neither xblock has changes
|
||||
self.assertFalse(self.store.has_changes(test_course))
|
||||
self.assertFalse(self.store.has_changes(chapter))
|
||||
assert not self.store.has_changes(test_course)
|
||||
assert not self.store.has_changes(chapter)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_has_changes(self, default_ms):
|
||||
@@ -591,22 +585,22 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
)
|
||||
|
||||
# Not yet published, so changes are present
|
||||
self.assertTrue(self.store.has_changes(xblock))
|
||||
assert self.store.has_changes(xblock)
|
||||
|
||||
# Publish and verify that there are no unpublished changes
|
||||
newXBlock = self.store.publish(xblock.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(newXBlock))
|
||||
assert not self.store.has_changes(newXBlock)
|
||||
|
||||
# Change the component, then check that there now are changes
|
||||
component = self.store.get_item(xblock.location)
|
||||
component.display_name = 'Changed Display Name'
|
||||
|
||||
component = self.store.update_item(component, self.user_id)
|
||||
self.assertTrue(self.store.has_changes(component))
|
||||
assert self.store.has_changes(component)
|
||||
|
||||
# Publish and verify again
|
||||
component = self.store.publish(component.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
assert not self.store.has_changes(component)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_unit_stuck_in_draft_mode(self, default_ms):
|
||||
@@ -626,19 +620,19 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
)
|
||||
|
||||
# Not yet published, so changes are present
|
||||
self.assertTrue(self.store.has_changes(xblock))
|
||||
assert self.store.has_changes(xblock)
|
||||
|
||||
# Publish and verify that there are no unpublished changes
|
||||
component = self.store.publish(xblock.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
assert not self.store.has_changes(component)
|
||||
|
||||
self.store.revert_to_published(component.location, self.user_id)
|
||||
component = self.store.get_item(component.location)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
assert not self.store.has_changes(component)
|
||||
|
||||
# Publish and verify again
|
||||
component = self.store.publish(component.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
assert not self.store.has_changes(component)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_unit_stuck_in_published_mode(self, default_ms):
|
||||
@@ -658,16 +652,16 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
)
|
||||
|
||||
# Not yet published, so changes are present
|
||||
self.assertTrue(self.store.has_changes(xblock))
|
||||
assert self.store.has_changes(xblock)
|
||||
|
||||
# Publish and verify that there are no unpublished changes
|
||||
component = self.store.publish(xblock.location, self.user_id)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
assert not self.store.has_changes(component)
|
||||
|
||||
# Discard changes and verify that there are no changes
|
||||
self.store.revert_to_published(component.location, self.user_id)
|
||||
component = self.store.get_item(component.location)
|
||||
self.assertFalse(self.store.has_changes(component))
|
||||
assert not self.store.has_changes(component)
|
||||
|
||||
# Change the component, then check that there now are changes
|
||||
component = self.store.get_item(component.location)
|
||||
@@ -675,7 +669,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.update_item(component, self.user_id)
|
||||
|
||||
# Verify that changes are present
|
||||
self.assertTrue(self.store.has_changes(component))
|
||||
assert self.store.has_changes(component)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_unit_stuck_in_published_mode_after_delete(self, default_ms):
|
||||
@@ -703,22 +697,22 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# publish vertical changes
|
||||
self.store.publish(vertical.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
assert not self._has_changes(vertical.location)
|
||||
|
||||
# Change a component, then check that there now are changes
|
||||
component = self.store.get_item(component.location)
|
||||
component.display_name = 'Changed Display Name'
|
||||
self.store.update_item(component, self.user_id)
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
assert self._has_changes(vertical.location)
|
||||
|
||||
# Discard changes and verify that there are no changes
|
||||
self.store.revert_to_published(vertical.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
assert not self._has_changes(vertical.location)
|
||||
|
||||
# Delete the component and verify that the unit has changes
|
||||
self.store.delete_item(component.location, self.user_id)
|
||||
vertical = self.store.get_item(vertical.location)
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
assert self._has_changes(vertical.location)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_publish_automatically_after_delete_unit(self, default_ms):
|
||||
@@ -735,11 +729,11 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# publish sequential changes
|
||||
self.store.publish(sequential.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(sequential.location))
|
||||
assert not self._has_changes(sequential.location)
|
||||
|
||||
# delete vertical and check sequential has no changes
|
||||
self.store.delete_item(vertical.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(sequential.location))
|
||||
assert not self._has_changes(sequential.location)
|
||||
|
||||
def setup_has_changes(self, default_ms):
|
||||
"""
|
||||
@@ -772,7 +766,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Verify that there are no unpublished changes
|
||||
for key in locations:
|
||||
self.assertFalse(self._has_changes(locations[key]))
|
||||
assert not self._has_changes(locations[key])
|
||||
|
||||
# Change the child
|
||||
child = self.store.get_item(locations['child'])
|
||||
@@ -780,18 +774,18 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.update_item(child, self.user_id)
|
||||
|
||||
# All ancestors should have changes, but not siblings
|
||||
self.assertTrue(self._has_changes(locations['grandparent']))
|
||||
self.assertTrue(self._has_changes(locations['parent']))
|
||||
self.assertTrue(self._has_changes(locations['child']))
|
||||
self.assertFalse(self._has_changes(locations['parent_sibling']))
|
||||
self.assertFalse(self._has_changes(locations['child_sibling']))
|
||||
assert self._has_changes(locations['grandparent'])
|
||||
assert self._has_changes(locations['parent'])
|
||||
assert self._has_changes(locations['child'])
|
||||
assert not self._has_changes(locations['parent_sibling'])
|
||||
assert not self._has_changes(locations['child_sibling'])
|
||||
|
||||
# Publish the unit with changes
|
||||
self.store.publish(locations['parent'], self.user_id)
|
||||
|
||||
# Verify that there are no unpublished changes
|
||||
for key in locations:
|
||||
self.assertFalse(self._has_changes(locations[key]))
|
||||
assert not self._has_changes(locations[key])
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_has_changes_publish_ancestors(self, default_ms):
|
||||
@@ -802,7 +796,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Verify that there are no unpublished changes
|
||||
for key in locations:
|
||||
self.assertFalse(self._has_changes(locations[key]))
|
||||
assert not self._has_changes(locations[key])
|
||||
|
||||
# Change both children
|
||||
child = self.store.get_item(locations['child'])
|
||||
@@ -813,22 +807,22 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.update_item(child_sibling, user_id=self.user_id)
|
||||
|
||||
# Verify that ancestors have changes
|
||||
self.assertTrue(self._has_changes(locations['grandparent']))
|
||||
self.assertTrue(self._has_changes(locations['parent']))
|
||||
assert self._has_changes(locations['grandparent'])
|
||||
assert self._has_changes(locations['parent'])
|
||||
|
||||
# Publish one child
|
||||
self.store.publish(locations['child_sibling'], self.user_id)
|
||||
|
||||
# Verify that ancestors still have changes
|
||||
self.assertTrue(self._has_changes(locations['grandparent']))
|
||||
self.assertTrue(self._has_changes(locations['parent']))
|
||||
assert self._has_changes(locations['grandparent'])
|
||||
assert self._has_changes(locations['parent'])
|
||||
|
||||
# Publish the other child
|
||||
self.store.publish(locations['child'], self.user_id)
|
||||
|
||||
# Verify that ancestors now have no changes
|
||||
self.assertFalse(self._has_changes(locations['grandparent']))
|
||||
self.assertFalse(self._has_changes(locations['parent']))
|
||||
assert not self._has_changes(locations['grandparent'])
|
||||
assert not self._has_changes(locations['parent'])
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_has_changes_add_remove_child(self, default_ms):
|
||||
@@ -839,8 +833,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
locations = self.setup_has_changes(default_ms)
|
||||
|
||||
# Test that the ancestors don't have changes
|
||||
self.assertFalse(self._has_changes(locations['grandparent']))
|
||||
self.assertFalse(self._has_changes(locations['parent']))
|
||||
assert not self._has_changes(locations['grandparent'])
|
||||
assert not self._has_changes(locations['parent'])
|
||||
|
||||
# Create a new child and attach it to parent
|
||||
self.store.create_child(
|
||||
@@ -851,8 +845,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
)
|
||||
|
||||
# Verify that the ancestors now have changes
|
||||
self.assertTrue(self._has_changes(locations['grandparent']))
|
||||
self.assertTrue(self._has_changes(locations['parent']))
|
||||
assert self._has_changes(locations['grandparent'])
|
||||
assert self._has_changes(locations['parent'])
|
||||
|
||||
# Remove the child from the parent
|
||||
parent = self.store.get_item(locations['parent'])
|
||||
@@ -860,8 +854,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.update_item(parent, user_id=self.user_id)
|
||||
|
||||
# Verify that ancestors now have no changes
|
||||
self.assertFalse(self._has_changes(locations['grandparent']))
|
||||
self.assertFalse(self._has_changes(locations['parent']))
|
||||
assert not self._has_changes(locations['grandparent'])
|
||||
assert not self._has_changes(locations['parent'])
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_has_changes_non_direct_only_children(self, default_ms):
|
||||
@@ -885,16 +879,16 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.publish(parent.location, self.user_id)
|
||||
|
||||
# Verify that there are no changes
|
||||
self.assertFalse(self._has_changes(parent.location))
|
||||
self.assertFalse(self._has_changes(child.location))
|
||||
assert not self._has_changes(parent.location)
|
||||
assert not self._has_changes(child.location)
|
||||
|
||||
# Change the child
|
||||
child.display_name = 'Changed Display Name'
|
||||
self.store.update_item(child, user_id=self.user_id)
|
||||
|
||||
# Verify that both parent and child have changes
|
||||
self.assertTrue(self._has_changes(parent.location))
|
||||
self.assertTrue(self._has_changes(child.location))
|
||||
assert self._has_changes(parent.location)
|
||||
assert self._has_changes(child.location)
|
||||
|
||||
@ddt.data(*itertools.product(
|
||||
(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split),
|
||||
@@ -919,7 +913,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
parent = self.store.update_item(parent, self.user_id)
|
||||
|
||||
# Check the parent for changes should return True and not throw an exception
|
||||
self.assertTrue(self.store.has_changes(parent))
|
||||
assert self.store.has_changes(parent)
|
||||
|
||||
# Draft
|
||||
# Find: find parents (definition.children query), get parent, get course (fill in run?),
|
||||
@@ -944,10 +938,10 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.delete_item(self.writable_chapter_location, self.user_id)
|
||||
|
||||
# verify it's gone
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.store.get_item(self.writable_chapter_location)
|
||||
# verify it's gone from published too
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.store.get_item(self.writable_chapter_location, revision=ModuleStoreEnum.RevisionOption.published_only)
|
||||
|
||||
# Draft:
|
||||
@@ -984,10 +978,10 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
vert_loc = private_vert.location.for_version(private_leaf.location.version_guid)
|
||||
else:
|
||||
vert_loc = private_vert.location
|
||||
self.assertTrue(self.store.has_item(vert_loc))
|
||||
self.assertTrue(self.store.has_item(private_leaf.location))
|
||||
assert self.store.has_item(vert_loc)
|
||||
assert self.store.has_item(private_leaf.location)
|
||||
course = self.store.get_course(self.course_locations[self.MONGO_COURSEID].course_key, 0)
|
||||
self.assertIn(vert_loc, course.children)
|
||||
assert vert_loc in course.children
|
||||
|
||||
# delete the vertical and ensure the course no longer points to it
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
@@ -1000,9 +994,9 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
else:
|
||||
vert_loc = private_vert.location
|
||||
leaf_loc = private_leaf.location
|
||||
self.assertFalse(self.store.has_item(vert_loc))
|
||||
self.assertFalse(self.store.has_item(leaf_loc))
|
||||
self.assertNotIn(vert_loc, course.children)
|
||||
assert not self.store.has_item(vert_loc)
|
||||
assert not self.store.has_item(leaf_loc)
|
||||
assert vert_loc not in course.children
|
||||
|
||||
# Draft:
|
||||
# find: find parent (definition.children) 2x, find draft item, get inheritance items
|
||||
@@ -1029,7 +1023,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
)
|
||||
|
||||
# verify that an error is raised when the revision is not valid
|
||||
with self.assertRaises(UnsupportedRevisionError):
|
||||
with pytest.raises(UnsupportedRevisionError):
|
||||
self.store.delete_item(
|
||||
private_leaf.location,
|
||||
self.user_id,
|
||||
@@ -1061,14 +1055,14 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
courses = self.store.get_courses()
|
||||
course_ids = [course.location for course in courses]
|
||||
self.assertEqual(len(courses), 1, "Not one course: {}".format(course_ids))
|
||||
self.assertIn(self.course_locations[self.MONGO_COURSEID], course_ids)
|
||||
assert len(courses) == 1, 'Not one course: {}'.format(course_ids)
|
||||
assert self.course_locations[self.MONGO_COURSEID] in course_ids
|
||||
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
draft_courses = self.store.get_courses(remove_branch=True)
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
|
||||
published_courses = self.store.get_courses(remove_branch=True)
|
||||
self.assertEqual([c.id for c in draft_courses], [c.id for c in published_courses])
|
||||
assert [c.id for c in draft_courses] == [c.id for c in published_courses]
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_create_child_detached_tabs(self, default_ms):
|
||||
@@ -1078,7 +1072,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
"""
|
||||
self.initdb(default_ms)
|
||||
mongo_course = self.store.get_course(self.course_locations[self.MONGO_COURSEID].course_key)
|
||||
self.assertEqual(len(mongo_course.children), 1)
|
||||
assert len(mongo_course.children) == 1
|
||||
|
||||
# create a static tab of the course
|
||||
self.store.create_child(
|
||||
@@ -1089,7 +1083,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# now check that the course has same number of children
|
||||
mongo_course = self.store.get_course(self.course_locations[self.MONGO_COURSEID].course_key)
|
||||
self.assertEqual(len(mongo_course.children), 1)
|
||||
assert len(mongo_course.children) == 1
|
||||
|
||||
# draft is 2: find out which ms owns course, get item
|
||||
# split: active_versions, structure, definition (to load course wiki string)
|
||||
@@ -1103,7 +1097,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.initdb(default_ms)
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
course = self.store.get_item(self.course_locations[self.MONGO_COURSEID])
|
||||
self.assertEqual(course.id, self.course_locations[self.MONGO_COURSEID].course_key)
|
||||
assert course.id == self.course_locations[self.MONGO_COURSEID].course_key
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_get_library(self, default_ms):
|
||||
@@ -1116,15 +1110,15 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
with self.store.default_store(ModuleStoreEnum.Type.split): # The CMS also wraps create_library like this
|
||||
library = self.store.create_library("org", "lib", self.user_id, {"display_name": "Test Library"})
|
||||
library_key = library.location.library_key
|
||||
self.assertIsInstance(library_key, LibraryLocator)
|
||||
assert isinstance(library_key, LibraryLocator)
|
||||
# Now load with get_library and make sure it works:
|
||||
library = self.store.get_library(library_key)
|
||||
self.assertEqual(library.location.library_key, library_key)
|
||||
assert library.location.library_key == library_key
|
||||
|
||||
# Clear the mappings so we can test get_library code path without mapping set:
|
||||
self.store.mappings.clear()
|
||||
library = self.store.get_library(library_key)
|
||||
self.assertEqual(library.location.library_key, library_key)
|
||||
assert library.location.library_key == library_key
|
||||
|
||||
# notice this doesn't test getting a public item via draft_preferred which draft would have 2 hits (split
|
||||
# still only 2)
|
||||
@@ -1141,17 +1135,14 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
parent = self.store.get_parent_location(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(parent, self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
assert parent == self.vertical_x1a # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
def verify_get_parent_locations_results(self, expected_results):
|
||||
"""
|
||||
Verifies the results of calling get_parent_locations matches expected_results.
|
||||
"""
|
||||
for child_location, parent_location, revision in expected_results:
|
||||
self.assertEqual(
|
||||
parent_location,
|
||||
self.store.get_parent_location(child_location, revision=revision)
|
||||
)
|
||||
assert parent_location == self.store.get_parent_location(child_location, revision=revision)
|
||||
|
||||
def verify_item_parent(self, item_location, expected_parent_location, old_parent_location, is_reverted=False):
|
||||
"""
|
||||
@@ -1168,7 +1159,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
old_parent = self.store.get_item(old_parent_location)
|
||||
expected_parent = self.store.get_item(expected_parent_location)
|
||||
|
||||
self.assertEqual(expected_parent_location, source_item.get_parent().location)
|
||||
assert expected_parent_location == source_item.get_parent().location
|
||||
|
||||
# If an item is reverted, it means it's actual parent was the one that is the current parent now
|
||||
# i.e expected_parent_location otherwise old_parent_location.
|
||||
@@ -1176,9 +1167,9 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Check parent locations wrt branches
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
self.assertEqual(expected_parent_location, self.store.get_item(item_location).get_parent().location)
|
||||
assert expected_parent_location == self.store.get_item(item_location).get_parent().location
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
|
||||
self.assertEqual(published_parent_location, self.store.get_item(item_location).get_parent().location)
|
||||
assert published_parent_location == self.store.get_item(item_location).get_parent().location
|
||||
|
||||
# Make location specific to published branch for verify_get_parent_locations_results call.
|
||||
published_parent_location = published_parent_location.for_branch(ModuleStoreEnum.BranchName.published)
|
||||
@@ -1191,12 +1182,12 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
])
|
||||
|
||||
# Also verify item.parent has correct parent location set.
|
||||
self.assertEqual(source_item.parent, expected_parent_location)
|
||||
self.assertEqual(source_item.parent, self.store.get_parent_location(item_location))
|
||||
assert source_item.parent == expected_parent_location
|
||||
assert source_item.parent == self.store.get_parent_location(item_location)
|
||||
|
||||
# Item should be present in new parent's children list but not in old parent's children list.
|
||||
self.assertIn(item_location, expected_parent.children)
|
||||
self.assertNotIn(item_location, old_parent.children)
|
||||
assert item_location in expected_parent.children
|
||||
assert item_location not in old_parent.children
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_update_item_parent(self, store_type):
|
||||
@@ -1216,7 +1207,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1243,7 +1234,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1280,7 +1271,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1321,7 +1312,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1343,7 +1334,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1376,13 +1367,13 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.update_item(problem, self.user_id)
|
||||
|
||||
updated_problem = self.store.get_item(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(updated_problem.display_name, 'updated')
|
||||
assert updated_problem.display_name == 'updated'
|
||||
|
||||
# Now, move from x1 to y1.
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1395,7 +1386,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Check that problem has the original name back.
|
||||
reverted_problem = self.store.get_item(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(orig_display_name, reverted_problem.display_name)
|
||||
assert orig_display_name == reverted_problem.display_name
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_move_1_moved_1_unchanged(self, store_type):
|
||||
@@ -1420,7 +1411,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1430,8 +1421,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Check that problem_item2 is still present in vertical_x1a
|
||||
problem_item2 = self.store.get_item(problem_item2.location)
|
||||
self.assertEqual(problem_item2.parent, self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertIn(problem_item2.location, problem_item2.get_parent().children)
|
||||
assert problem_item2.parent == self.vertical_x1a # lint-amnesty, pylint: disable=no-member
|
||||
assert problem_item2.location in problem_item2.get_parent().children
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_move_1_moved_1_edited(self, store_type):
|
||||
@@ -1455,7 +1446,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.update_item(problem_item2, self.user_id)
|
||||
|
||||
updated_problem2 = self.store.get_item(problem_item2.location)
|
||||
self.assertEqual(updated_problem2.display_name, 'updated')
|
||||
assert updated_problem2.display_name == 'updated'
|
||||
|
||||
item_location = self.problem_x1a_1 # lint-amnesty, pylint: disable=no-member
|
||||
new_parent_location = self.vertical_y1a # lint-amnesty, pylint: disable=no-member
|
||||
@@ -1465,7 +1456,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1478,7 +1469,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Check that problem_item2 has the original name back.
|
||||
reverted_problem2 = self.store.get_item(problem_item2.location)
|
||||
self.assertEqual(orig_display_name, reverted_problem2.display_name)
|
||||
assert orig_display_name == reverted_problem2.display_name
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_move_1_moved_1_deleted(self, store_type):
|
||||
@@ -1509,7 +1500,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_item_location = self.store.update_item_parent(
|
||||
item_location, new_parent_location, old_parent_location, self.user_id
|
||||
)
|
||||
self.assertEqual(updated_item_location, item_location)
|
||||
assert updated_item_location == item_location
|
||||
|
||||
self.verify_item_parent(
|
||||
item_location=item_location,
|
||||
@@ -1522,8 +1513,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Check that problem_item2 is also back in vertical_x1a
|
||||
problem_item2 = self.store.get_item(problem_item2.location)
|
||||
self.assertEqual(problem_item2.parent, self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertIn(problem_item2.location, problem_item2.get_parent().children)
|
||||
assert problem_item2.parent == self.vertical_x1a # lint-amnesty, pylint: disable=no-member
|
||||
assert problem_item2.location in problem_item2.get_parent().children
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_get_parent_locations_moved_child(self, default_ms):
|
||||
@@ -1546,7 +1537,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
old_parent = self.store.get_item(child_to_move_location).get_parent()
|
||||
|
||||
self.assertEqual(old_parent_location, old_parent.location)
|
||||
assert old_parent_location == old_parent.location
|
||||
|
||||
child_to_move_contextualized = child_to_move_location.map_into_course(old_parent.location.course_key)
|
||||
old_parent.children.remove(child_to_move_contextualized)
|
||||
@@ -1557,9 +1548,9 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.update_item(new_parent, self.user_id)
|
||||
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
self.assertEqual(new_parent_location, self.store.get_item(child_to_move_location).get_parent().location)
|
||||
assert new_parent_location == self.store.get_item(child_to_move_location).get_parent().location
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
|
||||
self.assertEqual(old_parent_location, self.store.get_item(child_to_move_location).get_parent().location)
|
||||
assert old_parent_location == self.store.get_item(child_to_move_location).get_parent().location
|
||||
old_parent_published_location = old_parent_location.for_branch(ModuleStoreEnum.BranchName.published)
|
||||
self.verify_get_parent_locations_results([
|
||||
(child_to_move_location, new_parent_location, None),
|
||||
@@ -1631,7 +1622,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
# convert first parent (unit) "vertical_x1a" of problem "problem_x1a_1" to draft
|
||||
self.store.convert_to_draft(self.vertical_x1a, self.user_id) # lint-amnesty, pylint: disable=no-member
|
||||
item = self.store.get_item(self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertTrue(self.store.has_published_version(item))
|
||||
assert self.store.has_published_version(item)
|
||||
|
||||
# now problem "problem_x1a_1" has 3 parents [vertical_x1a (draft),
|
||||
# vertical_x1a (published), vertical_x1b (published)]
|
||||
@@ -1640,7 +1631,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
# problem location revision
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course_id):
|
||||
parent = mongo_store.get_parent_location(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(parent, self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
assert parent == self.vertical_x1a # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
# Draft:
|
||||
# Problem path:
|
||||
@@ -1673,14 +1664,14 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
# each iteration has different find count, pop this iter's find count
|
||||
with check_mongo_calls(num_finds.pop(0), num_sends):
|
||||
path = path_to_location(self.store, location)
|
||||
self.assertEqual(path, expected)
|
||||
assert path == expected
|
||||
|
||||
not_found = (
|
||||
course_key.make_usage_key('video', 'WelcomeX'),
|
||||
course_key.make_usage_key('course', 'NotHome'),
|
||||
)
|
||||
for location in not_found:
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
path_to_location(self.store, location)
|
||||
|
||||
# Orphaned items should not be found.
|
||||
@@ -1692,7 +1683,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
block_id=orphan.block_id
|
||||
)
|
||||
|
||||
with self.assertRaises(NoPathToItem):
|
||||
with pytest.raises(NoPathToItem):
|
||||
path_to_location(self.store, orphan)
|
||||
|
||||
def test_navigation_index(self):
|
||||
@@ -1700,12 +1691,12 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
Make sure that navigation_index correctly parses the various position values that we might get from calls to
|
||||
path_to_location
|
||||
"""
|
||||
self.assertEqual(1, navigation_index("1"))
|
||||
self.assertEqual(10, navigation_index("10"))
|
||||
self.assertEqual(None, navigation_index(None))
|
||||
self.assertEqual(1, navigation_index("1_2"))
|
||||
self.assertEqual(5, navigation_index("5_2"))
|
||||
self.assertEqual(7, navigation_index("7_3_5_6_"))
|
||||
assert 1 == navigation_index('1')
|
||||
assert 10 == navigation_index('10')
|
||||
assert navigation_index(None) is None
|
||||
assert 1 == navigation_index('1_2')
|
||||
assert 5 == navigation_index('5_2')
|
||||
assert 7 == navigation_index('7_3_5_6_')
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_revert_to_published_root_draft(self, default_ms):
|
||||
@@ -1719,25 +1710,25 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
vertical_children_num = len(vertical.children)
|
||||
|
||||
self.store.publish(self.course.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(self.vertical_x1a)) # lint-amnesty, pylint: disable=no-member
|
||||
assert not self._has_changes(self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
# delete leaf problem (will make parent vertical a draft)
|
||||
self.store.delete_item(self.problem_x1a_1, self.user_id) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertTrue(self._has_changes(self.vertical_x1a)) # lint-amnesty, pylint: disable=no-member
|
||||
assert self._has_changes(self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
draft_parent = self.store.get_item(self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(vertical_children_num - 1, len(draft_parent.children))
|
||||
assert (vertical_children_num - 1) == len(draft_parent.children)
|
||||
published_parent = self.store.get_item(
|
||||
self.vertical_x1a, # lint-amnesty, pylint: disable=no-member
|
||||
revision=ModuleStoreEnum.RevisionOption.published_only
|
||||
)
|
||||
self.assertEqual(vertical_children_num, len(published_parent.children))
|
||||
assert vertical_children_num == len(published_parent.children)
|
||||
|
||||
self.store.revert_to_published(self.vertical_x1a, self.user_id) # lint-amnesty, pylint: disable=no-member
|
||||
reverted_parent = self.store.get_item(self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(vertical_children_num, len(published_parent.children))
|
||||
assert vertical_children_num == len(published_parent.children)
|
||||
self.assertBlocksEqualByFields(reverted_parent, published_parent)
|
||||
self.assertFalse(self._has_changes(self.vertical_x1a)) # lint-amnesty, pylint: disable=no-member
|
||||
assert not self._has_changes(self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_revert_to_published_root_published(self, default_ms):
|
||||
@@ -1757,7 +1748,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.revert_to_published(self.vertical_x1a, self.user_id) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
reverted_problem = self.store.get_item(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(orig_display_name, reverted_problem.display_name)
|
||||
assert orig_display_name == reverted_problem.display_name
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_revert_to_published_no_draft(self, default_ms):
|
||||
@@ -1781,7 +1772,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
"""
|
||||
self.initdb(default_ms)
|
||||
self._create_block_hierarchy()
|
||||
with self.assertRaises(InvalidVersionError):
|
||||
with pytest.raises(InvalidVersionError):
|
||||
self.store.revert_to_published(self.vertical_x1a, self.user_id) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
@@ -1795,7 +1786,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.revert_to_published(self.sequential_x1, self.user_id) # lint-amnesty, pylint: disable=no-member
|
||||
reverted_parent = self.store.get_item(self.sequential_x1) # lint-amnesty, pylint: disable=no-member
|
||||
# It does not discard the child vertical, even though that child is a draft (with no published version)
|
||||
self.assertEqual(num_children, len(reverted_parent.children))
|
||||
assert num_children == len(reverted_parent.children)
|
||||
|
||||
def test_reset_course_to_version(self):
|
||||
"""
|
||||
@@ -1943,7 +1934,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
mongo_store = self.store._get_modulestore_for_courselike(course_id) # pylint: disable=protected-access
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only, course_id):
|
||||
parent = mongo_store.get_parent_location(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(parent, self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
assert parent == self.vertical_x1a # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
# add some published orphans
|
||||
orphan_sequential = course_id.make_usage_key('sequential', 'OrphanSequential')
|
||||
@@ -1959,8 +1950,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.publish(location, self.user_id)
|
||||
|
||||
found_orphans = mongo_store.get_orphans(course_id)
|
||||
self.assertEqual(set(found_orphans), set(orphan_locations))
|
||||
self.assertEqual(len(set(found_orphans)), 2)
|
||||
assert set(found_orphans) == set(orphan_locations)
|
||||
assert len(set(found_orphans)) == 2
|
||||
|
||||
# add orphan vertical and sequential as another parents of problem "problem_x1a_1"
|
||||
mongo_store.collection.update_one(
|
||||
@@ -1975,18 +1966,15 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
# problem "problem_x1a_1" since the two other parents are orphans
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only, course_id):
|
||||
parent = mongo_store.get_parent_location(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
self.assertEqual(parent, self.vertical_x1a) # lint-amnesty, pylint: disable=no-member
|
||||
assert parent == self.vertical_x1a # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
# now add valid published vertical as another parent of problem
|
||||
mongo_store.collection.update_one(
|
||||
self.sequential_x1.to_deprecated_son('_id.'), # lint-amnesty, pylint: disable=no-member
|
||||
{'$push': {'definition.children': six.text_type(self.problem_x1a_1)}} # lint-amnesty, pylint: disable=no-member
|
||||
)
|
||||
mongo_store.collection.update_one(self.sequential_x1.to_deprecated_son('_id.'), {'$push': {'definition.children': six.text_type(self.problem_x1a_1)}}) # lint-amnesty, pylint: disable=no-member, line-too-long
|
||||
# now check that "get_parent_location" method of published branch raises "ReferentialIntegrityError" for
|
||||
# problem "problem_x1a_1" since it has now 2 valid published parents
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only, course_id):
|
||||
self.assertTrue(self.store.has_item(self.problem_x1a_1)) # lint-amnesty, pylint: disable=no-member
|
||||
with self.assertRaises(ReferentialIntegrityError):
|
||||
assert self.store.has_item(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
with pytest.raises(ReferentialIntegrityError):
|
||||
self.store.get_parent_location(self.problem_x1a_1) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo)
|
||||
@@ -2003,7 +1991,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
block_id='orphan'
|
||||
)
|
||||
orphans = self.store.get_orphans(self.course_locations[self.MONGO_COURSEID].course_key)
|
||||
self.assertEqual(len(orphans), 0, "unexpected orphans: {}".format(orphans))
|
||||
assert len(orphans) == 0, 'unexpected orphans: {}'.format(orphans)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_create_item_populates_edited_info(self, default_ms):
|
||||
@@ -2013,8 +2001,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.course.location.course_key,
|
||||
'problem'
|
||||
)
|
||||
self.assertEqual(self.user_id, block.edited_by)
|
||||
self.assertGreater(datetime.datetime.now(UTC), block.edited_on)
|
||||
assert self.user_id == block.edited_by
|
||||
assert datetime.datetime.now(UTC) > block.edited_on
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_create_item_populates_subtree_edited_info(self, default_ms):
|
||||
@@ -2024,8 +2012,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.course.location.course_key,
|
||||
'problem'
|
||||
)
|
||||
self.assertEqual(self.user_id, block.subtree_edited_by)
|
||||
self.assertGreater(datetime.datetime.now(UTC), block.subtree_edited_on)
|
||||
assert self.user_id == block.subtree_edited_by
|
||||
assert datetime.datetime.now(UTC) > block.subtree_edited_on
|
||||
|
||||
# Draft: wildcard search of draft and split
|
||||
# Split: wildcard search of draft and split
|
||||
@@ -2039,14 +2027,11 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
# Test Mongo wiki
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
wiki_courses = self.store.get_courses_for_wiki('999')
|
||||
self.assertEqual(len(wiki_courses), 1)
|
||||
self.assertIn(
|
||||
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None), # Branch agnostic
|
||||
wiki_courses
|
||||
)
|
||||
assert len(wiki_courses) == 1
|
||||
assert self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None) in wiki_courses
|
||||
|
||||
self.assertEqual(len(self.store.get_courses_for_wiki('edX.simple.2012_Fall')), 0)
|
||||
self.assertEqual(len(self.store.get_courses_for_wiki('no_such_wiki')), 0)
|
||||
assert len(self.store.get_courses_for_wiki('edX.simple.2012_Fall')) == 0
|
||||
assert len(self.store.get_courses_for_wiki('no_such_wiki')) == 0
|
||||
|
||||
# Draft:
|
||||
# Find: find vertical, find children
|
||||
@@ -2075,13 +2060,13 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.vertical_x1a, # lint-amnesty, pylint: disable=no-member
|
||||
revision=ModuleStoreEnum.RevisionOption.published_only
|
||||
)
|
||||
self.assertIsNotNone(published_xblock)
|
||||
assert published_xblock is not None
|
||||
|
||||
# unpublish
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
self.store.unpublish(self.vertical_x1a, self.user_id) # lint-amnesty, pylint: disable=no-member
|
||||
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.store.get_item(
|
||||
self.vertical_x1a, # lint-amnesty, pylint: disable=no-member
|
||||
revision=ModuleStoreEnum.RevisionOption.published_only
|
||||
@@ -2092,7 +2077,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.vertical_x1a, # lint-amnesty, pylint: disable=no-member
|
||||
revision=ModuleStoreEnum.RevisionOption.draft_only
|
||||
)
|
||||
self.assertIsNotNone(draft_xblock)
|
||||
assert draft_xblock is not None
|
||||
|
||||
# Draft: specific query for revision None
|
||||
# Split: active_versions, structure
|
||||
@@ -2109,33 +2094,33 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
item = self.store.create_child(self.user_id, self.writable_chapter_location, 'problem', 'test_compute_publish_state') # lint-amnesty, pylint: disable=line-too-long
|
||||
item_location = item.location
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
self.assertFalse(self.store.has_published_version(item))
|
||||
assert not self.store.has_published_version(item)
|
||||
|
||||
# Private -> Public
|
||||
self.store.publish(item_location, self.user_id)
|
||||
item = self.store.get_item(item_location)
|
||||
self.assertTrue(self.store.has_published_version(item))
|
||||
assert self.store.has_published_version(item)
|
||||
|
||||
# Public -> Private
|
||||
self.store.unpublish(item_location, self.user_id)
|
||||
item = self.store.get_item(item_location)
|
||||
self.assertFalse(self.store.has_published_version(item))
|
||||
assert not self.store.has_published_version(item)
|
||||
|
||||
# Private -> Public
|
||||
self.store.publish(item_location, self.user_id)
|
||||
item = self.store.get_item(item_location)
|
||||
self.assertTrue(self.store.has_published_version(item))
|
||||
assert self.store.has_published_version(item)
|
||||
|
||||
# Public -> Draft with NO changes
|
||||
self.store.convert_to_draft(item_location, self.user_id)
|
||||
item = self.store.get_item(item_location)
|
||||
self.assertTrue(self.store.has_published_version(item))
|
||||
assert self.store.has_published_version(item)
|
||||
|
||||
# Draft WITH changes
|
||||
item.display_name = 'new name'
|
||||
item = self.store.update_item(item, self.user_id)
|
||||
self.assertTrue(self.store.has_changes(item))
|
||||
self.assertTrue(self.store.has_published_version(item))
|
||||
assert self.store.has_changes(item)
|
||||
assert self.store.has_published_version(item)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_update_edit_info_ancestors(self, default_ms):
|
||||
@@ -2152,13 +2137,13 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
"""
|
||||
node = self.store.get_item(location_key)
|
||||
if after:
|
||||
self.assertLess(after, node.edited_on)
|
||||
self.assertLess(node.edited_on, before)
|
||||
self.assertEqual(node.edited_by, edited_by)
|
||||
assert after < node.edited_on
|
||||
assert node.edited_on < before
|
||||
assert node.edited_by == edited_by
|
||||
if subtree_after:
|
||||
self.assertLess(subtree_after, node.subtree_edited_on)
|
||||
self.assertLess(node.subtree_edited_on, subtree_before)
|
||||
self.assertEqual(node.subtree_edited_by, subtree_by)
|
||||
assert subtree_after < node.subtree_edited_on
|
||||
assert node.subtree_edited_on < subtree_before
|
||||
assert node.subtree_edited_by == subtree_by
|
||||
|
||||
with self.store.bulk_operations(test_course.id):
|
||||
# Create a dummy vertical & html to test against
|
||||
@@ -2230,7 +2215,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
)
|
||||
|
||||
# Store the current edit time and verify that user created the component
|
||||
self.assertEqual(component.edited_by, self.user_id)
|
||||
assert component.edited_by == self.user_id
|
||||
old_edited_on = component.edited_on
|
||||
|
||||
edit_user = self.user_id - 2
|
||||
@@ -2240,8 +2225,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_component = self.store.get_item(component.location)
|
||||
|
||||
# Verify the ordering of edit times and that dummy_user made the edit
|
||||
self.assertLess(old_edited_on, updated_component.edited_on)
|
||||
self.assertEqual(updated_component.edited_by, edit_user)
|
||||
assert old_edited_on < updated_component.edited_on
|
||||
assert updated_component.edited_by == edit_user
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_update_published_info(self, default_ms):
|
||||
@@ -2267,15 +2252,15 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
updated_component = self.store.get_item(component.location)
|
||||
|
||||
# Verify the time order and that publish_user caused publication
|
||||
self.assertLessEqual(old_time, updated_component.published_on)
|
||||
self.assertEqual(updated_component.published_by, publish_user)
|
||||
assert old_time <= updated_component.published_on
|
||||
assert updated_component.published_by == publish_user
|
||||
|
||||
# Verify that changing the item doesn't unset the published info
|
||||
updated_component.display_name = 'changed'
|
||||
self.store.update_item(updated_component, self.user_id)
|
||||
updated_component = self.store.get_item(updated_component.location)
|
||||
self.assertLessEqual(old_time, updated_component.published_on)
|
||||
self.assertEqual(updated_component.published_by, publish_user)
|
||||
assert old_time <= updated_component.published_on
|
||||
assert updated_component.published_by == publish_user
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_auto_publish(self, default_ms):
|
||||
@@ -2290,62 +2275,53 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# test create_course to make sure we are autopublishing
|
||||
test_course = self.store.create_course('testx', 'GreekHero', 'test_run', self.user_id)
|
||||
self.assertTrue(self.store.has_published_version(test_course))
|
||||
assert self.store.has_published_version(test_course)
|
||||
|
||||
test_course_key = test_course.id
|
||||
|
||||
# test create_item of direct-only category to make sure we are autopublishing
|
||||
chapter = self.store.create_child(self.user_id, test_course.location, 'chapter', 'Overview')
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
|
||||
self.assertIn(
|
||||
chapter.location,
|
||||
self.store.get_item(test_course.location).children,
|
||||
)
|
||||
self.assertTrue(self.store.has_published_version(chapter))
|
||||
assert chapter.location in self.store.get_item(test_course.location).children
|
||||
assert self.store.has_published_version(chapter)
|
||||
|
||||
chapter_location = chapter.location
|
||||
|
||||
# test create_child of direct-only category to make sure we are autopublishing
|
||||
sequential = self.store.create_child(self.user_id, chapter_location, 'sequential', 'Sequence')
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
|
||||
self.assertIn(
|
||||
sequential.location,
|
||||
self.store.get_item(chapter_location).children,
|
||||
)
|
||||
self.assertTrue(self.store.has_published_version(sequential))
|
||||
assert sequential.location in self.store.get_item(chapter_location).children
|
||||
assert self.store.has_published_version(sequential)
|
||||
|
||||
# test update_item of direct-only category to make sure we are autopublishing
|
||||
sequential.display_name = 'sequential1'
|
||||
sequential = self.store.update_item(sequential, self.user_id)
|
||||
self.assertTrue(self.store.has_published_version(sequential))
|
||||
assert self.store.has_published_version(sequential)
|
||||
|
||||
# test delete_item of direct-only category to make sure we are autopublishing
|
||||
self.store.delete_item(sequential.location, self.user_id, revision=ModuleStoreEnum.RevisionOption.all)
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
|
||||
self.assertNotIn(
|
||||
sequential.location,
|
||||
self.store.get_item(chapter_location).children,
|
||||
)
|
||||
assert sequential.location not in self.store.get_item(chapter_location).children
|
||||
chapter = self.store.get_item(chapter.location.for_branch(None))
|
||||
self.assertTrue(self.store.has_published_version(chapter))
|
||||
assert self.store.has_published_version(chapter)
|
||||
|
||||
# test create_child of NOT direct-only category to make sure we aren't autopublishing
|
||||
problem_child = self.store.create_child(self.user_id, chapter_location, 'problem', 'Problem_Child')
|
||||
self.assertFalse(self.store.has_published_version(problem_child))
|
||||
assert not self.store.has_published_version(problem_child)
|
||||
|
||||
# test create_item of NOT direct-only category to make sure we aren't autopublishing
|
||||
problem_item = self.store.create_item(self.user_id, test_course_key, 'problem', 'Problem_Item')
|
||||
self.assertFalse(self.store.has_published_version(problem_item))
|
||||
assert not self.store.has_published_version(problem_item)
|
||||
|
||||
# test update_item of NOT direct-only category to make sure we aren't autopublishing
|
||||
problem_item.display_name = 'Problem_Item1'
|
||||
problem_item = self.store.update_item(problem_item, self.user_id)
|
||||
self.assertFalse(self.store.has_published_version(problem_item))
|
||||
assert not self.store.has_published_version(problem_item)
|
||||
|
||||
# test delete_item of NOT direct-only category to make sure we aren't autopublishing
|
||||
self.store.delete_item(problem_child.location, self.user_id)
|
||||
chapter = self.store.get_item(chapter.location.for_branch(None))
|
||||
self.assertTrue(self.store.has_published_version(chapter))
|
||||
assert self.store.has_published_version(chapter)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_get_courses_for_wiki_shared(self, default_ms):
|
||||
@@ -2356,10 +2332,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# verify initial state - initially, we should have a wiki for the Mongo course
|
||||
wiki_courses = self.store.get_courses_for_wiki('999')
|
||||
self.assertIn(
|
||||
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None), # Branch agnostic
|
||||
wiki_courses
|
||||
)
|
||||
assert self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None) in wiki_courses
|
||||
|
||||
# set Mongo course to share the wiki with simple course
|
||||
mongo_course = self.store.get_course(self.course_locations[self.MONGO_COURSEID].course_key)
|
||||
@@ -2368,15 +2341,12 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# now mongo_course should not be retrievable with old wiki_slug
|
||||
wiki_courses = self.store.get_courses_for_wiki('999')
|
||||
self.assertEqual(len(wiki_courses), 0)
|
||||
assert len(wiki_courses) == 0
|
||||
|
||||
# but there should be one course with wiki_slug 'simple'
|
||||
wiki_courses = self.store.get_courses_for_wiki('simple')
|
||||
self.assertEqual(len(wiki_courses), 1)
|
||||
self.assertIn(
|
||||
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None),
|
||||
wiki_courses
|
||||
)
|
||||
assert len(wiki_courses) == 1
|
||||
assert self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None) in wiki_courses
|
||||
|
||||
# configure mongo course to use unique wiki_slug.
|
||||
mongo_course = self.store.get_course(self.course_locations[self.MONGO_COURSEID].course_key)
|
||||
@@ -2384,18 +2354,12 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.update_item(mongo_course, self.user_id)
|
||||
# it should be retrievable with its new wiki_slug
|
||||
wiki_courses = self.store.get_courses_for_wiki('MITx.999.2013_Spring')
|
||||
self.assertEqual(len(wiki_courses), 1)
|
||||
self.assertIn(
|
||||
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None),
|
||||
wiki_courses
|
||||
)
|
||||
assert len(wiki_courses) == 1
|
||||
assert self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None) in wiki_courses
|
||||
# and NOT retriveable with its old wiki_slug
|
||||
wiki_courses = self.store.get_courses_for_wiki('simple')
|
||||
self.assertEqual(len(wiki_courses), 0)
|
||||
self.assertNotIn(
|
||||
self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None),
|
||||
wiki_courses
|
||||
)
|
||||
assert len(wiki_courses) == 0
|
||||
assert self.course_locations[self.MONGO_COURSEID].course_key.replace(branch=None) not in wiki_courses
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_branch_setting(self, default_ms):
|
||||
@@ -2415,10 +2379,8 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
"""
|
||||
Asserts the number of problems with the given display name is the given expected number.
|
||||
"""
|
||||
self.assertEqual(
|
||||
len(self.store.get_items(course_key.for_branch(None), settings={'display_name': display_name})),
|
||||
expected_number
|
||||
)
|
||||
assert len(self.store.get_items(course_key.for_branch(None), settings={'display_name': display_name})) ==\
|
||||
expected_number
|
||||
|
||||
def assertProblemNameEquals(expected_display_name):
|
||||
"""
|
||||
@@ -2426,20 +2388,20 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
"""
|
||||
# check the display_name of the problem
|
||||
problem = self.store.get_item(problem_location)
|
||||
self.assertEqual(problem.display_name, expected_display_name)
|
||||
assert problem.display_name == expected_display_name
|
||||
|
||||
# there should be only 1 problem with the expected_display_name
|
||||
assertNumProblems(expected_display_name, 1)
|
||||
|
||||
# verify Draft problem
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course_key):
|
||||
self.assertTrue(self.store.has_item(problem_location))
|
||||
assert self.store.has_item(problem_location)
|
||||
assertProblemNameEquals(problem_original_name)
|
||||
|
||||
# verify Published problem doesn't exist
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only, course_key):
|
||||
self.assertFalse(self.store.has_item(problem_location))
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
assert not self.store.has_item(problem_location)
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.store.get_item(problem_location)
|
||||
|
||||
# PUBLISH the problem
|
||||
@@ -2448,7 +2410,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# verify Published problem
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only, course_key):
|
||||
self.assertTrue(self.store.has_item(problem_location))
|
||||
assert self.store.has_item(problem_location)
|
||||
assertProblemNameEquals(problem_original_name)
|
||||
|
||||
# verify Draft-preferred
|
||||
@@ -2481,25 +2443,25 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# verify branch setting is published-only in manager
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
|
||||
self.assertEqual(self.store.get_branch_setting(), ModuleStoreEnum.Branch.published_only)
|
||||
assert self.store.get_branch_setting() == ModuleStoreEnum.Branch.published_only
|
||||
|
||||
# verify branch setting is draft-preferred in manager
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
self.assertEqual(self.store.get_branch_setting(), ModuleStoreEnum.Branch.draft_preferred)
|
||||
assert self.store.get_branch_setting() == ModuleStoreEnum.Branch.draft_preferred
|
||||
|
||||
def verify_default_store(self, store_type):
|
||||
"""
|
||||
Verifies the default_store property
|
||||
"""
|
||||
self.assertEqual(self.store.default_modulestore.get_modulestore_type(), store_type)
|
||||
assert self.store.default_modulestore.get_modulestore_type() == store_type
|
||||
|
||||
# verify internal helper method
|
||||
store = self.store._get_modulestore_for_courselike() # pylint: disable=protected-access
|
||||
self.assertEqual(store.get_modulestore_type(), store_type)
|
||||
assert store.get_modulestore_type() == store_type
|
||||
|
||||
# verify store used for creating a course
|
||||
course = self.store.create_course("org", "course{}".format(uuid4().hex[:5]), "run", self.user_id)
|
||||
self.assertEqual(course.system.modulestore.get_modulestore_type(), store_type)
|
||||
assert course.system.modulestore.get_modulestore_type() == store_type
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_default_store(self, default_ms):
|
||||
@@ -2619,7 +2581,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.store.create_item(self.user_id, course_key, block_type)
|
||||
signal_handler.send.assert_not_called()
|
||||
|
||||
self.assertEqual(mock_clear_bulk_ops_record.call_count, 1)
|
||||
assert mock_clear_bulk_ops_record.call_count == 1
|
||||
|
||||
signal_handler.send.assert_called_with('course_published', course_key=course.id)
|
||||
|
||||
@@ -2637,7 +2599,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.addCleanup(self.store.close_all_connections)
|
||||
|
||||
with self.store.default_store(default):
|
||||
self.assertIsNotNone(self.store.thread_cache.default_store.signal_handler)
|
||||
assert self.store.thread_cache.default_store.signal_handler is not None
|
||||
|
||||
signal_handler.send.assert_not_called()
|
||||
|
||||
@@ -2678,7 +2640,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.addCleanup(self.store.close_all_connections)
|
||||
|
||||
with self.store.default_store(default):
|
||||
self.assertIsNotNone(self.store.thread_cache.default_store.signal_handler)
|
||||
assert self.store.thread_cache.default_store.signal_handler is not None
|
||||
|
||||
signal_handler.send.assert_not_called()
|
||||
|
||||
@@ -2709,7 +2671,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.addCleanup(self.store.close_all_connections)
|
||||
|
||||
with self.store.default_store(default):
|
||||
self.assertIsNotNone(self.store.thread_cache.default_store.signal_handler)
|
||||
assert self.store.thread_cache.default_store.signal_handler is not None
|
||||
|
||||
signal_handler.send.assert_not_called()
|
||||
|
||||
@@ -2742,7 +2704,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.addCleanup(self.store.close_all_connections)
|
||||
|
||||
with self.store.default_store(default):
|
||||
self.assertIsNotNone(self.store.thread_cache.default_store.signal_handler)
|
||||
assert self.store.thread_cache.default_store.signal_handler is not None
|
||||
|
||||
signal_handler.send.assert_not_called()
|
||||
|
||||
@@ -2798,7 +2760,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.addCleanup(self.store.close_all_connections)
|
||||
|
||||
with self.store.default_store(default):
|
||||
self.assertIsNotNone(self.store.thread_cache.default_store.signal_handler)
|
||||
assert self.store.thread_cache.default_store.signal_handler is not None
|
||||
|
||||
signal_handler.send.assert_not_called()
|
||||
|
||||
@@ -2840,7 +2802,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.addCleanup(self.store.close_all_connections)
|
||||
|
||||
with self.store.default_store(default):
|
||||
self.assertIsNotNone(self.store.thread_cache.default_store.signal_handler)
|
||||
assert self.store.thread_cache.default_store.signal_handler is not None
|
||||
|
||||
signal_handler.send.assert_not_called()
|
||||
|
||||
@@ -2909,7 +2871,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
self.addCleanup(self.store.close_all_connections)
|
||||
|
||||
with self.store.default_store(default):
|
||||
self.assertIsNotNone(self.store.thread_cache.default_store.signal_handler)
|
||||
assert self.store.thread_cache.default_store.signal_handler is not None
|
||||
|
||||
signal_handler.send.assert_not_called()
|
||||
|
||||
@@ -2949,23 +2911,23 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
self.store.publish(chapter.location, self.user_id)
|
||||
# Verify that there are no changes
|
||||
self.assertFalse(self._has_changes(chapter.location))
|
||||
self.assertFalse(self._has_changes(sequential.location))
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
self.assertFalse(self._has_changes(problem.location))
|
||||
assert not self._has_changes(chapter.location)
|
||||
assert not self._has_changes(sequential.location)
|
||||
assert not self._has_changes(vertical.location)
|
||||
assert not self._has_changes(problem.location)
|
||||
|
||||
# No orphans in course
|
||||
course_orphans = self.store.get_orphans(course_locator)
|
||||
self.assertEqual(len(course_orphans), 0)
|
||||
assert len(course_orphans) == 0
|
||||
self.store.delete_item(vertical.location, self.user_id)
|
||||
|
||||
# No orphans in course after delete, except
|
||||
# in old mongo, which still creates orphans
|
||||
course_orphans = self.store.get_orphans(course_locator)
|
||||
if default_store == ModuleStoreEnum.Type.mongo:
|
||||
self.assertEqual(len(course_orphans), 1)
|
||||
assert len(course_orphans) == 1
|
||||
else:
|
||||
self.assertEqual(len(course_orphans), 0)
|
||||
assert len(course_orphans) == 0
|
||||
|
||||
course_locator_publish = course_locator.for_branch(ModuleStoreEnum.BranchName.published)
|
||||
# No published oprhans after delete, except
|
||||
@@ -2973,9 +2935,9 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
course_publish_orphans = self.store.get_orphans(course_locator_publish)
|
||||
|
||||
if default_store == ModuleStoreEnum.Type.mongo:
|
||||
self.assertEqual(len(course_publish_orphans), 1)
|
||||
assert len(course_publish_orphans) == 1
|
||||
else:
|
||||
self.assertEqual(len(course_publish_orphans), 0)
|
||||
assert len(course_publish_orphans) == 0
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_delete_draft_item_orphans(self, default_store):
|
||||
@@ -3003,28 +2965,28 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
self.store.publish(chapter.location, self.user_id)
|
||||
# Verify that there are no changes
|
||||
self.assertFalse(self._has_changes(chapter.location))
|
||||
self.assertFalse(self._has_changes(sequential.location))
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
self.assertFalse(self._has_changes(problem.location))
|
||||
assert not self._has_changes(chapter.location)
|
||||
assert not self._has_changes(sequential.location)
|
||||
assert not self._has_changes(vertical.location)
|
||||
assert not self._has_changes(problem.location)
|
||||
|
||||
# No orphans in course
|
||||
course_orphans = self.store.get_orphans(course_locator)
|
||||
self.assertEqual(len(course_orphans), 0)
|
||||
assert len(course_orphans) == 0
|
||||
|
||||
problem.display_name = 'changed'
|
||||
problem = self.store.update_item(problem, self.user_id)
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
self.assertTrue(self._has_changes(problem.location))
|
||||
assert self._has_changes(vertical.location)
|
||||
assert self._has_changes(problem.location)
|
||||
|
||||
self.store.delete_item(vertical.location, self.user_id)
|
||||
# No orphans in course after delete, except
|
||||
# in old mongo, which still creates them
|
||||
course_orphans = self.store.get_orphans(course_locator)
|
||||
if default_store == ModuleStoreEnum.Type.mongo:
|
||||
self.assertEqual(len(course_orphans), 1)
|
||||
assert len(course_orphans) == 1
|
||||
else:
|
||||
self.assertEqual(len(course_orphans), 0)
|
||||
assert len(course_orphans) == 0
|
||||
|
||||
course_locator_publish = course_locator.for_branch(ModuleStoreEnum.BranchName.published)
|
||||
# No published orphans after delete, except
|
||||
@@ -3032,9 +2994,9 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
course_publish_orphans = self.store.get_orphans(course_locator_publish)
|
||||
|
||||
if default_store == ModuleStoreEnum.Type.mongo:
|
||||
self.assertEqual(len(course_publish_orphans), 1)
|
||||
assert len(course_publish_orphans) == 1
|
||||
else:
|
||||
self.assertEqual(len(course_publish_orphans), 0)
|
||||
assert len(course_publish_orphans) == 0
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -3106,14 +3068,14 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
block_id='test_vertical'
|
||||
)
|
||||
# Not yet published, so changes are present
|
||||
self.assertTrue(self._has_changes(draft_xblock.location))
|
||||
assert self._has_changes(draft_xblock.location)
|
||||
|
||||
self._export_import_course_round_trip(
|
||||
self.store, contentstore, source_course_key, self.export_dir
|
||||
)
|
||||
|
||||
# Verify that the imported block still is a draft, i.e. has changes.
|
||||
self.assertTrue(self._has_changes(draft_xblock.location))
|
||||
assert self._has_changes(draft_xblock.location)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_published_has_changes_before_export_and_after_import(self, default_ms):
|
||||
@@ -3132,7 +3094,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
self.store.publish(published_xblock.location, self.user_id)
|
||||
|
||||
# Retrieve the published block and make sure it's published.
|
||||
self.assertFalse(self._has_changes(published_xblock.location))
|
||||
assert not self._has_changes(published_xblock.location)
|
||||
|
||||
self._export_import_course_round_trip(
|
||||
self.store, contentstore, source_course_key, self.export_dir
|
||||
@@ -3140,7 +3102,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Get the published xblock from the imported course.
|
||||
# Verify that it still is published, i.e. has no changes.
|
||||
self.assertFalse(self._has_changes(published_xblock.location))
|
||||
assert not self._has_changes(published_xblock.location)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_changed_published_has_changes_before_export_and_after_import(self, default_ms):
|
||||
@@ -3159,13 +3121,13 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
self.store.publish(published_xblock.location, self.user_id)
|
||||
|
||||
# Retrieve the published block and make sure it's published.
|
||||
self.assertFalse(self._has_changes(published_xblock.location))
|
||||
assert not self._has_changes(published_xblock.location)
|
||||
|
||||
updated_display_name = 'Changed Display Name'
|
||||
component = self.store.get_item(published_xblock.location)
|
||||
component.display_name = updated_display_name
|
||||
component = self.store.update_item(component, self.user_id)
|
||||
self.assertTrue(self.store.has_changes(component))
|
||||
assert self.store.has_changes(component)
|
||||
|
||||
self._export_import_course_round_trip(
|
||||
self.store, contentstore, source_course_key, self.export_dir
|
||||
@@ -3173,12 +3135,12 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Get the published xblock from the imported course.
|
||||
# Verify that the published block still has a draft block, i.e. has changes.
|
||||
self.assertTrue(self._has_changes(published_xblock.location))
|
||||
assert self._has_changes(published_xblock.location)
|
||||
|
||||
# Verify that the changes in the draft vertical still exist.
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, source_course_key):
|
||||
component = self.store.get_item(published_xblock.location)
|
||||
self.assertEqual(component.display_name, updated_display_name)
|
||||
assert component.display_name == updated_display_name
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_seq_with_unpublished_vertical_has_changes_before_export_and_after_import(self, default_ms):
|
||||
@@ -3206,11 +3168,11 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Retrieve the published block and make sure it's published.
|
||||
# Chapter is published - but the changes in vertical below means it "has_changes".
|
||||
self.assertTrue(self._has_changes(chapter.location))
|
||||
assert self._has_changes(chapter.location)
|
||||
# Sequential is published - but the changes in vertical below means it "has_changes".
|
||||
self.assertTrue(self._has_changes(sequential.location))
|
||||
assert self._has_changes(sequential.location)
|
||||
# Vertical is unpublished - so it "has_changes".
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
assert self._has_changes(vertical.location)
|
||||
|
||||
self._export_import_course_round_trip(
|
||||
self.store, contentstore, source_course_key, self.export_dir
|
||||
@@ -3218,9 +3180,9 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Get the published xblock from the imported course.
|
||||
# Verify that the published block still has a draft block, i.e. has changes.
|
||||
self.assertTrue(self._has_changes(chapter.location))
|
||||
self.assertTrue(self._has_changes(sequential.location))
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
assert self._has_changes(chapter.location)
|
||||
assert self._has_changes(sequential.location)
|
||||
assert self._has_changes(vertical.location)
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_vertical_with_draft_and_published_unit_has_changes_before_export_and_after_import(self, default_ms):
|
||||
@@ -3246,41 +3208,41 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
self.user_id, sequential.location, 'vertical', block_id='moon_unit'
|
||||
)
|
||||
# Vertical has changes until it is actually published.
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
assert self._has_changes(vertical.location)
|
||||
self.store.publish(vertical.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
assert not self._has_changes(vertical.location)
|
||||
|
||||
# create unit
|
||||
unit = self.store.create_child(
|
||||
self.user_id, vertical.location, 'html', block_id='html_unit'
|
||||
)
|
||||
# Vertical has a new child -and- unit is unpublished. So both have changes.
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
self.assertTrue(self._has_changes(unit.location))
|
||||
assert self._has_changes(vertical.location)
|
||||
assert self._has_changes(unit.location)
|
||||
|
||||
# Publishing the vertical also publishes its unit child.
|
||||
self.store.publish(vertical.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
self.assertFalse(self._has_changes(unit.location))
|
||||
assert not self._has_changes(vertical.location)
|
||||
assert not self._has_changes(unit.location)
|
||||
|
||||
# Publishing the unit separately has no effect on whether it has changes - it's already published.
|
||||
self.store.publish(unit.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
self.assertFalse(self._has_changes(unit.location))
|
||||
assert not self._has_changes(vertical.location)
|
||||
assert not self._has_changes(unit.location)
|
||||
|
||||
# Retrieve the published block and make sure it's published.
|
||||
self.store.publish(chapter.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(chapter.location))
|
||||
self.assertFalse(self._has_changes(sequential.location))
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
self.assertFalse(self._has_changes(unit.location))
|
||||
assert not self._has_changes(chapter.location)
|
||||
assert not self._has_changes(sequential.location)
|
||||
assert not self._has_changes(vertical.location)
|
||||
assert not self._has_changes(unit.location)
|
||||
|
||||
# Now make changes to the unit - but don't publish them.
|
||||
component = self.store.get_item(unit.location)
|
||||
updated_display_name = 'Changed Display Name'
|
||||
component.display_name = updated_display_name
|
||||
component = self.store.update_item(component, self.user_id)
|
||||
self.assertTrue(self._has_changes(component.location))
|
||||
assert self._has_changes(component.location)
|
||||
|
||||
# Export the course - then import the course export.
|
||||
self._export_import_course_round_trip(
|
||||
@@ -3289,20 +3251,20 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Get the published xblock from the imported course.
|
||||
# Verify that the published block still has a draft block, i.e. has changes.
|
||||
self.assertTrue(self._has_changes(chapter.location))
|
||||
self.assertTrue(self._has_changes(sequential.location))
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
self.assertTrue(self._has_changes(unit.location))
|
||||
assert self._has_changes(chapter.location)
|
||||
assert self._has_changes(sequential.location)
|
||||
assert self._has_changes(vertical.location)
|
||||
assert self._has_changes(unit.location)
|
||||
|
||||
# Verify that the changes in the draft unit still exist.
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, source_course_key):
|
||||
component = self.store.get_item(unit.location)
|
||||
self.assertEqual(component.display_name, updated_display_name)
|
||||
assert component.display_name == updated_display_name
|
||||
|
||||
# Verify that the draft changes don't exist in the published unit - it still uses the default name.
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only, source_course_key):
|
||||
component = self.store.get_item(unit.location)
|
||||
self.assertEqual(component.display_name, 'Text')
|
||||
assert component.display_name == 'Text'
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
def test_vertical_with_published_unit_remains_published_before_export_and_after_import(self, default_ms):
|
||||
@@ -3328,9 +3290,9 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
self.user_id, sequential.location, 'vertical', block_id='moon_unit'
|
||||
)
|
||||
# Vertical has changes until it is actually published.
|
||||
self.assertTrue(self._has_changes(vertical.location))
|
||||
assert self._has_changes(vertical.location)
|
||||
self.store.publish(vertical.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
assert not self._has_changes(vertical.location)
|
||||
|
||||
# create unit
|
||||
unit = self.store.create_child(
|
||||
@@ -3340,12 +3302,12 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
updated_display_name = 'Changed Display Name'
|
||||
unit.display_name = updated_display_name
|
||||
unit = self.store.update_item(unit, self.user_id)
|
||||
self.assertTrue(self._has_changes(unit.location))
|
||||
assert self._has_changes(unit.location)
|
||||
|
||||
# Publishing the vertical also publishes its unit child.
|
||||
self.store.publish(vertical.location, self.user_id)
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
self.assertFalse(self._has_changes(unit.location))
|
||||
assert not self._has_changes(vertical.location)
|
||||
assert not self._has_changes(unit.location)
|
||||
|
||||
# Export the course - then import the course export.
|
||||
self._export_import_course_round_trip(
|
||||
@@ -3354,15 +3316,15 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
|
||||
# Get the published xblock from the imported course.
|
||||
# Verify that the published block still has a draft block, i.e. has changes.
|
||||
self.assertFalse(self._has_changes(chapter.location))
|
||||
self.assertFalse(self._has_changes(sequential.location))
|
||||
self.assertFalse(self._has_changes(vertical.location))
|
||||
self.assertFalse(self._has_changes(unit.location))
|
||||
assert not self._has_changes(chapter.location)
|
||||
assert not self._has_changes(sequential.location)
|
||||
assert not self._has_changes(vertical.location)
|
||||
assert not self._has_changes(unit.location)
|
||||
|
||||
# Verify that the published changes exist in the published unit.
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only, source_course_key):
|
||||
component = self.store.get_item(unit.location)
|
||||
self.assertEqual(component.display_name, updated_display_name)
|
||||
assert component.display_name == updated_display_name
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
@XBlockAside.register_temp_plugin(AsideTestType, 'test_aside')
|
||||
@@ -3399,11 +3361,11 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
"""
|
||||
asides = block.runtime.get_asides(block)
|
||||
|
||||
self.assertEqual(len(asides), 1, "Found {} asides but expected only test_aside".format(asides))
|
||||
self.assertIsInstance(asides[0], AsideTestType)
|
||||
assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides)
|
||||
assert isinstance(asides[0], AsideTestType)
|
||||
category = block.scope_ids.block_type
|
||||
self.assertEqual(asides[0].data_field, "{} aside data".format(category))
|
||||
self.assertEqual(asides[0].content, "{} Aside".format(category.capitalize()))
|
||||
assert asides[0].data_field == '{} aside data'.format(category)
|
||||
assert asides[0].content == '{} Aside'.format(category.capitalize())
|
||||
|
||||
for child in block.get_children():
|
||||
check_block(child)
|
||||
@@ -3414,17 +3376,13 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
new_chapter = self.store.create_child(self.user_id, courses[0].location, 'chapter', 'new_chapter')
|
||||
asides = new_chapter.runtime.get_asides(new_chapter)
|
||||
|
||||
self.assertEqual(len(asides), 1, "Found {} asides but expected only test_aside".format(asides))
|
||||
assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides)
|
||||
chapter_aside = asides[0]
|
||||
self.assertIsInstance(chapter_aside, AsideTestType)
|
||||
self.assertFalse(
|
||||
chapter_aside.fields['data_field'].is_set_on(chapter_aside),
|
||||
"data_field says it's assigned to {}".format(chapter_aside.data_field)
|
||||
)
|
||||
self.assertFalse(
|
||||
chapter_aside.fields['content'].is_set_on(chapter_aside),
|
||||
"content says it's assigned to {}".format(chapter_aside.content)
|
||||
)
|
||||
assert isinstance(chapter_aside, AsideTestType)
|
||||
assert not chapter_aside.fields['data_field'].is_set_on(chapter_aside), \
|
||||
f"data_field says it's assigned to {chapter_aside.data_field}"
|
||||
assert not chapter_aside.fields['content'].is_set_on(chapter_aside), \
|
||||
f"content says it's assigned to {chapter_aside.content}"
|
||||
|
||||
# now update the values
|
||||
chapter_aside.data_field = 'new value'
|
||||
@@ -3432,7 +3390,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
|
||||
new_chapter = self.store.get_item(new_chapter.location)
|
||||
chapter_aside = new_chapter.runtime.get_asides(new_chapter)[0]
|
||||
self.assertEqual('new value', chapter_aside.data_field)
|
||||
assert 'new value' == chapter_aside.data_field
|
||||
|
||||
# update the values the second time
|
||||
chapter_aside.data_field = 'another one value'
|
||||
@@ -3440,7 +3398,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
|
||||
new_chapter2 = self.store.get_item(new_chapter.location)
|
||||
chapter_aside2 = new_chapter2.runtime.get_asides(new_chapter2)[0]
|
||||
self.assertEqual('another one value', chapter_aside2.data_field)
|
||||
assert 'another one value' == chapter_aside2.data_field
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
@XBlockAside.register_temp_plugin(AsideTestType, 'test_aside')
|
||||
@@ -3509,7 +3467,7 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
raise_on_failure=True,
|
||||
)
|
||||
|
||||
self.assertEqual(1, len(courses2))
|
||||
assert 1 == len(courses2)
|
||||
|
||||
# check that the imported blocks have the right asides and values
|
||||
def check_block(block):
|
||||
@@ -3518,11 +3476,11 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
"""
|
||||
asides = block.runtime.get_asides(block)
|
||||
|
||||
self.assertEqual(len(asides), 1, "Found {} asides but expected only test_aside".format(asides))
|
||||
self.assertIsInstance(asides[0], AsideTestType)
|
||||
assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides)
|
||||
assert isinstance(asides[0], AsideTestType)
|
||||
category = block.scope_ids.block_type
|
||||
self.assertEqual(asides[0].data_field, "Exported data_field {} aside data".format(category))
|
||||
self.assertEqual(asides[0].content, "Exported content {} Aside".format(category.capitalize()))
|
||||
assert asides[0].data_field == 'Exported data_field {} aside data'.format(category)
|
||||
assert asides[0].content == 'Exported content {} Aside'.format(category.capitalize())
|
||||
|
||||
for child in block.get_children():
|
||||
check_block(child)
|
||||
@@ -3565,9 +3523,9 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
new_chapter.display_name = new_chapter_display_name
|
||||
asides = new_chapter.runtime.get_asides(new_chapter)
|
||||
|
||||
self.assertEqual(len(asides), 1, "Found {} asides but expected only test_aside".format(asides))
|
||||
assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides)
|
||||
chapter_aside = asides[0]
|
||||
self.assertIsInstance(chapter_aside, AsideTestType)
|
||||
assert isinstance(chapter_aside, AsideTestType)
|
||||
chapter_aside.data_field = 'new value'
|
||||
self.store.update_item(new_chapter, self.user_id, asides=[chapter_aside])
|
||||
|
||||
@@ -3578,9 +3536,9 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
new_problem.display_name = new_problem_display_name
|
||||
asides = new_problem.runtime.get_asides(new_problem)
|
||||
|
||||
self.assertEqual(len(asides), 1, "Found {} asides but expected only test_aside".format(asides))
|
||||
assert len(asides) == 1, 'Found {} asides but expected only test_aside'.format(asides)
|
||||
problem_aside = asides[0]
|
||||
self.assertIsInstance(problem_aside, AsideTestType)
|
||||
assert isinstance(problem_aside, AsideTestType)
|
||||
problem_aside.data_field = 'new problem value'
|
||||
problem_aside.content = 'new content value'
|
||||
self.store.update_item(new_problem, self.user_id, asides=[problem_aside])
|
||||
@@ -3607,44 +3565,44 @@ class TestPublishOverExportImport(CommonMixedModuleStoreSetup):
|
||||
raise_on_failure=True,
|
||||
)
|
||||
|
||||
self.assertEqual(1, len(courses2))
|
||||
assert 1 == len(courses2)
|
||||
|
||||
# check that aside for the new chapter was exported/imported properly
|
||||
chapters = courses2[0].get_children()
|
||||
self.assertEqual(2, len(chapters))
|
||||
self.assertIn(new_chapter_display_name, [item.display_name for item in chapters])
|
||||
assert 2 == len(chapters)
|
||||
assert new_chapter_display_name in [item.display_name for item in chapters]
|
||||
|
||||
found = False
|
||||
for child in chapters:
|
||||
if new_chapter.display_name == child.display_name:
|
||||
found = True
|
||||
asides = child.runtime.get_asides(child)
|
||||
self.assertEqual(len(asides), 1)
|
||||
assert len(asides) == 1
|
||||
child_aside = asides[0]
|
||||
self.assertIsInstance(child_aside, AsideTestType)
|
||||
self.assertEqual(child_aside.data_field, 'new value')
|
||||
assert isinstance(child_aside, AsideTestType)
|
||||
assert child_aside.data_field == 'new value'
|
||||
break
|
||||
|
||||
self.assertTrue(found, "new_chapter not found")
|
||||
assert found, 'new_chapter not found'
|
||||
|
||||
# check that aside for the new problem was exported/imported properly
|
||||
sequence_children = courses2[0].get_children()[0].get_children()[0].get_children()
|
||||
self.assertEqual(2, len(sequence_children))
|
||||
self.assertIn(new_problem_display_name, [item.display_name for item in sequence_children])
|
||||
assert 2 == len(sequence_children)
|
||||
assert new_problem_display_name in [item.display_name for item in sequence_children]
|
||||
|
||||
found = False
|
||||
for child in sequence_children:
|
||||
if new_problem.display_name == child.display_name:
|
||||
found = True
|
||||
asides = child.runtime.get_asides(child)
|
||||
self.assertEqual(len(asides), 1)
|
||||
assert len(asides) == 1
|
||||
child_aside = asides[0]
|
||||
self.assertIsInstance(child_aside, AsideTestType)
|
||||
self.assertEqual(child_aside.data_field, 'new problem value')
|
||||
self.assertEqual(child_aside.content, 'new content value')
|
||||
assert isinstance(child_aside, AsideTestType)
|
||||
assert child_aside.data_field == 'new problem value'
|
||||
assert child_aside.content == 'new content value'
|
||||
break
|
||||
|
||||
self.assertTrue(found, "new_chapter not found")
|
||||
assert found, 'new_chapter not found'
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -3704,12 +3662,12 @@ class TestAsidesWithMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
def _check_asides(asides, field11, field12, field21, field22):
|
||||
""" Helper function to check asides """
|
||||
self.assertEqual(len(asides), 2)
|
||||
self.assertEqual({type(asides[0]), type(asides[1])}, {AsideFoo, AsideBar})
|
||||
self.assertEqual(asides[0].field11, field11)
|
||||
self.assertEqual(asides[0].field12, field12)
|
||||
self.assertEqual(asides[1].field21, field21)
|
||||
self.assertEqual(asides[1].field22, field22)
|
||||
assert len(asides) == 2
|
||||
assert {type(asides[0]), type(asides[1])} == {AsideFoo, AsideBar}
|
||||
assert asides[0].field11 == field11
|
||||
assert asides[0].field12 == field12
|
||||
assert asides[1].field21 == field21
|
||||
assert asides[1].field22 == field22
|
||||
|
||||
# get saved item and check asides
|
||||
component = self.store.get_item(published_xblock.location)
|
||||
@@ -3767,13 +3725,13 @@ class TestAsidesWithMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
for block in actual_items:
|
||||
if block.scope_ids.block_type == 'chapter':
|
||||
asides = block.runtime.get_asides(block)
|
||||
self.assertEqual(len(asides), 1)
|
||||
self.assertEqual(asides[0].field11, 'test1')
|
||||
self.assertEqual(asides[0].field12, 'aside1_default_value2')
|
||||
assert len(asides) == 1
|
||||
assert asides[0].field11 == 'test1'
|
||||
assert asides[0].field12 == 'aside1_default_value2'
|
||||
chapter_is_found = True
|
||||
break
|
||||
|
||||
self.assertTrue(chapter_is_found)
|
||||
assert chapter_is_found
|
||||
|
||||
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split)
|
||||
@XBlockAside.register_temp_plugin(AsideFoo, 'test_aside1')
|
||||
@@ -3805,8 +3763,8 @@ class TestAsidesWithMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
)
|
||||
|
||||
asides = published_xblock.runtime.get_asides(published_xblock)
|
||||
self.assertEqual(asides[0].field11, 'new_value11')
|
||||
self.assertEqual(asides[0].field12, 'new_value12')
|
||||
assert asides[0].field11 == 'new_value11'
|
||||
assert asides[0].field12 == 'new_value12'
|
||||
|
||||
# remove item
|
||||
self.store.delete_item(published_xblock.location, self.user_id)
|
||||
@@ -3821,8 +3779,8 @@ class TestAsidesWithMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
|
||||
# check that aside has default values
|
||||
asides2 = published_xblock2.runtime.get_asides(published_xblock2)
|
||||
self.assertEqual(asides2[0].field11, 'aside1_default_value1')
|
||||
self.assertEqual(asides2[0].field12, 'aside1_default_value2')
|
||||
assert asides2[0].field11 == 'aside1_default_value1'
|
||||
assert asides2[0].field12 == 'aside1_default_value2'
|
||||
|
||||
@ddt.data((ModuleStoreEnum.Type.mongo, 1, 0), (ModuleStoreEnum.Type.split, 2, 0))
|
||||
@XBlockAside.register_temp_plugin(AsideFoo, 'test_aside1')
|
||||
@@ -3849,15 +3807,15 @@ class TestAsidesWithMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
def _check_asides(item):
|
||||
""" Helper function to check asides """
|
||||
asides = item.runtime.get_asides(item)
|
||||
self.assertEqual(asides[0].field11, 'new_value11')
|
||||
self.assertEqual(asides[0].field12, 'new_value12')
|
||||
assert asides[0].field11 == 'new_value11'
|
||||
assert asides[0].field12 == 'new_value12'
|
||||
|
||||
# start off as Private
|
||||
item = self.store.create_child(self.user_id, self.writable_chapter_location, 'problem',
|
||||
'test_compute_publish_state', asides=[aside1])
|
||||
item_location = item.location
|
||||
with check_mongo_calls(max_find, max_send):
|
||||
self.assertFalse(self.store.has_published_version(item))
|
||||
assert not self.store.has_published_version(item)
|
||||
_check_asides(item)
|
||||
|
||||
# Private -> Public
|
||||
@@ -3865,7 +3823,7 @@ class TestAsidesWithMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
_check_asides(published_block)
|
||||
|
||||
item = self.store.get_item(item_location)
|
||||
self.assertTrue(self.store.has_published_version(item))
|
||||
assert self.store.has_published_version(item)
|
||||
_check_asides(item)
|
||||
|
||||
# Public -> Private
|
||||
@@ -3873,5 +3831,5 @@ class TestAsidesWithMixedModuleStore(CommonMixedModuleStoreSetup):
|
||||
_check_asides(unpublished_block)
|
||||
|
||||
item = self.store.get_item(item_location)
|
||||
self.assertFalse(self.store.has_published_version(item))
|
||||
assert not self.store.has_published_version(item)
|
||||
_check_asides(item)
|
||||
|
||||
@@ -5,7 +5,7 @@ Tests for testing the modulestore settings migration code.
|
||||
|
||||
import copy
|
||||
from unittest import TestCase
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
|
||||
from openedx.core.lib.tempdir import mkdtemp_clean
|
||||
@@ -124,7 +124,7 @@ class ModuleStoreSettingsMigration(TestCase):
|
||||
"""
|
||||
store_fields = ["OPTIONS", "DOC_STORE_CONFIG"]
|
||||
for field in store_fields:
|
||||
self.assertEqual(store_setting1[field], store_setting2[field])
|
||||
assert store_setting1[field] == store_setting2[field]
|
||||
|
||||
def assertMigrated(self, old_setting):
|
||||
"""
|
||||
@@ -135,11 +135,11 @@ class ModuleStoreSettingsMigration(TestCase):
|
||||
new_mixed_setting = convert_module_store_setting_if_needed(copy.deepcopy(old_setting))
|
||||
|
||||
# check whether the configuration is encapsulated within Mixed.
|
||||
self.assertEqual(new_mixed_setting["default"]["ENGINE"], "xmodule.modulestore.mixed.MixedModuleStore")
|
||||
assert new_mixed_setting['default']['ENGINE'] == 'xmodule.modulestore.mixed.MixedModuleStore'
|
||||
|
||||
# check whether the stores are in an ordered list
|
||||
new_stores = get_mixed_stores(new_mixed_setting)
|
||||
self.assertIsInstance(new_stores, list)
|
||||
assert isinstance(new_stores, list)
|
||||
|
||||
return new_mixed_setting, new_stores[0]
|
||||
|
||||
@@ -151,9 +151,9 @@ class ModuleStoreSettingsMigration(TestCase):
|
||||
split_settings = [store for store in stores if store['ENGINE'].endswith('.DraftVersioningModuleStore')]
|
||||
if len(split_settings): # lint-amnesty, pylint: disable=len-as-condition
|
||||
# there should only be one setting for split
|
||||
self.assertEqual(len(split_settings), 1)
|
||||
assert len(split_settings) == 1
|
||||
# verify name
|
||||
self.assertEqual(split_settings[0]['NAME'], 'split')
|
||||
assert split_settings[0]['NAME'] == 'split'
|
||||
# verify split config settings equal those of mongo
|
||||
self.assertStoreValuesEqual(
|
||||
split_settings[0],
|
||||
@@ -165,28 +165,28 @@ class ModuleStoreSettingsMigration(TestCase):
|
||||
old_setting = self.OLD_CONFIG
|
||||
new_mixed_setting, new_default_store_setting = self.assertMigrated(old_setting)
|
||||
self.assertStoreValuesEqual(new_default_store_setting, old_setting["default"])
|
||||
self.assertEqual(new_default_store_setting["ENGINE"], old_setting["default"]["ENGINE"])
|
||||
self.assertFalse(self.is_split_configured(new_mixed_setting))
|
||||
assert new_default_store_setting['ENGINE'] == old_setting['default']['ENGINE']
|
||||
assert not self.is_split_configured(new_mixed_setting)
|
||||
|
||||
def test_convert_from_old_mongo_to_draft_store(self):
|
||||
old_setting = self.OLD_CONFIG_WITH_DIRECT_MONGO
|
||||
new_mixed_setting, new_default_store_setting = self.assertMigrated(old_setting)
|
||||
self.assertStoreValuesEqual(new_default_store_setting, old_setting["default"])
|
||||
self.assertEqual(new_default_store_setting["ENGINE"], "xmodule.modulestore.mongo.draft.DraftModuleStore")
|
||||
self.assertTrue(self.is_split_configured(new_mixed_setting))
|
||||
assert new_default_store_setting['ENGINE'] == 'xmodule.modulestore.mongo.draft.DraftModuleStore'
|
||||
assert self.is_split_configured(new_mixed_setting)
|
||||
|
||||
def test_convert_from_dict_to_list(self):
|
||||
old_mixed_setting = self.OLD_MIXED_CONFIG_WITH_DICT
|
||||
new_mixed_setting, new_default_store_setting = self.assertMigrated(old_mixed_setting)
|
||||
self.assertEqual(new_default_store_setting["ENGINE"], "the_default_store")
|
||||
self.assertTrue(self.is_split_configured(new_mixed_setting))
|
||||
assert new_default_store_setting['ENGINE'] == 'the_default_store'
|
||||
assert self.is_split_configured(new_mixed_setting)
|
||||
|
||||
# exclude split when comparing old and new, since split was added as part of the migration
|
||||
new_stores = [store for store in get_mixed_stores(new_mixed_setting) if store['NAME'] != 'split']
|
||||
old_stores = get_mixed_stores(self.OLD_MIXED_CONFIG_WITH_DICT)
|
||||
|
||||
# compare each store configured in mixed
|
||||
self.assertEqual(len(new_stores), len(old_stores))
|
||||
assert len(new_stores) == len(old_stores)
|
||||
for new_store in new_stores:
|
||||
self.assertStoreValuesEqual(new_store, old_stores[new_store['NAME']])
|
||||
|
||||
@@ -194,16 +194,16 @@ class ModuleStoreSettingsMigration(TestCase):
|
||||
# make sure there is no migration done on an already updated config
|
||||
old_mixed_setting = self.ALREADY_UPDATED_MIXED_CONFIG
|
||||
new_mixed_setting, new_default_store_setting = self.assertMigrated(old_mixed_setting) # lint-amnesty, pylint: disable=unused-variable
|
||||
self.assertTrue(self.is_split_configured(new_mixed_setting))
|
||||
self.assertEqual(old_mixed_setting, new_mixed_setting)
|
||||
assert self.is_split_configured(new_mixed_setting)
|
||||
assert old_mixed_setting == new_mixed_setting
|
||||
|
||||
@ddt.data('draft', 'split')
|
||||
def test_update_settings(self, default_store):
|
||||
mixed_setting = self.ALREADY_UPDATED_MIXED_CONFIG
|
||||
update_module_store_settings(mixed_setting, default_store=default_store)
|
||||
self.assertEqual(get_mixed_stores(mixed_setting)[0]['NAME'], default_store)
|
||||
assert get_mixed_stores(mixed_setting)[0]['NAME'] == default_store
|
||||
|
||||
def test_update_settings_error(self):
|
||||
mixed_setting = self.ALREADY_UPDATED_MIXED_CONFIG
|
||||
with self.assertRaises(Exception):
|
||||
with pytest.raises(Exception):
|
||||
update_module_store_settings(mixed_setting, default_store='non-existent store')
|
||||
|
||||
@@ -298,7 +298,7 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
"""
|
||||
course_key = CourseKey.from_string('course-v1:edX+simple+2012_Fall')
|
||||
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.draft_store.get_course(course_key)
|
||||
|
||||
def test_has_mongo_course_with_split_course_key(self):
|
||||
@@ -307,7 +307,7 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
"""
|
||||
course_key = CourseKey.from_string('course-v1:edX+simple+2012_Fall')
|
||||
|
||||
self.assertFalse(self.draft_store.has_course(course_key))
|
||||
assert not self.draft_store.has_course(course_key)
|
||||
|
||||
def test_has_course_with_library(self):
|
||||
"""
|
||||
@@ -369,10 +369,8 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
def test_get_courses_has_no_templates(self):
|
||||
courses = self.draft_store.get_courses()
|
||||
for course in courses:
|
||||
self.assertFalse(
|
||||
course.location.org == 'edx' and course.location.course == 'templates',
|
||||
assert not ((course.location.org == 'edx') and (course.location.course == 'templates')),\
|
||||
'{0} is a template course'.format(course)
|
||||
)
|
||||
|
||||
def test_contentstore_attrs(self):
|
||||
"""
|
||||
@@ -566,8 +564,8 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
root_dir = path(mkdtemp())
|
||||
self.addCleanup(shutil.rmtree, root_dir)
|
||||
export_course_to_xml(self.draft_store, self.content_store, course_key, root_dir, u'test_export')
|
||||
self.assertTrue(path(root_dir / 'test_export/static/images/course_image.jpg').isfile())
|
||||
self.assertTrue(path(root_dir / 'test_export/static/images_course_image.jpg').isfile())
|
||||
assert path((root_dir / 'test_export/static/images/course_image.jpg')).isfile()
|
||||
assert path((root_dir / 'test_export/static/images_course_image.jpg')).isfile()
|
||||
|
||||
@patch('xmodule.video_module.video_module.edxval_api', None)
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
@@ -582,8 +580,8 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
root_dir = path(mkdtemp())
|
||||
self.addCleanup(shutil.rmtree, root_dir)
|
||||
export_course_to_xml(self.draft_store, self.content_store, course.id, root_dir, u'test_export')
|
||||
self.assertTrue(path(root_dir / 'test_export/static/just_a_test.jpg').isfile())
|
||||
self.assertFalse(path(root_dir / 'test_export/static/images/course_image.jpg').isfile())
|
||||
assert path((root_dir / 'test_export/static/just_a_test.jpg')).isfile()
|
||||
assert not path((root_dir / 'test_export/static/images/course_image.jpg')).isfile()
|
||||
|
||||
@patch('xmodule.video_module.video_module.edxval_api', None)
|
||||
def test_course_without_image(self):
|
||||
@@ -595,8 +593,8 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
root_dir = path(mkdtemp())
|
||||
self.addCleanup(shutil.rmtree, root_dir)
|
||||
export_course_to_xml(self.draft_store, self.content_store, course.id, root_dir, u'test_export')
|
||||
self.assertFalse(path(root_dir / 'test_export/static/images/course_image.jpg').isfile())
|
||||
self.assertFalse(path(root_dir / 'test_export/static/images_course_image.jpg').isfile())
|
||||
assert not path((root_dir / 'test_export/static/images/course_image.jpg')).isfile()
|
||||
assert not path((root_dir / 'test_export/static/images_course_image.jpg')).isfile()
|
||||
|
||||
def _create_test_tree(self, name, user_id=None):
|
||||
"""
|
||||
@@ -677,8 +675,8 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
|
||||
# Retrieve the block and verify its fields
|
||||
component = self.draft_store.get_item(location)
|
||||
self.assertEqual(component.published_on, published_date)
|
||||
self.assertEqual(component.published_by, published_by)
|
||||
assert component.published_on == published_date
|
||||
assert component.published_by == published_by
|
||||
|
||||
def test_draft_modulestore_create_child_with_position(self):
|
||||
"""
|
||||
@@ -703,8 +701,8 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
|
||||
# First child should have been moved to second position, and better child takes the lead
|
||||
course = self.draft_store.get_course(course.id)
|
||||
self.assertEqual(six.text_type(course.children[1]), six.text_type(first_child.location))
|
||||
self.assertEqual(six.text_type(course.children[0]), six.text_type(second_child.location))
|
||||
assert six.text_type(course.children[1]) == six.text_type(first_child.location)
|
||||
assert six.text_type(course.children[0]) == six.text_type(second_child.location)
|
||||
|
||||
# Clean up the data so we don't break other tests which apparently expect a particular state
|
||||
self.draft_store.delete_course(course.id, self.dummy_user)
|
||||
@@ -713,8 +711,8 @@ class TestMongoModuleStore(TestMongoModuleStoreBase):
|
||||
"""Test that we get back the appropriate usage key for the root of a course key."""
|
||||
course_key = CourseLocator(org="edX", course="101", run="2015")
|
||||
root_block_key = self.draft_store.make_course_usage_key(course_key)
|
||||
self.assertEqual(root_block_key.block_type, "course")
|
||||
self.assertEqual(root_block_key.block_id, "2015")
|
||||
assert root_block_key.block_type == 'course'
|
||||
assert root_block_key.block_id == '2015'
|
||||
|
||||
|
||||
class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore): # lint-amnesty, pylint: disable=test-inherits-tests
|
||||
@@ -741,12 +739,12 @@ class TestMongoModuleStoreWithNoAssetCollection(TestMongoModuleStore): # lint-a
|
||||
courses = self.draft_store.get_courses()
|
||||
course = courses[0]
|
||||
# Confirm that no specified asset collection name means empty asset metadata.
|
||||
self.assertEqual(self.draft_store.get_all_asset_metadata(course.id, 'asset'), [])
|
||||
assert self.draft_store.get_all_asset_metadata(course.id, 'asset') == []
|
||||
|
||||
def test_no_asset_invalid_key(self):
|
||||
course_key = CourseLocator(org="edx3", course="test_course", run=None, deprecated=True)
|
||||
# Confirm that invalid course key raises ItemNotFoundError
|
||||
self.assertRaises(ItemNotFoundError, lambda: self.draft_store.get_all_asset_metadata(course_key, 'asset')[:1])
|
||||
pytest.raises(ItemNotFoundError, (lambda: self.draft_store.get_all_asset_metadata(course_key, 'asset')[:1]))
|
||||
|
||||
|
||||
class TestMongoKeyValueStore(TestCase):
|
||||
|
||||
@@ -13,6 +13,7 @@ from contextlib import contextmanager
|
||||
from shutil import rmtree
|
||||
from tempfile import mkdtemp
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import six
|
||||
from six.moves import range
|
||||
@@ -136,7 +137,7 @@ class TestPublish(SplitWMongoCourseBootstrapper):
|
||||
|
||||
# verify status
|
||||
item = self.draft_mongo.get_item(vert_location, 0)
|
||||
self.assertFalse(getattr(item, 'is_draft', False), "Item was published. Draft should not exist")
|
||||
assert not getattr(item, 'is_draft', False), 'Item was published. Draft should not exist'
|
||||
# however, children are still draft, but I'm not sure that's by design
|
||||
|
||||
# delete the draft version of the discussion
|
||||
@@ -144,8 +145,8 @@ class TestPublish(SplitWMongoCourseBootstrapper):
|
||||
self.draft_mongo.delete_item(location, self.user_id)
|
||||
|
||||
draft_vert = self.draft_mongo.get_item(vert_location, 0)
|
||||
self.assertTrue(getattr(draft_vert, 'is_draft', False), "Deletion didn't convert parent to draft")
|
||||
self.assertNotIn(location, draft_vert.children)
|
||||
assert getattr(draft_vert, 'is_draft', False), "Deletion didn't convert parent to draft"
|
||||
assert location not in draft_vert.children
|
||||
# move the other child
|
||||
other_child_loc = self.old_course_key.make_usage_key('html', block_id='Html2')
|
||||
draft_vert.children.remove(other_child_loc)
|
||||
@@ -156,12 +157,12 @@ class TestPublish(SplitWMongoCourseBootstrapper):
|
||||
# publish
|
||||
self.draft_mongo.publish(vert_location, self.user_id)
|
||||
item = self.draft_mongo.get_item(draft_vert.location, revision=ModuleStoreEnum.RevisionOption.published_only)
|
||||
self.assertNotIn(location, item.children)
|
||||
self.assertIsNone(self.draft_mongo.get_parent_location(location))
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
assert location not in item.children
|
||||
assert self.draft_mongo.get_parent_location(location) is None
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.draft_mongo.get_item(location)
|
||||
self.assertNotIn(other_child_loc, item.children)
|
||||
self.assertTrue(self.draft_mongo.has_item(other_child_loc), "Oops, lost moved item")
|
||||
assert other_child_loc not in item.children
|
||||
assert self.draft_mongo.has_item(other_child_loc), 'Oops, lost moved item'
|
||||
|
||||
|
||||
class DraftPublishedOpTestCourseSetup(unittest.TestCase):
|
||||
@@ -305,10 +306,7 @@ class OLXFormatChecker(unittest.TestCase):
|
||||
self._ensure_exported()
|
||||
|
||||
block_path = os.path.join(self.root_export_dir, self.export_dir) # pylint: disable=no-member
|
||||
self.assertTrue(
|
||||
os.path.isdir(block_path),
|
||||
msg='{} is not a dir.'.format(block_path)
|
||||
)
|
||||
assert os.path.isdir(block_path), '{} is not a dir.'.format(block_path)
|
||||
return block_path
|
||||
|
||||
def _get_block_type_path(self, course_export_dir, block_type, draft):
|
||||
@@ -335,10 +333,7 @@ class OLXFormatChecker(unittest.TestCase):
|
||||
|
||||
block_file = self._get_block_filename(block_id)
|
||||
block_file_path = os.path.join(block_subdir_path, block_file)
|
||||
self.assertTrue(
|
||||
os.path.isfile(block_file_path),
|
||||
msg='{} is not an existing file.'.format(block_file_path)
|
||||
)
|
||||
assert os.path.isfile(block_file_path), '{} is not an existing file.'.format(block_file_path)
|
||||
with open(block_file_path, "r") as file_handle:
|
||||
return file_handle.read()
|
||||
|
||||
@@ -350,7 +345,7 @@ class OLXFormatChecker(unittest.TestCase):
|
||||
element (ElementTree.Element): the element to check.
|
||||
tag (str): The tag to validate.
|
||||
"""
|
||||
self.assertEqual(element.tag, tag)
|
||||
assert element.tag == tag
|
||||
|
||||
def assertElementAttrsSubset(self, element, attrs):
|
||||
"""
|
||||
@@ -395,10 +390,7 @@ class OLXFormatChecker(unittest.TestCase):
|
||||
is_draft = kwargs.pop('draft', False)
|
||||
block_path = self._get_block_type_path(course_export_dir, block_type, is_draft)
|
||||
block_file_path = os.path.join(block_path, self._get_block_filename(block_id))
|
||||
self.assertFalse(
|
||||
os.path.exists(block_file_path),
|
||||
msg='{} exists but should not!'.format(block_file_path)
|
||||
)
|
||||
assert not os.path.exists(block_file_path), '{} exists but should not!'.format(block_file_path)
|
||||
|
||||
def assertParentReferences(self, element, course_key, parent_type, parent_id, index_in_children_list):
|
||||
"""
|
||||
@@ -458,7 +450,7 @@ class OLXFormatChecker(unittest.TestCase):
|
||||
"""
|
||||
for block_data in block_list:
|
||||
block_params = self.course_db.get(block_data)
|
||||
self.assertIsNotNone(block_params)
|
||||
assert block_params is not None
|
||||
(block_type, block_id) = block_data
|
||||
if draft:
|
||||
element = self.parse_olx(block_type, block_id, draft=True)
|
||||
@@ -691,7 +683,7 @@ class ElementalPublishingTests(DraftPublishedOpBaseTestSetup):
|
||||
# In Split, you cannot publish an item whose parents are unpublished.
|
||||
# Split will raise an exception when the item's parent(s) aren't found
|
||||
# in the published branch.
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.publish((('html', 'html00'),))
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
@@ -839,7 +831,7 @@ class ElementalUnpublishingTests(DraftPublishedOpBaseTestSetup):
|
||||
# The unit is a draft.
|
||||
self.assertOLXIsDraftOnly(block_list_to_unpublish)
|
||||
# Since there's no published version, attempting an unpublish throws an exception.
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.unpublish(block_list_to_unpublish)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
@@ -887,7 +879,7 @@ class ElementalUnpublishingTests(DraftPublishedOpBaseTestSetup):
|
||||
# The vertical is a draft.
|
||||
self.assertOLXIsDraftOnly(block_list_to_unpublish)
|
||||
# Since there's no published version, attempting an unpublish throws an exception.
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.unpublish(block_list_to_unpublish)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
@@ -939,7 +931,7 @@ class ElementalUnpublishingTests(DraftPublishedOpBaseTestSetup):
|
||||
block_list_to_unpublish = (
|
||||
('sequential', 'sequential03'),
|
||||
)
|
||||
with self.assertRaises(InvalidVersionError):
|
||||
with pytest.raises(InvalidVersionError):
|
||||
self.unpublish(block_list_to_unpublish)
|
||||
|
||||
|
||||
@@ -983,7 +975,7 @@ class ElementalDeleteItemTests(DraftPublishedOpBaseTestSetup):
|
||||
if revision in (ModuleStoreEnum.RevisionOption.published_only, ModuleStoreEnum.RevisionOption.all):
|
||||
# Split throws an exception when trying to delete an item from the published branch
|
||||
# that isn't yet published.
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
self.delete_item(block_list_to_delete, revision=revision)
|
||||
else:
|
||||
self.delete_item(block_list_to_delete, revision=revision)
|
||||
@@ -1060,7 +1052,7 @@ class ElementalDeleteItemTests(DraftPublishedOpBaseTestSetup):
|
||||
# MODULESTORE_DIFFERENCE:
|
||||
# Split throws an exception when trying to delete an item from the published branch
|
||||
# that isn't yet published.
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
self.delete_item(block_list_to_delete, revision=revision)
|
||||
else:
|
||||
self.delete_item(block_list_to_delete, revision=revision)
|
||||
@@ -1190,7 +1182,7 @@ class ElementalConvertToDraftTests(DraftPublishedOpBaseTestSetup):
|
||||
elif self.is_old_mongo_modulestore:
|
||||
# Old Mongo:
|
||||
# Direct-only categories are never allowed to be converted to draft.
|
||||
with self.assertRaises(InvalidVersionError):
|
||||
with pytest.raises(InvalidVersionError):
|
||||
self.convert_to_draft(block_list_to_convert)
|
||||
else:
|
||||
raise Exception("Must test either Old Mongo or Split modulestore!")
|
||||
@@ -1212,7 +1204,7 @@ class ElementalRevertToPublishedTests(DraftPublishedOpBaseTestSetup):
|
||||
self.assertOLXIsDraftOnly(block_list_to_revert)
|
||||
# Now, without publishing anything first, revert the same vertical to published.
|
||||
# Since no published version exists, an exception is raised.
|
||||
with self.assertRaises(InvalidVersionError):
|
||||
with pytest.raises(InvalidVersionError):
|
||||
self.revert_to_published(block_list_to_revert)
|
||||
|
||||
@ddt.data(*MODULESTORE_SETUPS)
|
||||
|
||||
@@ -6,6 +6,7 @@ Tests of modulestore semantics: How do the interfaces methods of ModuleStore rel
|
||||
import itertools
|
||||
from collections import namedtuple
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
from mock import patch
|
||||
from xblock.core import XBlock, XBlockAside
|
||||
@@ -79,12 +80,12 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
|
||||
"""
|
||||
if draft is None or draft:
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.store.get_item(block_usage_key)
|
||||
|
||||
if draft is None or not draft:
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.published_only):
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.store.get_item(block_usage_key)
|
||||
|
||||
def assertBlockHasContent(self, block_usage_key, field_name, content,
|
||||
@@ -108,22 +109,22 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
|
||||
target_block = self.store.get_item(
|
||||
block_usage_key,
|
||||
)
|
||||
self.assertEqual(content, target_block.fields[field_name].read_from(target_block))
|
||||
assert content == target_block.fields[field_name].read_from(target_block)
|
||||
if aside_field_name and aside_content:
|
||||
aside = self._get_aside(target_block)
|
||||
self.assertIsNotNone(aside)
|
||||
self.assertEqual(aside_content, aside.fields[aside_field_name].read_from(aside))
|
||||
assert aside is not None
|
||||
assert aside_content == aside.fields[aside_field_name].read_from(aside)
|
||||
|
||||
if draft is None or draft:
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
target_block = self.store.get_item(
|
||||
block_usage_key,
|
||||
)
|
||||
self.assertEqual(content, target_block.fields[field_name].read_from(target_block))
|
||||
assert content == target_block.fields[field_name].read_from(target_block)
|
||||
if aside_field_name and aside_content:
|
||||
aside = self._get_aside(target_block)
|
||||
self.assertIsNotNone(aside)
|
||||
self.assertEqual(aside_content, aside.fields[aside_field_name].read_from(aside))
|
||||
assert aside is not None
|
||||
assert aside_content == aside.fields[aside_field_name].read_from(aside)
|
||||
|
||||
def assertParentOf(self, parent_usage_key, child_usage_key, draft=None):
|
||||
"""
|
||||
@@ -142,14 +143,14 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
|
||||
parent_block = self.store.get_item(
|
||||
parent_usage_key,
|
||||
)
|
||||
self.assertIn(child_usage_key, parent_block.children)
|
||||
assert child_usage_key in parent_block.children
|
||||
|
||||
if draft is None or draft:
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
parent_block = self.store.get_item(
|
||||
parent_usage_key,
|
||||
)
|
||||
self.assertIn(child_usage_key, parent_block.children)
|
||||
assert child_usage_key in parent_block.children
|
||||
|
||||
def assertNotParentOf(self, parent_usage_key, child_usage_key, draft=None):
|
||||
"""
|
||||
@@ -168,14 +169,14 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
|
||||
parent_block = self.store.get_item(
|
||||
parent_usage_key,
|
||||
)
|
||||
self.assertNotIn(child_usage_key, parent_block.children)
|
||||
assert child_usage_key not in parent_block.children
|
||||
|
||||
if draft is None or draft:
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
parent_block = self.store.get_item(
|
||||
parent_usage_key,
|
||||
)
|
||||
self.assertNotIn(child_usage_key, parent_block.children)
|
||||
assert child_usage_key not in parent_block.children
|
||||
|
||||
def assertCoursePointsToBlock(self, block_usage_key, draft=None):
|
||||
"""
|
||||
@@ -215,7 +216,7 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
|
||||
expected_fields = CourseSummary.course_info_fields + ['id', 'location', 'has_ended']
|
||||
return all([hasattr(course_summary, field) for field in expected_fields])
|
||||
|
||||
self.assertTrue(all(verify_course_summery_fields(course_summary) for course_summary in course_summaries))
|
||||
assert all((verify_course_summery_fields(course_summary) for course_summary in course_summaries))
|
||||
|
||||
def is_detached(self, block_type):
|
||||
"""
|
||||
@@ -313,7 +314,7 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
|
||||
test_data = self.DATA_FIELDS[block_type]
|
||||
|
||||
updated_field_value = test_data.updated
|
||||
self.assertNotEqual(updated_field_value, block.fields[test_data.field_name].read_from(block))
|
||||
assert updated_field_value != block.fields[test_data.field_name].read_from(block)
|
||||
|
||||
block.fields[test_data.field_name].write_to(block, updated_field_value)
|
||||
|
||||
@@ -338,13 +339,13 @@ class DirectOnlyCategorySemantics(PureModulestoreTestCase):
|
||||
course_summaries = self.store.get_course_summaries()
|
||||
|
||||
# Verify course summaries
|
||||
self.assertEqual(len(course_summaries), 1)
|
||||
assert len(course_summaries) == 1
|
||||
|
||||
# Verify that all course summary objects have the required attributes.
|
||||
self.assertCourseSummaryFields(course_summaries)
|
||||
|
||||
# Verify fetched accessible courses list is a list of CourseSummery instances
|
||||
self.assertTrue(all(isinstance(course, CourseSummary) for course in course_summaries))
|
||||
assert all((isinstance(course, CourseSummary) for course in course_summaries))
|
||||
|
||||
@ddt.data(*itertools.product(['chapter', 'sequential'], [True, False]))
|
||||
@ddt.unpack
|
||||
@@ -437,7 +438,7 @@ class TestSplitDirectOnlyCategorySemantics(DirectOnlyCategorySemantics):
|
||||
with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred):
|
||||
block = self.store.get_item(block_usage_key)
|
||||
aside = self._get_aside(block)
|
||||
self.assertIsNotNone(aside)
|
||||
assert aside is not None
|
||||
aside.fields[self.ASIDE_DATA_FIELD.field_name].write_to(aside, self.ASIDE_DATA_FIELD.updated)
|
||||
|
||||
self.store.update_item(block, ModuleStoreEnum.UserID.test, allow_not_found=True, asides=[aside])
|
||||
|
||||
@@ -7,6 +7,7 @@ However for these tests, we make sure it also works when copying from course to
|
||||
|
||||
import ddt
|
||||
from six.moves import range
|
||||
import pytest
|
||||
|
||||
from xmodule.modulestore import ModuleStoreEnum
|
||||
from xmodule.modulestore.exceptions import ItemNotFoundError
|
||||
@@ -49,20 +50,20 @@ class TestSplitCopyTemplate(MixedSplitTestCase):
|
||||
# Inherit the vertical and the problem from the library into the course:
|
||||
source_keys = [source_container.children[0]]
|
||||
new_blocks = self.store.copy_from_template(source_keys, dest_key=course.location, user_id=self.user_id)
|
||||
self.assertEqual(len(new_blocks), 1)
|
||||
assert len(new_blocks) == 1
|
||||
|
||||
course = self.store.get_course(course.location.course_key) # Reload from modulestore
|
||||
|
||||
self.assertEqual(len(course.children), 1)
|
||||
assert len(course.children) == 1
|
||||
vertical_block_course = self.store.get_item(course.children[0])
|
||||
self.assertEqual(new_blocks[0], vertical_block_course.location)
|
||||
assert new_blocks[0] == vertical_block_course.location
|
||||
problem_block_course = self.store.get_item(vertical_block_course.children[0])
|
||||
self.assertEqual(problem_block_course.display_name, problem_library_display_name)
|
||||
assert problem_block_course.display_name == problem_library_display_name
|
||||
|
||||
# Check that when capa modules are copied, their "markdown" fields (Scope.settings) are removed.
|
||||
# (See note in split.py:copy_from_template())
|
||||
self.assertIsNotNone(problem_block.markdown)
|
||||
self.assertIsNone(problem_block_course.markdown)
|
||||
assert problem_block.markdown is not None
|
||||
assert problem_block_course.markdown is None
|
||||
|
||||
# Override the display_name and weight:
|
||||
new_display_name = "The Trouble with Tribbles"
|
||||
@@ -77,16 +78,16 @@ class TestSplitCopyTemplate(MixedSplitTestCase):
|
||||
|
||||
# Repeat the copy_from_template():
|
||||
new_blocks2 = self.store.copy_from_template(source_keys, dest_key=course.location, user_id=self.user_id)
|
||||
self.assertEqual(new_blocks, new_blocks2)
|
||||
assert new_blocks == new_blocks2
|
||||
# Reload problem_block_course:
|
||||
problem_block_course = self.store.get_item(problem_block_course.location)
|
||||
self.assertEqual(problem_block_course.display_name, new_display_name)
|
||||
self.assertEqual(problem_block_course.weight, new_weight)
|
||||
assert problem_block_course.display_name == new_display_name
|
||||
assert problem_block_course.weight == new_weight
|
||||
|
||||
# Ensure that extra_block was deleted:
|
||||
vertical_block_course = self.store.get_item(new_blocks2[0])
|
||||
self.assertEqual(len(vertical_block_course.children), 1)
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
assert len(vertical_block_course.children) == 1
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
self.store.get_item(extra_block.location)
|
||||
|
||||
def test_copy_from_template_publish(self):
|
||||
@@ -119,7 +120,7 @@ class TestSplitCopyTemplate(MixedSplitTestCase):
|
||||
problem_published = self.store.get_item(
|
||||
problem_key_in_course.for_branch(ModuleStoreEnum.BranchName.published)
|
||||
)
|
||||
self.assertEqual(problem_published.display_name, display_name_expected)
|
||||
assert problem_published.display_name == display_name_expected
|
||||
|
||||
def test_copy_from_template_auto_publish(self):
|
||||
"""
|
||||
@@ -146,7 +147,7 @@ class TestSplitCopyTemplate(MixedSplitTestCase):
|
||||
# Inherit the vertical and the problem from the library into the course:
|
||||
source_keys = [block.location for block in [about, chapter, html]]
|
||||
block_keys = self.store.copy_from_template(source_keys, dest_key=course.location, user_id=self.user_id)
|
||||
self.assertEqual(len(block_keys), len(source_keys))
|
||||
assert len(block_keys) == len(source_keys)
|
||||
|
||||
# Build dict of the new blocks in 'course', keyed by category (which is a unique key in our case)
|
||||
new_blocks = {}
|
||||
@@ -167,14 +168,15 @@ class TestSplitCopyTemplate(MixedSplitTestCase):
|
||||
return False
|
||||
|
||||
# Check that the auto-publish blocks have been published:
|
||||
self.assertFalse(self.store.has_changes(new_blocks["about"]))
|
||||
assert not self.store.has_changes(new_blocks['about'])
|
||||
# We can't use has_changes because it includes descendants
|
||||
self.assertTrue(published_version_exists(new_blocks["chapter"]))
|
||||
self.assertTrue(published_version_exists(new_blocks["sequential"])) # Ditto
|
||||
assert published_version_exists(new_blocks['chapter'])
|
||||
assert published_version_exists(new_blocks['sequential'])
|
||||
# Ditto
|
||||
# Check that non-auto-publish blocks and blocks with non-auto-publish descendants show changes:
|
||||
self.assertTrue(self.store.has_changes(new_blocks["html"]))
|
||||
self.assertTrue(self.store.has_changes(new_blocks["problem"]))
|
||||
assert self.store.has_changes(new_blocks['html'])
|
||||
assert self.store.has_changes(new_blocks['problem'])
|
||||
# Will have changes since a child block has changes.
|
||||
self.assertTrue(self.store.has_changes(new_blocks["chapter"]))
|
||||
assert self.store.has_changes(new_blocks['chapter'])
|
||||
# Verify that our published_version_exists works
|
||||
self.assertFalse(published_version_exists(new_blocks["vertical"]))
|
||||
assert not published_version_exists(new_blocks['vertical'])
|
||||
|
||||
@@ -165,7 +165,7 @@ class TestMigration(SplitWMongoCourseBootstrapper):
|
||||
|
||||
def compare_dags(self, presplit, presplit_dag_root, split_dag_root, published): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
if split_dag_root.category != 'course':
|
||||
self.assertEqual(presplit_dag_root.location.block_id, split_dag_root.location.block_id)
|
||||
assert presplit_dag_root.location.block_id == split_dag_root.location.block_id
|
||||
# compare all fields but references
|
||||
for name, field in six.iteritems(presplit_dag_root.fields):
|
||||
# fields generated from UNIQUE_IDs are unique to an XBlock's scope,
|
||||
@@ -176,23 +176,11 @@ class TestMigration(SplitWMongoCourseBootstrapper):
|
||||
field_generated_from_unique_id or isinstance(field, (Reference, ReferenceList, ReferenceValueDict))
|
||||
)
|
||||
if should_check_field:
|
||||
self.assertEqual(
|
||||
getattr(presplit_dag_root, name),
|
||||
getattr(split_dag_root, name),
|
||||
u"{}/{}: {} != {}".format(
|
||||
split_dag_root.location, name, getattr(presplit_dag_root, name), getattr(split_dag_root, name)
|
||||
)
|
||||
)
|
||||
assert getattr(presplit_dag_root, name) == getattr(split_dag_root, name), f'{split_dag_root.location}/{name}: {getattr(presplit_dag_root, name)} != {getattr(split_dag_root, name)}' # pylint: disable=line-too-long
|
||||
|
||||
# compare children
|
||||
if presplit_dag_root.has_children:
|
||||
self.assertEqual(
|
||||
# need get_children to filter out drafts
|
||||
len(presplit_dag_root.get_children()), len(split_dag_root.children),
|
||||
u"{0.category} '{0.display_name}': children {1} != {2}".format(
|
||||
presplit_dag_root, presplit_dag_root.children, split_dag_root.children
|
||||
)
|
||||
)
|
||||
assert len(presplit_dag_root.get_children()) == len(split_dag_root.children), f"{presplit_dag_root.category} '{presplit_dag_root.display_name}': children {presplit_dag_root.children} != {split_dag_root.children}" # pylint: disable=line-too-long
|
||||
for pre_child, split_child in zip(presplit_dag_root.get_children(), split_dag_root.get_children()):
|
||||
self.compare_dags(presplit, pre_child, split_child, published)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import re
|
||||
import unittest
|
||||
from importlib import import_module
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import six
|
||||
from ccx_keys.locator import CCXBlockUsageLocator
|
||||
@@ -589,25 +590,25 @@ class TestHasChildrenAtDepth(SplitModuleTest):
|
||||
self.assertRaises(
|
||||
ValueError, block.has_children_at_depth, -1,
|
||||
)
|
||||
self.assertTrue(block.has_children_at_depth(0))
|
||||
self.assertTrue(block.has_children_at_depth(1))
|
||||
self.assertFalse(block.has_children_at_depth(2))
|
||||
assert block.has_children_at_depth(0)
|
||||
assert block.has_children_at_depth(1)
|
||||
assert not block.has_children_at_depth(2)
|
||||
|
||||
ch1 = modulestore().get_item(
|
||||
BlockUsageLocator(course_locator, 'chapter', block_id='chapter1')
|
||||
)
|
||||
self.assertFalse(ch1.has_children_at_depth(0))
|
||||
assert not ch1.has_children_at_depth(0)
|
||||
|
||||
ch2 = modulestore().get_item(
|
||||
BlockUsageLocator(course_locator, 'chapter', block_id='chapter2')
|
||||
)
|
||||
self.assertFalse(ch2.has_children_at_depth(0))
|
||||
assert not ch2.has_children_at_depth(0)
|
||||
|
||||
ch3 = modulestore().get_item(
|
||||
BlockUsageLocator(course_locator, 'chapter', block_id='chapter3')
|
||||
)
|
||||
self.assertTrue(ch3.has_children_at_depth(0))
|
||||
self.assertFalse(ch3.has_children_at_depth(1))
|
||||
assert ch3.has_children_at_depth(0)
|
||||
assert not ch3.has_children_at_depth(1)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -620,23 +621,17 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
def test_get_courses(self, _from_json):
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT)
|
||||
# should have gotten 3 draft courses
|
||||
self.assertEqual(len(courses), 3, "Wrong number of courses")
|
||||
assert len(courses) == 3, 'Wrong number of courses'
|
||||
# check metadata -- NOTE no promised order
|
||||
course = self.findByIdInResult(courses, "head12345")
|
||||
self.assertEqual(course.location.org, "testx")
|
||||
self.assertEqual(course.category, 'course', 'wrong category')
|
||||
self.assertEqual(len(course.tabs), 6, "wrong number of tabs")
|
||||
self.assertEqual(
|
||||
course.display_name, "The Ancient Greek Hero",
|
||||
"wrong display name"
|
||||
)
|
||||
self.assertEqual(
|
||||
course.advertised_start, "Fall 2013",
|
||||
"advertised_start"
|
||||
)
|
||||
self.assertEqual(len(course.children), 4, "children")
|
||||
assert course.location.org == 'testx'
|
||||
assert course.category == 'course', 'wrong category'
|
||||
assert len(course.tabs) == 6, 'wrong number of tabs'
|
||||
assert course.display_name == 'The Ancient Greek Hero', 'wrong display name'
|
||||
assert course.advertised_start == 'Fall 2013', 'advertised_start'
|
||||
assert len(course.children) == 4, 'children'
|
||||
# check dates and graders--forces loading of descriptor
|
||||
self.assertEqual(course.edited_by, "testassist@edx.org")
|
||||
assert course.edited_by == 'testassist@edx.org'
|
||||
self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.45})
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
@@ -647,7 +642,7 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
"""
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT)
|
||||
# Should have gotten 3 draft courses.
|
||||
self.assertEqual(len(courses), 3)
|
||||
assert len(courses) == 3
|
||||
|
||||
course_index = modulestore().get_course_index_info(courses[0].id)
|
||||
# Creating a new course with same course index of another course.
|
||||
@@ -656,44 +651,42 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
)
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT)
|
||||
# Should have gotten 4 draft courses.
|
||||
self.assertEqual(len(courses), 4)
|
||||
self.assertIn(new_draft_course.id.version_agnostic(), [c.id for c in courses])
|
||||
assert len(courses) == 4
|
||||
assert new_draft_course.id.version_agnostic() in [c.id for c in courses]
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
def test_get_org_courses(self, _from_json):
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT, org='guestx')
|
||||
|
||||
# should have gotten 1 draft courses
|
||||
self.assertEqual(len(courses), 1)
|
||||
assert len(courses) == 1
|
||||
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT, org='testx')
|
||||
|
||||
# should have gotten 2 draft courses
|
||||
self.assertEqual(len(courses), 2)
|
||||
assert len(courses) == 2
|
||||
|
||||
# although this is already covered in other tests, let's
|
||||
# also not pass in org= parameter to make sure we get back
|
||||
# 3 courses
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT)
|
||||
self.assertEqual(len(courses), 3)
|
||||
assert len(courses) == 3
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
def test_branch_requests(self, _from_json):
|
||||
# query w/ branch qualifier (both draft and published)
|
||||
def _verify_published_course(courses_published):
|
||||
""" Helper function for verifying published course. """
|
||||
self.assertEqual(len(courses_published), 1, len(courses_published))
|
||||
assert len(courses_published) == 1, len(courses_published)
|
||||
course = self.findByIdInResult(courses_published, "head23456")
|
||||
self.assertIsNotNone(course, "published courses")
|
||||
self.assertEqual(course.location.course_key.org, "testx")
|
||||
self.assertEqual(course.location.course_key.course, "wonderful")
|
||||
self.assertEqual(course.category, 'course', 'wrong category')
|
||||
self.assertEqual(len(course.tabs), 4, "wrong number of tabs")
|
||||
self.assertEqual(course.display_name, "The most wonderful course",
|
||||
course.display_name)
|
||||
self.assertIsNone(course.advertised_start)
|
||||
self.assertEqual(len(course.children), 0,
|
||||
"children")
|
||||
assert course is not None, 'published courses'
|
||||
assert course.location.course_key.org == 'testx'
|
||||
assert course.location.course_key.course == 'wonderful'
|
||||
assert course.category == 'course', 'wrong category'
|
||||
assert len(course.tabs) == 4, 'wrong number of tabs'
|
||||
assert course.display_name == 'The most wonderful course', course.display_name
|
||||
assert course.advertised_start is None
|
||||
assert len(course.children) == 0, 'children'
|
||||
|
||||
_verify_published_course(modulestore().get_courses(branch=BRANCH_NAME_PUBLISHED))
|
||||
|
||||
@@ -715,34 +708,34 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
'''
|
||||
locator = CourseLocator(org='testx', course='GreekHero', run="run", branch=BRANCH_NAME_DRAFT)
|
||||
head_course = modulestore().get_course(locator)
|
||||
self.assertNotEqual(head_course.location.version_guid, head_course.previous_version)
|
||||
assert head_course.location.version_guid != head_course.previous_version
|
||||
locator = CourseLocator(version_guid=head_course.previous_version)
|
||||
course = modulestore().get_course(locator)
|
||||
self.assertIsNone(course.location.course_key.org)
|
||||
self.assertEqual(course.location.version_guid, head_course.previous_version)
|
||||
self.assertEqual(course.category, 'course')
|
||||
self.assertEqual(len(course.tabs), 6)
|
||||
self.assertEqual(course.display_name, "The Ancient Greek Hero")
|
||||
self.assertEqual(course.graceperiod, datetime.timedelta(hours=2))
|
||||
self.assertIsNone(course.advertised_start)
|
||||
self.assertEqual(len(course.children), 0)
|
||||
self.assertNotEqual(course.definition_locator.definition_id, head_course.definition_locator.definition_id)
|
||||
assert course.location.course_key.org is None
|
||||
assert course.location.version_guid == head_course.previous_version
|
||||
assert course.category == 'course'
|
||||
assert len(course.tabs) == 6
|
||||
assert course.display_name == 'The Ancient Greek Hero'
|
||||
assert course.graceperiod == datetime.timedelta(hours=2)
|
||||
assert course.advertised_start is None
|
||||
assert len(course.children) == 0
|
||||
assert course.definition_locator.definition_id != head_course.definition_locator.definition_id
|
||||
# check dates and graders--forces loading of descriptor
|
||||
self.assertEqual(course.edited_by, "testassist@edx.org")
|
||||
assert course.edited_by == 'testassist@edx.org'
|
||||
self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.55})
|
||||
|
||||
locator = CourseLocator(org='testx', course='GreekHero', run="run", branch=BRANCH_NAME_DRAFT)
|
||||
course = modulestore().get_course(locator)
|
||||
self.assertEqual(course.location.course_key.org, "testx")
|
||||
self.assertEqual(course.location.course_key.course, "GreekHero")
|
||||
self.assertEqual(course.location.course_key.run, "run")
|
||||
self.assertEqual(course.category, 'course')
|
||||
self.assertEqual(len(course.tabs), 6)
|
||||
self.assertEqual(course.display_name, "The Ancient Greek Hero")
|
||||
self.assertEqual(course.advertised_start, "Fall 2013")
|
||||
self.assertEqual(len(course.children), 4)
|
||||
assert course.location.course_key.org == 'testx'
|
||||
assert course.location.course_key.course == 'GreekHero'
|
||||
assert course.location.course_key.run == 'run'
|
||||
assert course.category == 'course'
|
||||
assert len(course.tabs) == 6
|
||||
assert course.display_name == 'The Ancient Greek Hero'
|
||||
assert course.advertised_start == 'Fall 2013'
|
||||
assert len(course.children) == 4
|
||||
# check dates and graders--forces loading of descriptor
|
||||
self.assertEqual(course.edited_by, "testassist@edx.org")
|
||||
assert course.edited_by == 'testassist@edx.org'
|
||||
self.assertDictEqual(course.grade_cutoffs, {"Pass": 0.45})
|
||||
|
||||
locator = CourseLocator(org='testx', course='wonderful', run="run", branch=BRANCH_NAME_PUBLISHED)
|
||||
@@ -751,15 +744,15 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
|
||||
locator = CourseLocator(org='testx', course='wonderful', run="run", branch=BRANCH_NAME_DRAFT)
|
||||
course = modulestore().get_course(locator)
|
||||
self.assertNotEqual(course.location.version_guid, published_version)
|
||||
assert course.location.version_guid != published_version
|
||||
|
||||
def test_get_course_negative(self):
|
||||
# Now negative testing
|
||||
with self.assertRaises(InsufficientSpecificationError):
|
||||
with pytest.raises(InsufficientSpecificationError):
|
||||
modulestore().get_course(CourseLocator(org='edu', course='meh', run='blah'))
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().get_course(CourseLocator(org='edu', course='nosuchthing', run="run", branch=BRANCH_NAME_DRAFT)) # lint-amnesty, pylint: disable=line-too-long
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().get_course(CourseLocator(org='testx', course='GreekHero', run="run", branch=BRANCH_NAME_PUBLISHED)) # lint-amnesty, pylint: disable=line-too-long
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
@@ -772,8 +765,8 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
block_map = modulestore().cache_items(
|
||||
course.system, [BlockKey.from_usage_key(child) for child in course.children], course.id, depth=3
|
||||
)
|
||||
self.assertIn(BlockKey('chapter', 'chapter1'), block_map)
|
||||
self.assertIn(BlockKey('problem', 'problem3_2'), block_map)
|
||||
assert BlockKey('chapter', 'chapter1') in block_map
|
||||
assert BlockKey('problem', 'problem3_2') in block_map
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
def test_course_successors(self, _from_json):
|
||||
@@ -789,23 +782,23 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
|
||||
locator = CourseLocator(version_guid=course.previous_version)
|
||||
result = modulestore().get_course_successors(locator)
|
||||
self.assertIsInstance(result, VersionTree)
|
||||
self.assertIsNone(result.locator.org)
|
||||
self.assertEqual(result.locator.version_guid, versions[-1])
|
||||
self.assertEqual(len(result.children), 1)
|
||||
self.assertEqual(result.children[0].locator.version_guid, versions[-2])
|
||||
self.assertEqual(len(result.children[0].children), 0, "descended more than one level")
|
||||
assert isinstance(result, VersionTree)
|
||||
assert result.locator.org is None
|
||||
assert result.locator.version_guid == versions[(- 1)]
|
||||
assert len(result.children) == 1
|
||||
assert result.children[0].locator.version_guid == versions[(- 2)]
|
||||
assert len(result.children[0].children) == 0, 'descended more than one level'
|
||||
|
||||
result = modulestore().get_course_successors(locator, version_history_depth=2)
|
||||
self.assertEqual(len(result.children), 1)
|
||||
self.assertEqual(result.children[0].locator.version_guid, versions[-2])
|
||||
self.assertEqual(len(result.children[0].children), 1)
|
||||
assert len(result.children) == 1
|
||||
assert result.children[0].locator.version_guid == versions[(- 2)]
|
||||
assert len(result.children[0].children) == 1
|
||||
|
||||
result = modulestore().get_course_successors(locator, version_history_depth=99)
|
||||
self.assertEqual(len(result.children), 1)
|
||||
self.assertEqual(result.children[0].locator.version_guid, versions[-2])
|
||||
self.assertEqual(len(result.children[0].children), 1)
|
||||
self.assertEqual(result.children[0].children[0].locator.version_guid, versions[0])
|
||||
assert len(result.children) == 1
|
||||
assert result.children[0].locator.version_guid == versions[(- 2)]
|
||||
assert len(result.children[0].children) == 1
|
||||
assert result.children[0].children[0].locator.version_guid == versions[0]
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
def test_persist_dag(self, _from_json):
|
||||
@@ -821,7 +814,7 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
test_course.system, test_course.id, 'chapter', fields={'display_name': 'chapter n'},
|
||||
parent_xblock=test_course
|
||||
)
|
||||
self.assertEqual(test_chapter.display_name, 'chapter n')
|
||||
assert test_chapter.display_name == 'chapter n'
|
||||
test_def_content = '<problem>boo</problem>'
|
||||
# create child
|
||||
new_block = modulestore().create_xblock(
|
||||
@@ -833,24 +826,24 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
},
|
||||
parent_xblock=test_chapter
|
||||
)
|
||||
self.assertIsNotNone(new_block.definition_locator)
|
||||
self.assertTrue(isinstance(new_block.definition_locator.definition_id, LocalId))
|
||||
assert new_block.definition_locator is not None
|
||||
assert isinstance(new_block.definition_locator.definition_id, LocalId)
|
||||
# better to pass in persisted parent over the subdag so
|
||||
# subdag gets the parent pointer (otherwise 2 ops, persist dag, update parent children,
|
||||
# persist parent
|
||||
persisted_course = modulestore().persist_xblock_dag(test_course, 'testbot')
|
||||
self.assertEqual(len(persisted_course.children), 1)
|
||||
assert len(persisted_course.children) == 1
|
||||
persisted_chapter = persisted_course.get_children()[0]
|
||||
self.assertEqual(persisted_chapter.category, 'chapter')
|
||||
self.assertEqual(persisted_chapter.display_name, 'chapter n')
|
||||
self.assertEqual(len(persisted_chapter.children), 1)
|
||||
assert persisted_chapter.category == 'chapter'
|
||||
assert persisted_chapter.display_name == 'chapter n'
|
||||
assert len(persisted_chapter.children) == 1
|
||||
persisted_problem = persisted_chapter.get_children()[0]
|
||||
self.assertEqual(persisted_problem.category, 'problem')
|
||||
self.assertEqual(persisted_problem.data, test_def_content)
|
||||
assert persisted_problem.category == 'problem'
|
||||
assert persisted_problem.data == test_def_content
|
||||
# update it
|
||||
persisted_problem.display_name = 'altered problem'
|
||||
persisted_problem = modulestore().update_item(persisted_problem, 'testbot')
|
||||
self.assertEqual(persisted_problem.display_name, 'altered problem')
|
||||
assert persisted_problem.display_name == 'altered problem'
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
def test_block_generations(self, _from_json):
|
||||
@@ -886,9 +879,9 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
first_problem.max_attempts = 3
|
||||
first_problem.save() # decache the above into the kvs
|
||||
updated_problem = modulestore().update_item(first_problem, 'testbot')
|
||||
self.assertIsNotNone(updated_problem.previous_version)
|
||||
self.assertEqual(updated_problem.previous_version, first_problem.update_version)
|
||||
self.assertNotEqual(updated_problem.update_version, first_problem.update_version)
|
||||
assert updated_problem.previous_version is not None
|
||||
assert updated_problem.previous_version == first_problem.update_version
|
||||
assert updated_problem.update_version != first_problem.update_version
|
||||
modulestore().delete_item(updated_problem.location, 'testbot')
|
||||
|
||||
second_problem = modulestore().create_child(
|
||||
@@ -901,27 +894,28 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
# The draft course root has 2 revisions: the published revision, and then the subsequent
|
||||
# changes to the draft revision
|
||||
version_history = modulestore().get_block_generations(test_course.location)
|
||||
self.assertIsNotNone(version_history)
|
||||
self.assertEqual(version_history.locator.version_guid, test_course.location.version_guid)
|
||||
self.assertEqual(len(version_history.children), 1)
|
||||
self.assertEqual(version_history.children[0].children, [])
|
||||
self.assertEqual(version_history.children[0].locator.version_guid, chapter.location.version_guid)
|
||||
assert version_history is not None
|
||||
assert version_history.locator.version_guid == test_course.location.version_guid
|
||||
assert len(version_history.children) == 1
|
||||
assert version_history.children[0].children == []
|
||||
assert version_history.children[0].locator.version_guid == chapter.location.version_guid
|
||||
|
||||
# sub changed on add, add problem, delete problem, add problem in strict linear seq
|
||||
version_history = modulestore().get_block_generations(sub.location)
|
||||
self.assertEqual(len(version_history.children), 1)
|
||||
self.assertEqual(len(version_history.children[0].children), 1)
|
||||
self.assertEqual(len(version_history.children[0].children[0].children), 1)
|
||||
self.assertEqual(len(version_history.children[0].children[0].children[0].children), 0)
|
||||
assert len(version_history.children) == 1
|
||||
assert len(version_history.children[0].children) == 1
|
||||
assert len(version_history.children[0].children[0].children) == 1
|
||||
assert len(version_history.children[0].children[0].children[0].children) == 0
|
||||
|
||||
# first and second problem may show as same usage_id; so, need to ensure their histories are right
|
||||
version_history = modulestore().get_block_generations(updated_problem.location)
|
||||
self.assertEqual(version_history.locator.version_guid, first_problem.location.version_guid)
|
||||
self.assertEqual(len(version_history.children), 1) # updated max_attempts
|
||||
self.assertEqual(len(version_history.children[0].children), 0)
|
||||
assert version_history.locator.version_guid == first_problem.location.version_guid
|
||||
assert len(version_history.children) == 1
|
||||
# updated max_attempts
|
||||
assert len(version_history.children[0].children) == 0
|
||||
|
||||
version_history = modulestore().get_block_generations(second_problem.location)
|
||||
self.assertNotEqual(version_history.locator.version_guid, first_problem.location.version_guid)
|
||||
assert version_history.locator.version_guid != first_problem.location.version_guid
|
||||
|
||||
@ddt.data(
|
||||
("course-v1:edx+test_course+test_run", BlockUsageLocator),
|
||||
@@ -935,9 +929,9 @@ class SplitModuleCourseTests(SplitModuleTest):
|
||||
"""
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
root_block_key = modulestore().make_course_usage_key(course_key)
|
||||
self.assertIsInstance(root_block_key, root_block_cls)
|
||||
self.assertEqual(root_block_key.block_type, "course")
|
||||
self.assertEqual(root_block_key.block_id, "course")
|
||||
assert isinstance(root_block_key, root_block_cls)
|
||||
assert root_block_key.block_type == 'course'
|
||||
assert root_block_key.block_id == 'course'
|
||||
|
||||
|
||||
class TestCourseStructureCache(SplitModuleTest):
|
||||
@@ -975,7 +969,7 @@ class TestCourseStructureCache(SplitModuleTest):
|
||||
cached_structure = self._get_structure(self.new_course)
|
||||
|
||||
# now make sure that you get the same structure
|
||||
self.assertEqual(cached_structure, not_cached_structure)
|
||||
assert cached_structure == not_cached_structure
|
||||
|
||||
# If data is corrupted, get it from mongo again.
|
||||
cache_key = self.new_course.id.version_guid
|
||||
@@ -984,7 +978,7 @@ class TestCourseStructureCache(SplitModuleTest):
|
||||
not_corrupt_structure = self._get_structure(self.new_course)
|
||||
|
||||
# now make sure that you get the same structure
|
||||
self.assertEqual(not_corrupt_structure, not_cached_structure)
|
||||
assert not_corrupt_structure == not_cached_structure
|
||||
|
||||
@patch('xmodule.modulestore.split_mongo.mongo_connection.get_cache')
|
||||
def test_course_structure_cache_no_cache_configured(self, mock_get_cache):
|
||||
@@ -999,7 +993,7 @@ class TestCourseStructureCache(SplitModuleTest):
|
||||
cached_structure = self._get_structure(self.new_course)
|
||||
|
||||
# now make sure that you get the same structure
|
||||
self.assertEqual(cached_structure, not_cached_structure)
|
||||
assert cached_structure == not_cached_structure
|
||||
|
||||
def test_dummy_cache(self):
|
||||
with check_mongo_calls(1):
|
||||
@@ -1011,7 +1005,7 @@ class TestCourseStructureCache(SplitModuleTest):
|
||||
cached_structure = self._get_structure(self.new_course)
|
||||
|
||||
# now make sure that you get the same structure
|
||||
self.assertEqual(cached_structure, not_cached_structure)
|
||||
assert cached_structure == not_cached_structure
|
||||
|
||||
def _get_structure(self, course):
|
||||
"""
|
||||
@@ -1040,31 +1034,18 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
previous_version = course.previous_version
|
||||
# positive tests of various forms
|
||||
locator = course.location.map_into_course(CourseLocator(version_guid=previous_version))
|
||||
self.assertTrue(
|
||||
modulestore().has_item(locator), "couldn't find in %s" % previous_version
|
||||
)
|
||||
assert modulestore().has_item(locator), ("couldn't find in %s" % previous_version)
|
||||
|
||||
locator = course.location.version_agnostic()
|
||||
self.assertTrue(
|
||||
modulestore().has_item(locator),
|
||||
)
|
||||
self.assertFalse(
|
||||
modulestore().has_item(
|
||||
BlockUsageLocator(
|
||||
locator.course_key.for_branch(BRANCH_NAME_PUBLISHED),
|
||||
block_type=locator.block_type,
|
||||
block_id=locator.block_id
|
||||
)
|
||||
),
|
||||
"found in published head"
|
||||
)
|
||||
assert modulestore().has_item(locator)
|
||||
assert not modulestore()\
|
||||
.has_item(BlockUsageLocator(locator.course_key.for_branch(BRANCH_NAME_PUBLISHED),
|
||||
block_type=locator.block_type,
|
||||
block_id=locator.block_id)), 'found in published head'
|
||||
|
||||
# not a course obj
|
||||
locator = BlockUsageLocator(course_locator, block_type='chapter', block_id='chapter1')
|
||||
self.assertTrue(
|
||||
modulestore().has_item(locator),
|
||||
"couldn't find chapter1"
|
||||
)
|
||||
assert modulestore().has_item(locator), "couldn't find chapter1"
|
||||
|
||||
# in published course
|
||||
locator = BlockUsageLocator(
|
||||
@@ -1072,9 +1053,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
block_type="course",
|
||||
block_id="head23456"
|
||||
)
|
||||
self.assertTrue(
|
||||
modulestore().has_item(locator.for_branch(BRANCH_NAME_PUBLISHED))
|
||||
)
|
||||
assert modulestore().has_item(locator.for_branch(BRANCH_NAME_PUBLISHED))
|
||||
|
||||
def test_negative_has_item(self):
|
||||
# negative tests--not found
|
||||
@@ -1084,13 +1063,13 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
block_type="course",
|
||||
block_id="head23456"
|
||||
)
|
||||
self.assertFalse(modulestore().has_item(locator))
|
||||
assert not modulestore().has_item(locator)
|
||||
locator = BlockUsageLocator(
|
||||
CourseLocator(org="testx", course="wonderful", run="run", branch=BRANCH_NAME_DRAFT),
|
||||
block_type="vertical",
|
||||
block_id="doesnotexist"
|
||||
)
|
||||
self.assertFalse(modulestore().has_item(locator))
|
||||
assert not modulestore().has_item(locator)
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
def test_get_item(self, _from_json):
|
||||
@@ -1104,22 +1083,22 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
# positive tests of various forms
|
||||
locator = course.location.map_into_course(CourseLocator(version_guid=previous_version))
|
||||
block = modulestore().get_item(locator)
|
||||
self.assertIsInstance(block, CourseDescriptor)
|
||||
self.assertIsInstance(modulestore().get_item(locator), CourseDescriptor)
|
||||
assert isinstance(block, CourseDescriptor)
|
||||
assert isinstance(modulestore().get_item(locator), CourseDescriptor)
|
||||
|
||||
def verify_greek_hero(block):
|
||||
"""
|
||||
Check contents of block
|
||||
"""
|
||||
self.assertEqual(block.location.org, "testx")
|
||||
self.assertEqual(block.location.course, "GreekHero")
|
||||
self.assertEqual(block.location.run, "run")
|
||||
self.assertEqual(len(block.tabs), 6, "wrong number of tabs")
|
||||
self.assertEqual(block.display_name, "The Ancient Greek Hero")
|
||||
self.assertEqual(block.advertised_start, "Fall 2013")
|
||||
self.assertEqual(len(block.children), 4)
|
||||
assert block.location.org == 'testx'
|
||||
assert block.location.course == 'GreekHero'
|
||||
assert block.location.run == 'run'
|
||||
assert len(block.tabs) == 6, 'wrong number of tabs'
|
||||
assert block.display_name == 'The Ancient Greek Hero'
|
||||
assert block.advertised_start == 'Fall 2013'
|
||||
assert len(block.children) == 4
|
||||
# check dates and graders--forces loading of descriptor
|
||||
self.assertEqual(block.edited_by, "testassist@edx.org")
|
||||
assert block.edited_by == 'testassist@edx.org'
|
||||
self.assertDictEqual(
|
||||
block.grade_cutoffs, {"Pass": 0.45},
|
||||
)
|
||||
@@ -1127,7 +1106,7 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
verify_greek_hero(modulestore().get_item(course.location))
|
||||
|
||||
# try to look up other branches
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().get_item(course.location.for_branch(BRANCH_NAME_PUBLISHED))
|
||||
|
||||
def test_get_non_root(self):
|
||||
@@ -1136,32 +1115,29 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
CourseLocator(org='testx', course='GreekHero', run="run", branch=BRANCH_NAME_DRAFT), 'chapter', 'chapter1'
|
||||
)
|
||||
block = modulestore().get_item(locator)
|
||||
self.assertEqual(block.location.org, "testx")
|
||||
self.assertEqual(block.location.course, "GreekHero")
|
||||
self.assertEqual(block.category, 'chapter')
|
||||
self.assertEqual(block.display_name, "Hercules")
|
||||
self.assertEqual(block.edited_by, "testassist@edx.org")
|
||||
assert block.location.org == 'testx'
|
||||
assert block.location.course == 'GreekHero'
|
||||
assert block.category == 'chapter'
|
||||
assert block.display_name == 'Hercules'
|
||||
assert block.edited_by == 'testassist@edx.org'
|
||||
|
||||
# in published course
|
||||
locator = BlockUsageLocator(
|
||||
CourseLocator(org='testx', course='wonderful', run="run", branch=BRANCH_NAME_PUBLISHED), 'course', 'head23456' # lint-amnesty, pylint: disable=line-too-long
|
||||
)
|
||||
self.assertIsInstance(
|
||||
modulestore().get_item(locator),
|
||||
CourseDescriptor
|
||||
)
|
||||
assert isinstance(modulestore().get_item(locator), CourseDescriptor)
|
||||
|
||||
# negative tests--not found
|
||||
# no such course or block
|
||||
locator = BlockUsageLocator(
|
||||
CourseLocator(org='doesnotexist', course='doesnotexist', run="run", branch=BRANCH_NAME_DRAFT), 'course', 'head23456' # lint-amnesty, pylint: disable=line-too-long
|
||||
)
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().get_item(locator)
|
||||
locator = BlockUsageLocator(
|
||||
CourseLocator(org='testx', course='wonderful', run="run", branch=BRANCH_NAME_DRAFT), 'html', 'doesnotexist'
|
||||
)
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().get_item(locator)
|
||||
|
||||
# pylint: disable=protected-access
|
||||
@@ -1169,41 +1145,37 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
'''
|
||||
test the block and value matches help functions
|
||||
'''
|
||||
self.assertTrue(modulestore()._value_matches('help', 'help'))
|
||||
self.assertFalse(modulestore()._value_matches('help', 'Help'))
|
||||
self.assertTrue(modulestore()._value_matches(['distract', 'help', 'notme'], 'help'))
|
||||
self.assertFalse(modulestore()._value_matches(['distract', 'Help', 'notme'], 'help'))
|
||||
self.assertFalse(modulestore()._block_matches({'field': ['distract', 'Help', 'notme']}, {'field': 'help'}))
|
||||
self.assertTrue(modulestore()._block_matches(
|
||||
{'field': ['distract', 'help', 'notme'],
|
||||
'irrelevant': 2},
|
||||
{'field': 'help'}))
|
||||
self.assertTrue(modulestore()._value_matches('I need some help', re.compile(r'help')))
|
||||
self.assertTrue(modulestore()._value_matches(['I need some help', 'today'], re.compile(r'help')))
|
||||
self.assertFalse(modulestore()._value_matches('I need some help', re.compile(r'Help')))
|
||||
self.assertTrue(modulestore()._value_matches(['I need some help', 'today'], re.compile(r'Help', re.IGNORECASE)))
|
||||
assert modulestore()._value_matches('help', 'help')
|
||||
assert not modulestore()._value_matches('help', 'Help')
|
||||
assert modulestore()._value_matches(['distract', 'help', 'notme'], 'help')
|
||||
assert not modulestore()._value_matches(['distract', 'Help', 'notme'], 'help')
|
||||
assert not modulestore()._block_matches({'field': ['distract', 'Help', 'notme']}, {'field': 'help'})
|
||||
assert modulestore()._block_matches({'field': ['distract', 'help', 'notme'], 'irrelevant': 2},
|
||||
{'field': 'help'})
|
||||
assert modulestore()._value_matches('I need some help', re.compile('help'))
|
||||
assert modulestore()._value_matches(['I need some help', 'today'], re.compile('help'))
|
||||
assert not modulestore()._value_matches('I need some help', re.compile('Help'))
|
||||
assert modulestore()._value_matches(['I need some help', 'today'], re.compile('Help', re.IGNORECASE))
|
||||
|
||||
self.assertTrue(modulestore()._value_matches('gotcha', {'$in': ['a', 'bunch', 'of', 'gotcha']}))
|
||||
self.assertFalse(modulestore()._value_matches('gotcha', {'$in': ['a', 'bunch', 'of', 'gotchas']}))
|
||||
self.assertFalse(modulestore()._value_matches('gotcha', {'$nin': ['a', 'bunch', 'of', 'gotcha']}))
|
||||
self.assertTrue(modulestore()._value_matches('gotcha', {'$nin': ['a', 'bunch', 'of', 'gotchas']}))
|
||||
assert modulestore()._value_matches('gotcha', {'$in': ['a', 'bunch', 'of', 'gotcha']})
|
||||
assert not modulestore()._value_matches('gotcha', {'$in': ['a', 'bunch', 'of', 'gotchas']})
|
||||
assert not modulestore()._value_matches('gotcha', {'$nin': ['a', 'bunch', 'of', 'gotcha']})
|
||||
assert modulestore()._value_matches('gotcha', {'$nin': ['a', 'bunch', 'of', 'gotchas']})
|
||||
|
||||
self.assertTrue(modulestore()._block_matches({'group_access': {'1': [1]}}, {'group_access': {'$exists': True}}))
|
||||
self.assertTrue(modulestore()._block_matches({'a': 1, 'b': 2}, {'group_access': {'$exists': False}}))
|
||||
self.assertTrue(modulestore()._block_matches(
|
||||
{'a': 1, 'group_access': {'1': [1]}},
|
||||
{'a': 1, 'group_access': {'$exists': True}}))
|
||||
self.assertFalse(modulestore()._block_matches(
|
||||
{'a': 1, 'group_access': {'1': [1]}},
|
||||
{'a': 111, 'group_access': {'$exists': True}}))
|
||||
self.assertTrue(modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 1, 'group_access': {'$exists': False}}))
|
||||
self.assertFalse(modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 9, 'group_access': {'$exists': False}}))
|
||||
assert modulestore()._block_matches({'group_access': {'1': [1]}}, {'group_access': {'$exists': True}})
|
||||
assert modulestore()._block_matches({'a': 1, 'b': 2}, {'group_access': {'$exists': False}})
|
||||
assert modulestore()._block_matches({'a': 1, 'group_access': {'1': [1]}},
|
||||
{'a': 1, 'group_access': {'$exists': True}})
|
||||
assert not modulestore()._block_matches({'a': 1, 'group_access': {'1': [1]}},
|
||||
{'a': 111, 'group_access': {'$exists': True}})
|
||||
assert modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 1, 'group_access': {'$exists': False}})
|
||||
assert not modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 9, 'group_access': {'$exists': False}})
|
||||
|
||||
self.assertTrue(modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 1}))
|
||||
self.assertFalse(modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 2}))
|
||||
self.assertFalse(modulestore()._block_matches({'a': 1, 'b': 2}, {'c': 1}))
|
||||
self.assertFalse(modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 1, 'c': 1}))
|
||||
self.assertTrue(modulestore()._block_matches({'a': 1, 'b': 2}, {'a': lambda i: 0 < i < 2}))
|
||||
assert modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 1})
|
||||
assert not modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 2})
|
||||
assert not modulestore()._block_matches({'a': 1, 'b': 2}, {'c': 1})
|
||||
assert not modulestore()._block_matches({'a': 1, 'b': 2}, {'a': 1, 'c': 1})
|
||||
assert modulestore()._block_matches({'a': 1, 'b': 2}, {'a': (lambda i: (0 < i < 2))})
|
||||
|
||||
def test_get_items(self):
|
||||
'''
|
||||
@@ -1212,28 +1184,28 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
locator = CourseLocator(org='testx', course='GreekHero', run="run", branch=BRANCH_NAME_DRAFT)
|
||||
# get all modules
|
||||
matches = modulestore().get_items(locator)
|
||||
self.assertEqual(len(matches), 8)
|
||||
assert len(matches) == 8
|
||||
matches = modulestore().get_items(locator)
|
||||
self.assertEqual(len(matches), 8)
|
||||
assert len(matches) == 8
|
||||
matches = modulestore().get_items(locator, qualifiers={'category': 'chapter'})
|
||||
self.assertEqual(len(matches), 4)
|
||||
assert len(matches) == 4
|
||||
matches = modulestore().get_items(locator, qualifiers={'category': 'garbage'})
|
||||
self.assertEqual(len(matches), 0)
|
||||
assert len(matches) == 0
|
||||
# Test that we don't accidentally get an item with a similar name.
|
||||
matches = modulestore().get_items(locator, qualifiers={'name': 'chapter1'})
|
||||
self.assertEqual(len(matches), 1)
|
||||
assert len(matches) == 1
|
||||
matches = modulestore().get_items(locator, qualifiers={'name': ['chapter1', 'chapter2']})
|
||||
self.assertEqual(len(matches), 2)
|
||||
assert len(matches) == 2
|
||||
matches = modulestore().get_items(
|
||||
locator,
|
||||
qualifiers={'category': 'chapter'},
|
||||
settings={'display_name': re.compile(r'Hera')},
|
||||
)
|
||||
self.assertEqual(len(matches), 2)
|
||||
assert len(matches) == 2
|
||||
matches = modulestore().get_items(locator, settings={'group_access': {'$exists': True}})
|
||||
self.assertEqual(len(matches), 1)
|
||||
assert len(matches) == 1
|
||||
matches = modulestore().get_items(locator, settings={'group_access': {'$exists': False}})
|
||||
self.assertEqual(len(matches), 7)
|
||||
assert len(matches) == 7
|
||||
|
||||
def test_get_parents(self):
|
||||
'''
|
||||
@@ -1244,17 +1216,17 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
'chapter', block_id='chapter1'
|
||||
)
|
||||
parent = modulestore().get_parent_location(locator)
|
||||
self.assertIsNotNone(parent)
|
||||
self.assertEqual(parent.block_id, 'head12345')
|
||||
self.assertEqual(parent.org, "testx")
|
||||
self.assertEqual(parent.course, "GreekHero")
|
||||
assert parent is not None
|
||||
assert parent.block_id == 'head12345'
|
||||
assert parent.org == 'testx'
|
||||
assert parent.course == 'GreekHero'
|
||||
locator = locator.course_key.make_usage_key('chapter', 'chapter2')
|
||||
parent = modulestore().get_parent_location(locator)
|
||||
self.assertIsNotNone(parent)
|
||||
self.assertEqual(parent.block_id, 'head12345')
|
||||
assert parent is not None
|
||||
assert parent.block_id == 'head12345'
|
||||
locator = locator.course_key.make_usage_key('garbage', 'nosuchblock')
|
||||
parent = modulestore().get_parent_location(locator)
|
||||
self.assertIsNone(parent)
|
||||
assert parent is None
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
def test_get_children(self, _from_json):
|
||||
@@ -1270,10 +1242,10 @@ class SplitModuleItemTests(SplitModuleTest):
|
||||
"chapter1", "chap", "chapter2", "chapter3"
|
||||
]
|
||||
for child in children:
|
||||
self.assertEqual(child.category, "chapter")
|
||||
self.assertIn(child.location.block_id, expected_ids)
|
||||
assert child.category == 'chapter'
|
||||
assert child.location.block_id in expected_ids
|
||||
expected_ids.remove(child.location.block_id)
|
||||
self.assertEqual(len(expected_ids), 0)
|
||||
assert len(expected_ids) == 0
|
||||
|
||||
|
||||
def version_agnostic(children):
|
||||
@@ -1323,25 +1295,26 @@ class TestItemCrud(SplitModuleTest):
|
||||
fields={'display_name': 'new sequential'}
|
||||
)
|
||||
# check that course version changed and course's previous is the other one
|
||||
self.assertEqual(new_module.location.course, "GreekHero")
|
||||
self.assertNotEqual(new_module.location.version_guid, premod_course.location.version_guid)
|
||||
self.assertIsNone(locator.version_guid, "Version inadvertently filled in") # lint-amnesty, pylint: disable=no-member
|
||||
assert new_module.location.course == 'GreekHero'
|
||||
assert new_module.location.version_guid != premod_course.location.version_guid
|
||||
assert locator.version_guid is None,\
|
||||
'Version inadvertently filled in' # lint-amnesty, pylint: disable=no-member
|
||||
current_course = modulestore().get_course(locator)
|
||||
self.assertEqual(new_module.location.version_guid, current_course.location.version_guid)
|
||||
assert new_module.location.version_guid == current_course.location.version_guid
|
||||
|
||||
history_info = modulestore().get_course_history_info(current_course.location.course_key)
|
||||
self.assertEqual(history_info['previous_version'], premod_course.location.version_guid)
|
||||
self.assertEqual(history_info['original_version'], premod_history['original_version'])
|
||||
self.assertEqual(history_info['edited_by'], "user123")
|
||||
assert history_info['previous_version'] == premod_course.location.version_guid
|
||||
assert history_info['original_version'] == premod_history['original_version']
|
||||
assert history_info['edited_by'] == 'user123'
|
||||
# check block's info: category, definition_locator, and display_name
|
||||
self.assertEqual(new_module.category, 'sequential')
|
||||
self.assertIsNotNone(new_module.definition_locator)
|
||||
self.assertEqual(new_module.display_name, 'new sequential')
|
||||
assert new_module.category == 'sequential'
|
||||
assert new_module.definition_locator is not None
|
||||
assert new_module.display_name == 'new sequential'
|
||||
# check that block does not exist in previous version
|
||||
locator = new_module.location.map_into_course(
|
||||
CourseLocator(version_guid=premod_course.location.version_guid)
|
||||
)
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().get_item(locator)
|
||||
|
||||
def test_create_parented_item(self):
|
||||
@@ -1365,10 +1338,10 @@ class TestItemCrud(SplitModuleTest):
|
||||
definition_locator=original.definition_locator
|
||||
)
|
||||
# check that course version changed and course's previous is the other one
|
||||
self.assertNotEqual(new_module.location.version_guid, premod_course.location.version_guid)
|
||||
assert new_module.location.version_guid != premod_course.location.version_guid
|
||||
parent = modulestore().get_item(locator)
|
||||
self.assertIn(new_module.location.version_agnostic(), version_agnostic(parent.children))
|
||||
self.assertEqual(new_module.definition_locator.definition_id, original.definition_locator.definition_id)
|
||||
assert new_module.location.version_agnostic() in version_agnostic(parent.children)
|
||||
assert new_module.definition_locator.definition_id == original.definition_locator.definition_id
|
||||
|
||||
def test_unique_naming(self):
|
||||
"""
|
||||
@@ -1399,18 +1372,18 @@ class TestItemCrud(SplitModuleTest):
|
||||
)
|
||||
# check that course version changed and course's previous is the other one
|
||||
parent = modulestore().get_item(locator)
|
||||
self.assertNotEqual(new_module.location.block_id, another_module.location.block_id)
|
||||
self.assertIn(new_module.location.version_agnostic(), version_agnostic(parent.children))
|
||||
self.assertIn(another_module.location.version_agnostic(), version_agnostic(parent.children))
|
||||
self.assertEqual(new_module.data, new_payload)
|
||||
self.assertEqual(another_module.data, another_payload)
|
||||
assert new_module.location.block_id != another_module.location.block_id
|
||||
assert new_module.location.version_agnostic() in version_agnostic(parent.children)
|
||||
assert another_module.location.version_agnostic() in version_agnostic(parent.children)
|
||||
assert new_module.data == new_payload
|
||||
assert another_module.data == another_payload
|
||||
# check definition histories
|
||||
new_history = modulestore().get_definition_history_info(new_module.definition_locator)
|
||||
self.assertIsNone(new_history['previous_version'])
|
||||
self.assertEqual(new_history['original_version'], new_module.definition_locator.definition_id)
|
||||
self.assertEqual(new_history['edited_by'], "anotheruser")
|
||||
assert new_history['previous_version'] is None
|
||||
assert new_history['original_version'] == new_module.definition_locator.definition_id
|
||||
assert new_history['edited_by'] == 'anotheruser'
|
||||
another_history = modulestore().get_definition_history_info(another_module.definition_locator)
|
||||
self.assertEqual(another_history['previous_version'], original.definition_locator.definition_id)
|
||||
assert another_history['previous_version'] == original.definition_locator.definition_id
|
||||
|
||||
def test_encoded_naming(self):
|
||||
"""
|
||||
@@ -1426,7 +1399,8 @@ class TestItemCrud(SplitModuleTest):
|
||||
)
|
||||
# check that course version changed and course's previous is the other one
|
||||
new_module = modulestore().get_item(chapter_locator)
|
||||
self.assertEqual(new_module.location.block_id, "foo.bar_-~:0") # hardcode to ensure BUL init didn't change
|
||||
assert new_module.location.block_id == 'foo.bar_-~:0'
|
||||
# hardcode to ensure BUL init didn't change
|
||||
# now try making that a parent of something
|
||||
new_payload = "<problem>empty</problem>"
|
||||
problem_locator = BlockUsageLocator(course_key, 'problem', block_id="prob.bar_-~:99a")
|
||||
@@ -1437,9 +1411,9 @@ class TestItemCrud(SplitModuleTest):
|
||||
)
|
||||
# check that course version changed and course's previous is the other one
|
||||
new_module = modulestore().get_item(problem_locator)
|
||||
self.assertEqual(new_module.location.block_id, problem_locator.block_id)
|
||||
assert new_module.location.block_id == problem_locator.block_id
|
||||
chapter = modulestore().get_item(chapter_locator)
|
||||
self.assertIn(problem_locator, version_agnostic(chapter.children))
|
||||
assert problem_locator in version_agnostic(chapter.children)
|
||||
|
||||
def test_create_bulk_operations(self):
|
||||
"""
|
||||
@@ -1454,7 +1428,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
index_history_info = modulestore().get_course_history_info(new_course.location.course_key)
|
||||
course_block_prev_version = new_course.previous_version
|
||||
course_block_update_version = new_course.update_version
|
||||
self.assertIsNotNone(new_course_locator.version_guid, "Want to test a definite version")
|
||||
assert new_course_locator.version_guid is not None, 'Want to test a definite version'
|
||||
versionless_course_locator = new_course_locator.version_agnostic()
|
||||
|
||||
# positive simple case: no force, add chapter
|
||||
@@ -1463,18 +1437,18 @@ class TestItemCrud(SplitModuleTest):
|
||||
fields={'display_name': 'chapter 1'},
|
||||
)
|
||||
# version info shouldn't change
|
||||
self.assertEqual(new_ele.update_version, course_block_update_version)
|
||||
self.assertEqual(new_ele.update_version, new_ele.location.version_guid)
|
||||
assert new_ele.update_version == course_block_update_version
|
||||
assert new_ele.update_version == new_ele.location.version_guid
|
||||
refetch_course = modulestore().get_course(versionless_course_locator)
|
||||
self.assertEqual(refetch_course.location.version_guid, new_course.location.version_guid)
|
||||
self.assertEqual(refetch_course.previous_version, course_block_prev_version)
|
||||
self.assertEqual(refetch_course.update_version, course_block_update_version)
|
||||
assert refetch_course.location.version_guid == new_course.location.version_guid
|
||||
assert refetch_course.previous_version == course_block_prev_version
|
||||
assert refetch_course.update_version == course_block_update_version
|
||||
refetch_index_history_info = modulestore().get_course_history_info(refetch_course.location.course_key)
|
||||
self.assertEqual(refetch_index_history_info, index_history_info)
|
||||
self.assertIn(new_ele.location.version_agnostic(), version_agnostic(refetch_course.children))
|
||||
assert refetch_index_history_info == index_history_info
|
||||
assert new_ele.location.version_agnostic() in version_agnostic(refetch_course.children)
|
||||
|
||||
# try to create existing item
|
||||
with self.assertRaises(DuplicateItemError):
|
||||
with pytest.raises(DuplicateItemError):
|
||||
_fail = modulestore().create_child(
|
||||
user, new_course.location, 'chapter',
|
||||
block_id=new_ele.location.block_id,
|
||||
@@ -1489,7 +1463,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
)
|
||||
transaction_guid = new_ele.location.version_guid
|
||||
# ensure force w/ continue gives exception
|
||||
with self.assertRaises(VersionConflictError):
|
||||
with pytest.raises(VersionConflictError):
|
||||
_fail = modulestore().create_child(
|
||||
user, new_course.location, 'chapter',
|
||||
fields={'display_name': 'chapter 2'},
|
||||
@@ -1497,7 +1471,7 @@ class TestItemCrud(SplitModuleTest):
|
||||
)
|
||||
|
||||
# ensure trying to continue the old one gives exception
|
||||
with self.assertRaises(VersionConflictError):
|
||||
with pytest.raises(VersionConflictError):
|
||||
_fail = modulestore().create_child(
|
||||
user, new_course.location, 'chapter',
|
||||
fields={'display_name': 'chapter 3'},
|
||||
@@ -1509,14 +1483,14 @@ class TestItemCrud(SplitModuleTest):
|
||||
user, course_module_locator, 'chapter',
|
||||
fields={'display_name': 'chapter 4'},
|
||||
)
|
||||
self.assertNotEqual(new_ele.update_version, course_block_update_version)
|
||||
self.assertEqual(new_ele.location.version_guid, transaction_guid)
|
||||
assert new_ele.update_version != course_block_update_version
|
||||
assert new_ele.location.version_guid == transaction_guid
|
||||
|
||||
# check children, previous_version
|
||||
refetch_course = modulestore().get_course(versionless_course_locator)
|
||||
self.assertIn(new_ele.location.version_agnostic(), version_agnostic(refetch_course.children))
|
||||
self.assertEqual(refetch_course.previous_version, course_block_update_version)
|
||||
self.assertEqual(refetch_course.update_version, transaction_guid)
|
||||
assert new_ele.location.version_agnostic() in version_agnostic(refetch_course.children)
|
||||
assert refetch_course.previous_version == course_block_update_version
|
||||
assert refetch_course.update_version == transaction_guid
|
||||
|
||||
def test_bulk_ops_org_filtering(self):
|
||||
"""
|
||||
@@ -1531,23 +1505,23 @@ class TestItemCrud(SplitModuleTest):
|
||||
modulestore().create_course('test_org', 'test_transaction', 'test_run', user, BRANCH_NAME_DRAFT)
|
||||
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT, org='test_org')
|
||||
self.assertEqual(len(courses), 1)
|
||||
self.assertEqual(courses[0].id.org, course_key.org)
|
||||
self.assertEqual(courses[0].id.course, course_key.course)
|
||||
self.assertEqual(courses[0].id.run, course_key.run)
|
||||
assert len(courses) == 1
|
||||
assert courses[0].id.org == course_key.org
|
||||
assert courses[0].id.course == course_key.course
|
||||
assert courses[0].id.run == course_key.run
|
||||
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT, org='other_org')
|
||||
self.assertEqual(len(courses), 0)
|
||||
assert len(courses) == 0
|
||||
|
||||
# re-assert after the end of the with scope
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT, org='test_org')
|
||||
self.assertEqual(len(courses), 1)
|
||||
self.assertEqual(courses[0].id.org, course_key.org)
|
||||
self.assertEqual(courses[0].id.course, course_key.course)
|
||||
self.assertEqual(courses[0].id.run, course_key.run)
|
||||
assert len(courses) == 1
|
||||
assert courses[0].id.org == course_key.org
|
||||
assert courses[0].id.course == course_key.course
|
||||
assert courses[0].id.run == course_key.run
|
||||
|
||||
courses = modulestore().get_courses(branch=BRANCH_NAME_DRAFT, org='other_org')
|
||||
self.assertEqual(len(courses), 0)
|
||||
assert len(courses) == 0
|
||||
|
||||
def test_update_metadata(self):
|
||||
"""
|
||||
@@ -1560,28 +1534,28 @@ class TestItemCrud(SplitModuleTest):
|
||||
problem = modulestore().get_item(locator)
|
||||
pre_def_id = problem.definition_locator.definition_id
|
||||
pre_version_guid = problem.location.version_guid
|
||||
self.assertIsNotNone(pre_def_id)
|
||||
self.assertIsNotNone(pre_version_guid)
|
||||
self.assertNotEqual(problem.max_attempts, 4, "Invalidates rest of test")
|
||||
assert pre_def_id is not None
|
||||
assert pre_version_guid is not None
|
||||
assert problem.max_attempts != 4, 'Invalidates rest of test'
|
||||
|
||||
problem.max_attempts = 4
|
||||
problem.save() # decache above setting into the kvs
|
||||
updated_problem = modulestore().update_item(problem, self.user_id)
|
||||
# check that course version changed and course's previous is the other one
|
||||
self.assertEqual(updated_problem.definition_locator.definition_id, pre_def_id)
|
||||
self.assertNotEqual(updated_problem.location.version_guid, pre_version_guid)
|
||||
self.assertEqual(updated_problem.max_attempts, 4)
|
||||
assert updated_problem.definition_locator.definition_id == pre_def_id
|
||||
assert updated_problem.location.version_guid != pre_version_guid
|
||||
assert updated_problem.max_attempts == 4
|
||||
# refetch to ensure original didn't change
|
||||
original_location = problem.location.map_into_course(CourseLocator(version_guid=pre_version_guid))
|
||||
problem = modulestore().get_item(original_location)
|
||||
self.assertNotEqual(problem.max_attempts, 4, "original changed")
|
||||
assert problem.max_attempts != 4, 'original changed'
|
||||
|
||||
current_course = modulestore().get_course(locator.course_key)
|
||||
self.assertEqual(updated_problem.location.version_guid, current_course.location.version_guid)
|
||||
assert updated_problem.location.version_guid == current_course.location.version_guid
|
||||
|
||||
history_info = modulestore().get_course_history_info(current_course.location.course_key)
|
||||
self.assertEqual(history_info['previous_version'], pre_version_guid)
|
||||
self.assertEqual(history_info['edited_by'], self.user_id)
|
||||
assert history_info['previous_version'] == pre_version_guid
|
||||
assert history_info['edited_by'] == self.user_id
|
||||
|
||||
def test_update_children(self):
|
||||
"""
|
||||
@@ -1595,20 +1569,20 @@ class TestItemCrud(SplitModuleTest):
|
||||
pre_version_guid = block.location.version_guid
|
||||
|
||||
# reorder children
|
||||
self.assertGreater(len(block.children), 0, "meaningless test")
|
||||
assert len(block.children) > 0, 'meaningless test'
|
||||
moved_child = block.children.pop()
|
||||
block.save() # decache model changes
|
||||
updated_problem = modulestore().update_item(block, self.user_id)
|
||||
# check that course version changed and course's previous is the other one
|
||||
self.assertEqual(updated_problem.definition_locator.definition_id, pre_def_id)
|
||||
self.assertNotEqual(updated_problem.location.version_guid, pre_version_guid)
|
||||
self.assertEqual(version_agnostic(updated_problem.children), version_agnostic(block.children))
|
||||
self.assertNotIn(moved_child, version_agnostic(updated_problem.children))
|
||||
assert updated_problem.definition_locator.definition_id == pre_def_id
|
||||
assert updated_problem.location.version_guid != pre_version_guid
|
||||
assert version_agnostic(updated_problem.children) == version_agnostic(block.children)
|
||||
assert moved_child not in version_agnostic(updated_problem.children)
|
||||
locator = locator.course_key.make_usage_key('chapter', "chapter1")
|
||||
other_block = modulestore().get_item(locator)
|
||||
other_block.children.append(moved_child)
|
||||
other_updated = modulestore().update_item(other_block, self.user_id)
|
||||
self.assertIn(moved_child.version_agnostic(), version_agnostic(other_updated.children))
|
||||
assert moved_child.version_agnostic() in version_agnostic(other_updated.children)
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
def test_update_definition(self, _from_json):
|
||||
@@ -1626,9 +1600,9 @@ class TestItemCrud(SplitModuleTest):
|
||||
block.save() # decache model changes
|
||||
updated_block = modulestore().update_item(block, self.user_id)
|
||||
|
||||
self.assertNotEqual(updated_block.definition_locator.definition_id, pre_def_id)
|
||||
self.assertNotEqual(updated_block.location.version_guid, pre_version_guid)
|
||||
self.assertEqual(updated_block.grading_policy['GRADER'][0]['min_count'], 13)
|
||||
assert updated_block.definition_locator.definition_id != pre_def_id
|
||||
assert updated_block.location.version_guid != pre_version_guid
|
||||
assert updated_block.grading_policy['GRADER'][0]['min_count'] == 13
|
||||
|
||||
def test_update_manifold(self):
|
||||
"""
|
||||
@@ -1664,22 +1638,22 @@ class TestItemCrud(SplitModuleTest):
|
||||
pre_def_id = block.definition_locator.definition_id
|
||||
pre_version_guid = block.location.version_guid
|
||||
|
||||
self.assertNotEqual(block.grading_policy['GRADER'][0]['min_count'], 13)
|
||||
assert block.grading_policy['GRADER'][0]['min_count'] != 13
|
||||
block.grading_policy['GRADER'][0]['min_count'] = 13
|
||||
block.children = block.children[1:] + [block.children[0]]
|
||||
block.advertised_start = "Soon"
|
||||
|
||||
block.save() # decache model changes
|
||||
updated_block = modulestore().update_item(block, self.user_id)
|
||||
self.assertNotEqual(updated_block.definition_locator.definition_id, pre_def_id)
|
||||
self.assertNotEqual(updated_block.location.version_guid, pre_version_guid)
|
||||
self.assertEqual(updated_block.grading_policy['GRADER'][0]['min_count'], 13)
|
||||
self.assertEqual(updated_block.children[0].version_agnostic(), block.children[0].version_agnostic())
|
||||
self.assertEqual(updated_block.advertised_start, "Soon")
|
||||
assert updated_block.definition_locator.definition_id != pre_def_id
|
||||
assert updated_block.location.version_guid != pre_version_guid
|
||||
assert updated_block.grading_policy['GRADER'][0]['min_count'] == 13
|
||||
assert updated_block.children[0].version_agnostic() == block.children[0].version_agnostic()
|
||||
assert updated_block.advertised_start == 'Soon'
|
||||
|
||||
def test_delete_item(self):
|
||||
course = self.create_course_for_deletion()
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
modulestore().delete_item(course.location, self.user_id)
|
||||
reusable_location = course.id.version_agnostic().for_branch(BRANCH_NAME_DRAFT)
|
||||
|
||||
@@ -1688,14 +1662,14 @@ class TestItemCrud(SplitModuleTest):
|
||||
locn_to_del = problems[0].location
|
||||
new_course_loc = modulestore().delete_item(locn_to_del, self.user_id)
|
||||
deleted = locn_to_del.version_agnostic()
|
||||
self.assertFalse(modulestore().has_item(deleted))
|
||||
with self.assertRaises(VersionConflictError):
|
||||
assert not modulestore().has_item(deleted)
|
||||
with pytest.raises(VersionConflictError):
|
||||
modulestore().has_item(locn_to_del)
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
modulestore().delete_item(deleted, self.user_id)
|
||||
|
||||
self.assertTrue(modulestore().has_item(locn_to_del.course_agnostic()))
|
||||
self.assertNotEqual(new_course_loc.version_guid, course.location.version_guid)
|
||||
assert modulestore().has_item(locn_to_del.course_agnostic())
|
||||
assert new_course_loc.version_guid != course.location.version_guid
|
||||
|
||||
# delete a subtree
|
||||
nodes = modulestore().get_items(reusable_location, qualifiers={'category': 'chapter'})
|
||||
@@ -1708,10 +1682,8 @@ class TestItemCrud(SplitModuleTest):
|
||||
"""
|
||||
if node:
|
||||
node_loc = node.location
|
||||
self.assertFalse(
|
||||
modulestore().has_item(node_loc.version_agnostic())
|
||||
)
|
||||
self.assertTrue(modulestore().has_item(node_loc.course_agnostic()))
|
||||
assert not modulestore().has_item(node_loc.version_agnostic())
|
||||
assert modulestore().has_item(node_loc.course_agnostic())
|
||||
if node.has_children:
|
||||
for sub in node.get_children():
|
||||
check_subtree(sub)
|
||||
@@ -1769,8 +1741,8 @@ class TestItemCrud(SplitModuleTest):
|
||||
# First child should have been moved to second position, and better child takes the lead
|
||||
refetch_course = store.get_course(versionless_course_locator)
|
||||
children = refetch_course.get_children()
|
||||
self.assertEqual(six.text_type(children[1].location), six.text_type(first_child.location))
|
||||
self.assertEqual(six.text_type(children[0].location), six.text_type(second_child.location))
|
||||
assert six.text_type(children[1].location) == six.text_type(first_child.location)
|
||||
assert six.text_type(children[0].location) == six.text_type(second_child.location)
|
||||
|
||||
# Clean up the data so we don't break other tests which apparently expect a particular state
|
||||
store.delete_course(refetch_course.id, user)
|
||||
@@ -1791,22 +1763,22 @@ class TestCourseCreation(SplitModuleTest):
|
||||
new_locator = new_course.location
|
||||
# check index entry
|
||||
index_info = modulestore().get_course_index_info(new_locator.course_key)
|
||||
self.assertEqual(index_info['org'], 'test_org')
|
||||
self.assertEqual(index_info['edited_by'], 'create_user')
|
||||
assert index_info['org'] == 'test_org'
|
||||
assert index_info['edited_by'] == 'create_user'
|
||||
# check structure info
|
||||
structure_info = modulestore().get_course_history_info(new_locator.course_key)
|
||||
self.assertEqual(structure_info['original_version'], index_info['versions'][BRANCH_NAME_DRAFT])
|
||||
self.assertIsNone(structure_info['previous_version'])
|
||||
assert structure_info['original_version'] == index_info['versions'][BRANCH_NAME_DRAFT]
|
||||
assert structure_info['previous_version'] is None
|
||||
|
||||
self.assertEqual(structure_info['edited_by'], 'create_user')
|
||||
assert structure_info['edited_by'] == 'create_user'
|
||||
# check the returned course object
|
||||
self.assertIsInstance(new_course, CourseDescriptor)
|
||||
self.assertEqual(new_course.category, 'course')
|
||||
self.assertFalse(new_course.show_calculator)
|
||||
self.assertTrue(new_course.allow_anonymous)
|
||||
self.assertEqual(len(new_course.children), 0)
|
||||
self.assertEqual(new_course.edited_by, "create_user")
|
||||
self.assertEqual(len(new_course.grading_policy['GRADER']), 4)
|
||||
assert isinstance(new_course, CourseDescriptor)
|
||||
assert new_course.category == 'course'
|
||||
assert not new_course.show_calculator
|
||||
assert new_course.allow_anonymous
|
||||
assert len(new_course.children) == 0
|
||||
assert new_course.edited_by == 'create_user'
|
||||
assert len(new_course.grading_policy['GRADER']) == 4
|
||||
self.assertDictEqual(new_course.grade_cutoffs, {"Pass": 0.5})
|
||||
|
||||
def test_cloned_course(self):
|
||||
@@ -1821,16 +1793,16 @@ class TestCourseCreation(SplitModuleTest):
|
||||
new_draft_locator = new_draft.location
|
||||
self.assertRegex(new_draft_locator.org, 'best')
|
||||
# the edited_by and other meta fields on the new course will be the original author not this one
|
||||
self.assertEqual(new_draft.edited_by, 'test@edx.org')
|
||||
self.assertEqual(new_draft_locator.version_guid, original_index['versions'][BRANCH_NAME_DRAFT])
|
||||
assert new_draft.edited_by == 'test@edx.org'
|
||||
assert new_draft_locator.version_guid == original_index['versions'][BRANCH_NAME_DRAFT]
|
||||
# however the edited_by and other meta fields on course_index will be this one
|
||||
new_index = modulestore().get_course_index_info(new_draft_locator.course_key)
|
||||
self.assertEqual(new_index['edited_by'], 'leech_master')
|
||||
assert new_index['edited_by'] == 'leech_master'
|
||||
|
||||
new_published_locator = new_draft_locator.course_key.for_branch(BRANCH_NAME_PUBLISHED)
|
||||
new_published = modulestore().get_course(new_published_locator)
|
||||
self.assertEqual(new_published.edited_by, 'test@edx.org')
|
||||
self.assertEqual(new_published.location.version_guid, original_index['versions'][BRANCH_NAME_PUBLISHED])
|
||||
assert new_published.edited_by == 'test@edx.org'
|
||||
assert new_published.location.version_guid == original_index['versions'][BRANCH_NAME_PUBLISHED]
|
||||
|
||||
# changing this course will not change the original course
|
||||
# using new_draft.location will insert the chapter under the course root
|
||||
@@ -1840,16 +1812,16 @@ class TestCourseCreation(SplitModuleTest):
|
||||
)
|
||||
new_draft_locator = new_draft_locator.course_key.version_agnostic()
|
||||
new_index = modulestore().get_course_index_info(new_draft_locator)
|
||||
self.assertNotEqual(new_index['versions'][BRANCH_NAME_DRAFT], original_index['versions'][BRANCH_NAME_DRAFT])
|
||||
assert new_index['versions'][BRANCH_NAME_DRAFT] != original_index['versions'][BRANCH_NAME_DRAFT]
|
||||
new_draft = modulestore().get_course(new_draft_locator)
|
||||
self.assertEqual(new_item.edited_by, 'leech_master')
|
||||
self.assertNotEqual(new_item.location.version_guid, original_index['versions'][BRANCH_NAME_DRAFT])
|
||||
self.assertNotEqual(new_draft.location.version_guid, original_index['versions'][BRANCH_NAME_DRAFT])
|
||||
assert new_item.edited_by == 'leech_master'
|
||||
assert new_item.location.version_guid != original_index['versions'][BRANCH_NAME_DRAFT]
|
||||
assert new_draft.location.version_guid != original_index['versions'][BRANCH_NAME_DRAFT]
|
||||
structure_info = modulestore().get_course_history_info(new_draft_locator)
|
||||
self.assertEqual(structure_info['edited_by'], 'leech_master')
|
||||
assert structure_info['edited_by'] == 'leech_master'
|
||||
|
||||
original_course = modulestore().get_course(original_locator)
|
||||
self.assertEqual(original_course.location.version_guid, original_index['versions'][BRANCH_NAME_DRAFT])
|
||||
assert original_course.location.version_guid == original_index['versions'][BRANCH_NAME_DRAFT]
|
||||
|
||||
def test_derived_course(self):
|
||||
"""
|
||||
@@ -1871,12 +1843,12 @@ class TestCourseCreation(SplitModuleTest):
|
||||
new_draft_locator = new_draft.location
|
||||
self.assertRegex(new_draft_locator.org, 'counter')
|
||||
# the edited_by and other meta fields on the new course will be the original author not this one
|
||||
self.assertEqual(new_draft.edited_by, 'leech_master')
|
||||
self.assertNotEqual(new_draft_locator.version_guid, original_index['versions'][BRANCH_NAME_DRAFT])
|
||||
assert new_draft.edited_by == 'leech_master'
|
||||
assert new_draft_locator.version_guid != original_index['versions'][BRANCH_NAME_DRAFT]
|
||||
# however the edited_by and other meta fields on course_index will be this one
|
||||
new_index = modulestore().get_course_index_info(new_draft_locator.course_key)
|
||||
self.assertEqual(new_index['edited_by'], 'leech_master')
|
||||
self.assertEqual(new_draft.display_name, fields['display_name'])
|
||||
assert new_index['edited_by'] == 'leech_master'
|
||||
assert new_draft.display_name == fields['display_name']
|
||||
self.assertDictEqual(
|
||||
new_draft.grading_policy['GRADE_CUTOFFS'],
|
||||
fields['grading_policy']['GRADE_CUTOFFS']
|
||||
@@ -1898,13 +1870,13 @@ class TestCourseCreation(SplitModuleTest):
|
||||
versions[BRANCH_NAME_DRAFT] = head_course.previous_version
|
||||
modulestore().update_course_index(None, course_info)
|
||||
course = modulestore().get_course(locator)
|
||||
self.assertEqual(course.location.version_guid, versions[BRANCH_NAME_DRAFT])
|
||||
assert course.location.version_guid == versions[BRANCH_NAME_DRAFT]
|
||||
|
||||
# an allowed but not recommended way to publish a course
|
||||
versions[BRANCH_NAME_PUBLISHED] = versions[BRANCH_NAME_DRAFT]
|
||||
modulestore().update_course_index(None, course_info)
|
||||
course = modulestore().get_course(locator.for_branch(BRANCH_NAME_PUBLISHED))
|
||||
self.assertEqual(course.location.version_guid, versions[BRANCH_NAME_DRAFT])
|
||||
assert course.location.version_guid == versions[BRANCH_NAME_DRAFT]
|
||||
|
||||
def test_create_with_root(self):
|
||||
"""
|
||||
@@ -1915,16 +1887,16 @@ class TestCourseCreation(SplitModuleTest):
|
||||
'test_org', 'test_transaction', 'test_run', user, BRANCH_NAME_DRAFT,
|
||||
root_block_id='top', root_category='chapter'
|
||||
)
|
||||
self.assertEqual(new_course.location.block_id, 'top')
|
||||
self.assertEqual(new_course.category, 'chapter')
|
||||
assert new_course.location.block_id == 'top'
|
||||
assert new_course.category == 'chapter'
|
||||
# look at db to verify
|
||||
db_structure = modulestore().db_connection.get_structure(
|
||||
new_course.location.as_object_id(new_course.location.version_guid)
|
||||
)
|
||||
self.assertIsNotNone(db_structure, "Didn't find course")
|
||||
self.assertNotIn(BlockKey('course', 'course'), db_structure['blocks'])
|
||||
self.assertIn(BlockKey('chapter', 'top'), db_structure['blocks'])
|
||||
self.assertEqual(db_structure['blocks'][BlockKey('chapter', 'top')].block_type, 'chapter')
|
||||
assert db_structure is not None, "Didn't find course"
|
||||
assert BlockKey('course', 'course') not in db_structure['blocks']
|
||||
assert BlockKey('chapter', 'top') in db_structure['blocks']
|
||||
assert db_structure['blocks'][BlockKey('chapter', 'top')].block_type == 'chapter'
|
||||
|
||||
def test_create_id_dupe(self):
|
||||
"""
|
||||
@@ -1932,7 +1904,7 @@ class TestCourseCreation(SplitModuleTest):
|
||||
"""
|
||||
user = random.getrandbits(32)
|
||||
courses = modulestore().get_courses(BRANCH_NAME_DRAFT)
|
||||
with self.assertRaises(DuplicateCourseError):
|
||||
with pytest.raises(DuplicateCourseError):
|
||||
dupe_course_key = courses[0].location.course_key
|
||||
modulestore().create_course(
|
||||
dupe_course_key.org, dupe_course_key.course, dupe_course_key.run, user, BRANCH_NAME_DRAFT
|
||||
@@ -1966,12 +1938,12 @@ class TestCourseCreation(SplitModuleTest):
|
||||
# now get_courses
|
||||
courses = split_store.get_courses(BRANCH_NAME_DRAFT)
|
||||
|
||||
self.assertEqual(len(courses), 3)
|
||||
assert len(courses) == 3
|
||||
course_ids = [course.id.for_branch(None) for course in courses]
|
||||
self.assertNotIn(to_be_deleted, course_ids)
|
||||
self.assertIn(to_be_created, course_ids)
|
||||
assert to_be_deleted not in course_ids
|
||||
assert to_be_created in course_ids
|
||||
fetched_modified = [course for course in courses if course.id == modified_course_loc][0]
|
||||
self.assertEqual(fetched_modified.advertised_start, modified_course.advertised_start)
|
||||
assert fetched_modified.advertised_start == modified_course.advertised_start
|
||||
|
||||
|
||||
class TestInheritance(SplitModuleTest):
|
||||
@@ -1990,13 +1962,13 @@ class TestInheritance(SplitModuleTest):
|
||||
)
|
||||
node = modulestore().get_item(locator)
|
||||
# inherited
|
||||
self.assertEqual(node.graceperiod, datetime.timedelta(hours=2))
|
||||
assert node.graceperiod == datetime.timedelta(hours=2)
|
||||
locator = BlockUsageLocator(
|
||||
CourseLocator(org='testx', course='GreekHero', run="run", branch=BRANCH_NAME_DRAFT), 'problem', 'problem1'
|
||||
)
|
||||
node = modulestore().get_item(locator)
|
||||
# overridden
|
||||
self.assertEqual(node.graceperiod, datetime.timedelta(hours=4))
|
||||
assert node.graceperiod == datetime.timedelta(hours=4)
|
||||
|
||||
def test_inheritance_not_saved(self):
|
||||
"""
|
||||
@@ -2013,12 +1985,12 @@ class TestInheritance(SplitModuleTest):
|
||||
CourseLocator(org='testx', course='GreekHero', run="run", branch=BRANCH_NAME_DRAFT), 'problem', 'problem3_2' # lint-amnesty, pylint: disable=line-too-long
|
||||
)
|
||||
)
|
||||
self.assertFalse(problem.visible_to_staff_only)
|
||||
assert not problem.visible_to_staff_only
|
||||
|
||||
chapter.visible_to_staff_only = True
|
||||
modulestore().update_item(chapter, self.user_id)
|
||||
problem = modulestore().get_item(problem.location.version_agnostic())
|
||||
self.assertTrue(problem.visible_to_staff_only)
|
||||
assert problem.visible_to_staff_only
|
||||
|
||||
# unset on parent, retrieve child, verify unset
|
||||
chapter = modulestore().get_item(chapter.location.version_agnostic())
|
||||
@@ -2026,7 +1998,7 @@ class TestInheritance(SplitModuleTest):
|
||||
modulestore().update_item(chapter, self.user_id)
|
||||
|
||||
problem = modulestore().get_item(problem.location.version_agnostic())
|
||||
self.assertFalse(problem.visible_to_staff_only)
|
||||
assert not problem.visible_to_staff_only
|
||||
|
||||
def test_dynamic_inheritance(self):
|
||||
"""
|
||||
@@ -2037,13 +2009,13 @@ class TestInheritance(SplitModuleTest):
|
||||
|
||||
chapter.visible_to_staff_only = True
|
||||
orphan_problem = modulestore().create_item(self.user_id, course_key, 'problem')
|
||||
self.assertFalse(orphan_problem.visible_to_staff_only)
|
||||
assert not orphan_problem.visible_to_staff_only
|
||||
parented_problem = modulestore().create_child(self.user_id, chapter.location.version_agnostic(), 'problem') # lint-amnesty, pylint: disable=unused-variable
|
||||
# FIXME LMS-11376
|
||||
# self.assertTrue(parented_problem.visible_to_staff_only)
|
||||
|
||||
orphan_problem = modulestore().create_xblock(chapter.runtime, course_key, 'problem')
|
||||
self.assertFalse(orphan_problem.visible_to_staff_only)
|
||||
assert not orphan_problem.visible_to_staff_only
|
||||
parented_problem = modulestore().create_xblock(chapter.runtime, course_key, 'problem', parent_xblock=chapter)
|
||||
# FIXME LMS-11376
|
||||
# self.assertTrue(parented_problem.visible_to_staff_only)
|
||||
@@ -2081,16 +2053,14 @@ class TestPublish(SplitModuleTest):
|
||||
# remove chapter1 from expected b/c its pub'd version != the source anymore since source changed
|
||||
expected.remove(BlockKey.from_usage_key(chapter1))
|
||||
# check that it's not in published course
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().get_item(new_module.location.map_into_course(dest_course))
|
||||
# publish it
|
||||
modulestore().copy(self.user_id, source_course, dest_course, [new_module.location], None)
|
||||
expected.append(BlockKey.from_usage_key(new_module.location))
|
||||
# check that it is in the published course and that its parent is the chapter
|
||||
pub_module = modulestore().get_item(new_module.location.map_into_course(dest_course))
|
||||
self.assertEqual(
|
||||
modulestore().get_parent_location(pub_module.location).block_id, chapter1.block_id
|
||||
)
|
||||
assert modulestore().get_parent_location(pub_module.location).block_id == chapter1.block_id
|
||||
# ensure intentionally orphaned blocks work (e.g., course_info)
|
||||
new_module = modulestore().create_item(
|
||||
self.user_id, source_course, "course_info", block_id="handouts"
|
||||
@@ -2112,15 +2082,15 @@ class TestPublish(SplitModuleTest):
|
||||
head = source_course.make_usage_key('course', "head12345")
|
||||
chapter3 = source_course.make_usage_key('chapter', 'chapter3')
|
||||
problem1 = source_course.make_usage_key('problem', 'problem1')
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().copy(self.user_id, source_course, destination_course, [chapter3], None)
|
||||
# publishing into a new branch w/o publishing the root
|
||||
destination_course = CourseLocator(org='testx', course='GreekHero', run='run', branch=BRANCH_NAME_PUBLISHED)
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().copy(self.user_id, source_course, destination_course, [chapter3], None)
|
||||
# publishing a subdag w/o the parent already in course
|
||||
modulestore().copy(self.user_id, source_course, destination_course, [head], [chapter3])
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().copy(self.user_id, source_course, destination_course, [problem1], [])
|
||||
|
||||
@patch('xmodule.tabs.CourseTab.from_json', side_effect=mock_tab_from_json)
|
||||
@@ -2163,31 +2133,25 @@ class TestPublish(SplitModuleTest):
|
||||
Check that the course has the expected blocks and does not have the unexpected blocks
|
||||
"""
|
||||
history_info = modulestore().get_course_history_info(dest_course_loc)
|
||||
self.assertEqual(history_info['edited_by'], self.user_id)
|
||||
assert history_info['edited_by'] == self.user_id
|
||||
for expected in expected_blocks:
|
||||
source = modulestore().get_item(source_course_loc.make_usage_key(expected.type, expected.id))
|
||||
pub_copy = modulestore().get_item(dest_course_loc.make_usage_key(expected.type, expected.id))
|
||||
# everything except previous_version & children should be the same
|
||||
self.assertEqual(source.category, pub_copy.category)
|
||||
self.assertEqual(
|
||||
source.update_version, pub_copy.source_version,
|
||||
u"Versions don't match for {}: {} != {}".format(
|
||||
expected, source.update_version, pub_copy.update_version
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
self.user_id, pub_copy.edited_by,
|
||||
"{} edited_by {} not {}".format(pub_copy.location, pub_copy.edited_by, self.user_id)
|
||||
)
|
||||
assert source.category == pub_copy.category
|
||||
assert source.update_version == pub_copy.source_version,\
|
||||
f"Versions don't match for {expected}: {source.update_version} != {pub_copy.update_version}"
|
||||
assert self.user_id == pub_copy.edited_by,\
|
||||
f'{pub_copy.location} edited_by {pub_copy.edited_by} not {self.user_id}'
|
||||
for field in source.fields.values():
|
||||
if field.name == 'children':
|
||||
self._compare_children(field.read_from(source), field.read_from(pub_copy), unexpected_blocks)
|
||||
elif isinstance(field, (Reference, ReferenceList, ReferenceValueDict)):
|
||||
self.assertReferenceEqual(field.read_from(source), field.read_from(pub_copy))
|
||||
else:
|
||||
self.assertEqual(field.read_from(source), field.read_from(pub_copy))
|
||||
assert field.read_from(source) == field.read_from(pub_copy)
|
||||
for unexp in unexpected_blocks:
|
||||
with self.assertRaises(ItemNotFoundError):
|
||||
with pytest.raises(ItemNotFoundError):
|
||||
modulestore().get_item(dest_course_loc.make_usage_key(unexp.type, unexp.id))
|
||||
|
||||
def assertReferenceEqual(self, expected, actual): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
@@ -2200,7 +2164,7 @@ class TestPublish(SplitModuleTest):
|
||||
elif isinstance(expected, dict):
|
||||
expected = {key: BlockKey.from_usage_key(val) for (key, val) in expected}
|
||||
actual = {key: BlockKey.from_usage_key(val) for (key, val) in actual}
|
||||
self.assertEqual(expected, actual)
|
||||
assert expected == actual
|
||||
|
||||
@contract(
|
||||
source_children="list(BlockUsageLocator)",
|
||||
@@ -2219,9 +2183,9 @@ class TestPublish(SplitModuleTest):
|
||||
]
|
||||
dest_block_keys = [BlockKey.from_usage_key(dest) for dest in dest_children]
|
||||
for unexp in unexpected:
|
||||
self.assertNotIn(unexp, dest_block_keys)
|
||||
assert unexp not in dest_block_keys
|
||||
|
||||
self.assertEqual(source_block_keys, dest_block_keys)
|
||||
assert source_block_keys == dest_block_keys
|
||||
|
||||
|
||||
class TestSchema(SplitModuleTest):
|
||||
@@ -2234,16 +2198,10 @@ class TestSchema(SplitModuleTest):
|
||||
"""
|
||||
db_connection = modulestore().db_connection
|
||||
for collection in [db_connection.course_index, db_connection.structures, db_connection.definitions]:
|
||||
self.assertEqual(
|
||||
collection.count_documents({'schema_version': {'$exists': False}}),
|
||||
0,
|
||||
"{0.name} has records without schema_version".format(collection)
|
||||
)
|
||||
self.assertEqual(
|
||||
collection.count_documents({'schema_version': {'$ne': SplitMongoModuleStore.SCHEMA_VERSION}}),
|
||||
0,
|
||||
"{0.name} has records with wrong schema_version".format(collection)
|
||||
)
|
||||
assert collection.count_documents({'schema_version': {'$exists': False}}) == 0, \
|
||||
f'{collection.name} has records without schema_version'
|
||||
assert collection.count_documents({'schema_version': {'$ne': SplitMongoModuleStore.SCHEMA_VERSION}}) == 0, \
|
||||
f'{collection.name} has records with wrong schema_version'
|
||||
|
||||
|
||||
# ===========================================
|
||||
|
||||
@@ -42,10 +42,10 @@ class TestBulkWriteMixin(unittest.TestCase): # lint-amnesty, pylint: disable=mi
|
||||
self.index_entry = {'this': 'is', 'an': 'index'}
|
||||
|
||||
def assertConnCalls(self, *calls):
|
||||
self.assertEqual(list(calls), self.conn.mock_calls)
|
||||
assert list(calls) == self.conn.mock_calls
|
||||
|
||||
def assertCacheNotCleared(self):
|
||||
self.assertFalse(self.clear_cache.called)
|
||||
assert not self.clear_cache.called
|
||||
|
||||
|
||||
class TestBulkWriteMixinPreviousTransaction(TestBulkWriteMixin):
|
||||
@@ -77,7 +77,7 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin):
|
||||
self.assertConnCalls(
|
||||
call.get_structure(self.course_key.as_object_id(version_guid), self.course_key)
|
||||
)
|
||||
self.assertEqual(result, self.conn.get_structure.return_value)
|
||||
assert result == self.conn.get_structure.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
def test_no_bulk_write_structure(self):
|
||||
@@ -100,7 +100,7 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin):
|
||||
self.course_key
|
||||
)
|
||||
)
|
||||
self.assertEqual(result, self.conn.get_definition.return_value)
|
||||
assert result == self.conn.get_definition.return_value
|
||||
|
||||
def test_no_bulk_write_definition(self):
|
||||
# Writing a definition when no bulk operation is active should just
|
||||
@@ -114,7 +114,7 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin):
|
||||
# through to the db_connection
|
||||
result = self.bulk.get_course_index(self.course_key, ignore_case=ignore_case)
|
||||
self.assertConnCalls(call.get_course_index(self.course_key, ignore_case))
|
||||
self.assertEqual(result, self.conn.get_course_index.return_value)
|
||||
assert result == self.conn.get_course_index.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
def test_no_bulk_write_index(self):
|
||||
@@ -291,17 +291,14 @@ class TestBulkWriteMixinClosed(TestBulkWriteMixin):
|
||||
)
|
||||
|
||||
def test_version_structure_creates_new_version(self):
|
||||
self.assertNotEqual(
|
||||
self.bulk.version_structure(self.course_key, self.structure, 'user_id')['_id'],
|
||||
self.structure['_id']
|
||||
)
|
||||
assert self.bulk.version_structure(self.course_key, self.structure, 'user_id')['_id'] != self.structure['_id']
|
||||
|
||||
def test_version_structure_new_course(self):
|
||||
self.conn.get_course_index.return_value = None
|
||||
self.bulk._begin_bulk_operation(self.course_key)
|
||||
version_result = self.bulk.version_structure(self.course_key, self.structure, 'user_id')
|
||||
get_result = self.bulk.get_structure(self.course_key, version_result['_id'])
|
||||
self.assertEqual(version_result, get_result)
|
||||
assert version_result == get_result
|
||||
|
||||
|
||||
class TestBulkWriteMixinClosedAfterPrevTransaction(TestBulkWriteMixinClosed, TestBulkWriteMixinPreviousTransaction): # lint-amnesty, pylint: disable=test-inherits-tests
|
||||
@@ -330,7 +327,7 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin):
|
||||
course_keys=None
|
||||
)
|
||||
)
|
||||
self.assertEqual(result, self.conn.find_matching_course_indexes.return_value)
|
||||
assert result == self.conn.find_matching_course_indexes.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
@ddt.data(
|
||||
@@ -399,14 +396,14 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin):
|
||||
result = self.bulk.find_matching_course_indexes(branch, search_targets)
|
||||
six.assertCountEqual(self, result, expected)
|
||||
for item in unmatching:
|
||||
self.assertNotIn(item, result)
|
||||
assert item not in result
|
||||
|
||||
def test_no_bulk_find_structures_by_id(self):
|
||||
ids = [Mock(name='id')]
|
||||
self.conn.find_structures_by_id.return_value = [MagicMock(name='result')]
|
||||
result = self.bulk.find_structures_by_id(ids)
|
||||
self.assertConnCalls(call.find_structures_by_id(ids))
|
||||
self.assertEqual(result, self.conn.find_structures_by_id.return_value)
|
||||
assert result == self.conn.find_structures_by_id.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
@ddt.data(
|
||||
@@ -431,14 +428,14 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin):
|
||||
self.conn.find_structures_by_id.assert_called_once_with(list(set(search_ids) - set(active_ids)))
|
||||
for _id in active_ids:
|
||||
if _id in search_ids:
|
||||
self.assertIn(active_structure(_id), results)
|
||||
assert active_structure(_id) in results
|
||||
else:
|
||||
self.assertNotIn(active_structure(_id), results)
|
||||
assert active_structure(_id) not in results
|
||||
for _id in db_ids:
|
||||
if _id in search_ids and _id not in active_ids:
|
||||
self.assertIn(db_structure(_id), results)
|
||||
assert db_structure(_id) in results
|
||||
else:
|
||||
self.assertNotIn(db_structure(_id), results)
|
||||
assert db_structure(_id) not in results
|
||||
|
||||
@ddt.data(
|
||||
([], [], []),
|
||||
@@ -463,17 +460,17 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin):
|
||||
self.conn.get_definitions.assert_called_once_with(definitions_gotten, self.course_key)
|
||||
else:
|
||||
# If no definitions to get, then get_definitions() should *not* have been called.
|
||||
self.assertEqual(self.conn.get_definitions.call_count, 0)
|
||||
assert self.conn.get_definitions.call_count == 0
|
||||
for _id in active_ids:
|
||||
if _id in search_ids:
|
||||
self.assertIn(active_definition(_id), results)
|
||||
assert active_definition(_id) in results
|
||||
else:
|
||||
self.assertNotIn(active_definition(_id), results)
|
||||
assert active_definition(_id) not in results
|
||||
for _id in db_ids:
|
||||
if _id in search_ids and _id not in active_ids:
|
||||
self.assertIn(db_definition(_id), results)
|
||||
assert db_definition(_id) in results
|
||||
else:
|
||||
self.assertNotIn(db_definition(_id), results)
|
||||
assert db_definition(_id) not in results
|
||||
|
||||
def test_get_definitions_doesnt_update_db(self):
|
||||
test_ids = [1, 2]
|
||||
@@ -484,14 +481,14 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin):
|
||||
self.bulk._begin_bulk_operation(self.course_key)
|
||||
self.bulk.get_definitions(self.course_key, test_ids)
|
||||
self.bulk._end_bulk_operation(self.course_key)
|
||||
self.assertFalse(self.conn.insert_definition.called)
|
||||
assert not self.conn.insert_definition.called
|
||||
|
||||
def test_no_bulk_find_structures_derived_from(self):
|
||||
ids = [Mock(name='id')]
|
||||
self.conn.find_structures_derived_from.return_value = [MagicMock(name='result')]
|
||||
result = self.bulk.find_structures_derived_from(ids)
|
||||
self.assertConnCalls(call.find_structures_derived_from(ids))
|
||||
self.assertEqual(result, self.conn.find_structures_derived_from.return_value)
|
||||
assert result == self.conn.find_structures_derived_from.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
@ddt.data(
|
||||
@@ -529,17 +526,17 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin):
|
||||
self.conn.find_structures_derived_from.assert_called_once_with(search_ids)
|
||||
for structure in active_structures:
|
||||
if structure['previous_version'] in search_ids:
|
||||
self.assertIn(structure, results)
|
||||
assert structure in results
|
||||
else:
|
||||
self.assertNotIn(structure, results)
|
||||
assert structure not in results
|
||||
for structure in db_structures:
|
||||
if (
|
||||
structure['previous_version'] in search_ids and # We're searching for this document
|
||||
not any(active.endswith(structure['_id']) for active in active_ids) # This document doesn't match any active _ids # lint-amnesty, pylint: disable=line-too-long
|
||||
):
|
||||
self.assertIn(structure, results)
|
||||
assert structure in results
|
||||
else:
|
||||
self.assertNotIn(structure, results)
|
||||
assert structure not in results
|
||||
|
||||
def test_no_bulk_find_ancestor_structures(self):
|
||||
original_version = Mock(name='original_version')
|
||||
@@ -547,7 +544,7 @@ class TestBulkWriteMixinFindMethods(TestBulkWriteMixin):
|
||||
self.conn.find_ancestor_structures.return_value = [MagicMock(name='result')]
|
||||
result = self.bulk.find_ancestor_structures(original_version, block_id)
|
||||
self.assertConnCalls(call.find_ancestor_structures(original_version, block_id))
|
||||
self.assertEqual(result, self.conn.find_ancestor_structures.return_value)
|
||||
assert result == self.conn.find_ancestor_structures.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
@ddt.data(
|
||||
@@ -604,8 +601,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
# returns the structure from the database
|
||||
version_guid = VERSION_GUID_DICT[version_guid_name]
|
||||
result = self.bulk.get_structure(self.course_key, version_guid)
|
||||
self.assertEqual(self.conn.get_structure.call_count, 1)
|
||||
self.assertEqual(result, self.conn.get_structure.return_value)
|
||||
assert self.conn.get_structure.call_count == 1
|
||||
assert result == self.conn.get_structure.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
@ddt.data(*SAMPLE_GUIDS_LIST)
|
||||
@@ -615,8 +612,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
version_guid = VERSION_GUID_DICT[version_guid_name]
|
||||
for _ in range(2):
|
||||
result = self.bulk.get_structure(self.course_key, version_guid)
|
||||
self.assertEqual(self.conn.get_structure.call_count, 1)
|
||||
self.assertEqual(result, self.conn.get_structure.return_value)
|
||||
assert self.conn.get_structure.call_count == 1
|
||||
assert result == self.conn.get_structure.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
@ddt.data(*SAMPLE_GUIDS_LIST)
|
||||
@@ -626,8 +623,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
self.structure['_id'] = version_guid
|
||||
self.bulk.update_structure(self.course_key, self.structure)
|
||||
result = self.bulk.get_structure(self.course_key, version_guid)
|
||||
self.assertEqual(self.conn.get_structure.call_count, 0)
|
||||
self.assertEqual(result, self.structure)
|
||||
assert self.conn.get_structure.call_count == 0
|
||||
assert result == self.structure
|
||||
|
||||
@ddt.data(*SAMPLE_GUIDS_LIST)
|
||||
def test_read_structure_after_write_after_read(self, version_guid_name):
|
||||
@@ -638,8 +635,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
self.bulk.get_structure(self.course_key, version_guid)
|
||||
self.bulk.update_structure(self.course_key, self.structure)
|
||||
result = self.bulk.get_structure(self.course_key, version_guid)
|
||||
self.assertEqual(self.conn.get_structure.call_count, 1)
|
||||
self.assertEqual(result, self.structure)
|
||||
assert self.conn.get_structure.call_count == 1
|
||||
assert result == self.structure
|
||||
|
||||
@ddt.data(*SAMPLE_GUIDS_LIST)
|
||||
def test_read_definition_without_write_from_db(self, version_guid_name):
|
||||
@@ -647,8 +644,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
# returns the definition from the database
|
||||
version_guid = VERSION_GUID_DICT[version_guid_name]
|
||||
result = self.bulk.get_definition(self.course_key, version_guid)
|
||||
self.assertEqual(self.conn.get_definition.call_count, 1)
|
||||
self.assertEqual(result, self.conn.get_definition.return_value)
|
||||
assert self.conn.get_definition.call_count == 1
|
||||
assert result == self.conn.get_definition.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
@ddt.data(*SAMPLE_GUIDS_LIST)
|
||||
@@ -658,8 +655,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
version_guid = VERSION_GUID_DICT[version_guid_name]
|
||||
for _ in range(2):
|
||||
result = self.bulk.get_definition(self.course_key, version_guid)
|
||||
self.assertEqual(self.conn.get_definition.call_count, 1)
|
||||
self.assertEqual(result, self.conn.get_definition.return_value)
|
||||
assert self.conn.get_definition.call_count == 1
|
||||
assert result == self.conn.get_definition.return_value
|
||||
self.assertCacheNotCleared()
|
||||
|
||||
@ddt.data(*SAMPLE_GUIDS_LIST)
|
||||
@@ -669,8 +666,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
self.definition['_id'] = version_guid
|
||||
self.bulk.update_definition(self.course_key, self.definition)
|
||||
result = self.bulk.get_definition(self.course_key, version_guid)
|
||||
self.assertEqual(self.conn.get_definition.call_count, 0)
|
||||
self.assertEqual(result, self.definition)
|
||||
assert self.conn.get_definition.call_count == 0
|
||||
assert result == self.definition
|
||||
|
||||
@ddt.data(*SAMPLE_GUIDS_LIST)
|
||||
def test_read_definition_after_write_after_read(self, version_guid_name):
|
||||
@@ -681,15 +678,15 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
self.bulk.get_definition(self.course_key, version_guid)
|
||||
self.bulk.update_definition(self.course_key, self.definition)
|
||||
result = self.bulk.get_definition(self.course_key, version_guid)
|
||||
self.assertEqual(self.conn.get_definition.call_count, 1)
|
||||
self.assertEqual(result, self.definition)
|
||||
assert self.conn.get_definition.call_count == 1
|
||||
assert result == self.definition
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_read_index_without_write_from_db(self, ignore_case):
|
||||
# Reading the index without writing to it should pull from the database
|
||||
result = self.bulk.get_course_index(self.course_key, ignore_case=ignore_case)
|
||||
self.assertEqual(self.conn.get_course_index.call_count, 1)
|
||||
self.assertEqual(self.conn.get_course_index.return_value, result)
|
||||
assert self.conn.get_course_index.call_count == 1
|
||||
assert self.conn.get_course_index.return_value == result
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_read_index_without_write_only_reads_once(self, ignore_case):
|
||||
@@ -697,8 +694,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
# the database
|
||||
for _ in range(2):
|
||||
result = self.bulk.get_course_index(self.course_key, ignore_case=ignore_case)
|
||||
self.assertEqual(self.conn.get_course_index.call_count, 1)
|
||||
self.assertEqual(self.conn.get_course_index.return_value, result)
|
||||
assert self.conn.get_course_index.call_count == 1
|
||||
assert self.conn.get_course_index.return_value == result
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_read_index_after_write(self, ignore_case):
|
||||
@@ -706,8 +703,8 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
# initial index, and should return the written index_entry
|
||||
self.bulk.insert_course_index(self.course_key, self.index_entry)
|
||||
result = self.bulk.get_course_index(self.course_key, ignore_case=ignore_case)
|
||||
self.assertEqual(self.conn.get_course_index.call_count, 1)
|
||||
self.assertEqual(self.index_entry, result)
|
||||
assert self.conn.get_course_index.call_count == 1
|
||||
assert self.index_entry == result
|
||||
|
||||
def test_read_index_ignore_case(self):
|
||||
# Reading using ignore case should find an already written entry with a different case
|
||||
@@ -720,22 +717,16 @@ class TestBulkWriteMixinOpen(TestBulkWriteMixin):
|
||||
),
|
||||
ignore_case=True
|
||||
)
|
||||
self.assertEqual(self.conn.get_course_index.call_count, 1)
|
||||
self.assertEqual(self.index_entry, result)
|
||||
assert self.conn.get_course_index.call_count == 1
|
||||
assert self.index_entry == result
|
||||
|
||||
def test_version_structure_creates_new_version_before_read(self):
|
||||
self.assertNotEqual(
|
||||
self.bulk.version_structure(self.course_key, self.structure, 'user_id')['_id'],
|
||||
self.structure['_id']
|
||||
)
|
||||
assert self.bulk.version_structure(self.course_key, self.structure, 'user_id')['_id'] != self.structure['_id']
|
||||
|
||||
def test_version_structure_creates_new_version_after_read(self):
|
||||
self.conn.get_structure.return_value = copy.deepcopy(self.structure)
|
||||
self.bulk.get_structure(self.course_key, self.structure['_id'])
|
||||
self.assertNotEqual(
|
||||
self.bulk.version_structure(self.course_key, self.structure, 'user_id')['_id'],
|
||||
self.structure['_id']
|
||||
)
|
||||
assert self.bulk.version_structure(self.course_key, self.structure, 'user_id')['_id'] != self.structure['_id']
|
||||
|
||||
def test_copy_branch_versions(self):
|
||||
# Directly updating an index so that the draft branch points to the published index
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
from mock import patch
|
||||
from pymongo.errors import ConnectionFailure
|
||||
|
||||
@@ -21,5 +21,5 @@ class TestHeartbeatFailureException(unittest.TestCase):
|
||||
mock_proxy.return_value.admin.command.side_effect = ConnectionFailure('Test')
|
||||
useless_conn = MongoConnection('useless', 'useless', 'useless')
|
||||
|
||||
with self.assertRaises(HeartbeatFailure):
|
||||
with pytest.raises(HeartbeatFailure):
|
||||
useless_conn.heartbeat()
|
||||
|
||||
@@ -81,4 +81,4 @@ class TestUtils(unittest.TestCase):
|
||||
module_nodes.append(draft_node_constructor(Mock(), node_args[0], node_args[1]))
|
||||
subtree_roots_urls = [root.url for root in get_draft_subtree_roots(module_nodes)]
|
||||
# check that we return the expected urls
|
||||
self.assertEqual(set(subtree_roots_urls), set(expected_roots_urls))
|
||||
assert set(subtree_roots_urls) == set(expected_roots_urls)
|
||||
|
||||
@@ -6,7 +6,7 @@ well-formed and not-well-formed XML.
|
||||
|
||||
import os.path
|
||||
from glob import glob
|
||||
|
||||
import pytest
|
||||
from django.test import TestCase
|
||||
from mock import Mock, patch
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
@@ -44,7 +44,7 @@ class TestXMLModuleStore(TestCase):
|
||||
# Ensure that there really is a non-ASCII character in the course.
|
||||
with open(os.path.join(DATA_DIR, "toy/sequential/vertical_sequential.xml"), 'rb') as xmlf:
|
||||
xml = xmlf.read()
|
||||
with self.assertRaises(UnicodeDecodeError):
|
||||
with pytest.raises(UnicodeDecodeError):
|
||||
xml.decode('ascii')
|
||||
|
||||
# Load the course, but don't make error modules. This will succeed,
|
||||
@@ -66,23 +66,23 @@ class TestXMLModuleStore(TestCase):
|
||||
store = XMLModuleStore(DATA_DIR, source_dirs=['toy', 'simple'])
|
||||
for course in store.get_courses():
|
||||
course_locations = store.get_courses_for_wiki(course.wiki_slug)
|
||||
self.assertEqual(len(course_locations), 1)
|
||||
self.assertIn(course.location.course_key, course_locations)
|
||||
assert len(course_locations) == 1
|
||||
assert course.location.course_key in course_locations
|
||||
|
||||
course_locations = store.get_courses_for_wiki('no_such_wiki')
|
||||
self.assertEqual(len(course_locations), 0)
|
||||
assert len(course_locations) == 0
|
||||
|
||||
# now set toy course to share the wiki with simple course
|
||||
toy_course = store.get_course(CourseKey.from_string('edX/toy/2012_Fall'))
|
||||
toy_course.wiki_slug = 'simple'
|
||||
|
||||
course_locations = store.get_courses_for_wiki('toy')
|
||||
self.assertEqual(len(course_locations), 0)
|
||||
assert len(course_locations) == 0
|
||||
|
||||
course_locations = store.get_courses_for_wiki('simple')
|
||||
self.assertEqual(len(course_locations), 2)
|
||||
assert len(course_locations) == 2
|
||||
for course_number in ['toy', 'simple']:
|
||||
self.assertIn(CourseKey.from_string('/'.join(['edX', course_number, '2012_Fall'])), course_locations)
|
||||
assert CourseKey.from_string('/'.join(['edX', course_number, '2012_Fall'])) in course_locations
|
||||
|
||||
def test_has_course(self):
|
||||
"""
|
||||
@@ -106,7 +106,7 @@ class TestXMLModuleStore(TestCase):
|
||||
store.get_item(course.location)
|
||||
|
||||
# XML store does NOT allow draft_preferred branch setting
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
with store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, course.id):
|
||||
# verify that the above context manager raises a ValueError
|
||||
pass # pragma: no cover
|
||||
@@ -130,15 +130,15 @@ class TestXMLModuleStore(TestCase):
|
||||
shared_item_loc = course_key.make_usage_key('html', 'toyhtml')
|
||||
shared_item = store.get_item(shared_item_loc)
|
||||
parent = shared_item.get_parent()
|
||||
self.assertIsNotNone(parent, "get_parent failed to return a value")
|
||||
assert parent is not None, 'get_parent failed to return a value'
|
||||
parent_loc = course_key.make_usage_key('vertical', 'vertical_test')
|
||||
self.assertEqual(parent.location, parent_loc)
|
||||
self.assertIn(shared_item.location, [x.location for x in parent.get_children()])
|
||||
assert parent.location == parent_loc
|
||||
assert shared_item.location in [x.location for x in parent.get_children()]
|
||||
# ensure it's still a child of the other parent even tho it doesn't claim the other parent as its parent
|
||||
other_parent_loc = course_key.make_usage_key('vertical', 'zeta')
|
||||
other_parent = store.get_item(other_parent_loc)
|
||||
# children rather than get_children b/c the instance returned by get_children != shared_item
|
||||
self.assertIn(shared_item_loc, other_parent.children)
|
||||
assert shared_item_loc in other_parent.children
|
||||
|
||||
|
||||
class TestModuleStoreIgnore(TestXMLModuleStore): # lint-amnesty, pylint: disable=missing-class-docstring, test-inherits-tests
|
||||
@@ -156,5 +156,5 @@ class TestModuleStoreIgnore(TestXMLModuleStore): # lint-amnesty, pylint: disabl
|
||||
'about', 'index',
|
||||
)
|
||||
about_module = modulestore.get_item(about_location)
|
||||
self.assertIn("GREEN", about_module.data)
|
||||
self.assertNotIn("RED", about_module.data)
|
||||
assert 'GREEN' in about_module.data
|
||||
assert 'RED' not in about_module.data
|
||||
|
||||
@@ -7,7 +7,7 @@ import importlib
|
||||
import os
|
||||
import unittest
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
import mock
|
||||
import six
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
@@ -165,22 +165,16 @@ class RemapNamespaceTest(ModuleStoreNoSettings):
|
||||
)
|
||||
|
||||
# Check the XBlock's location
|
||||
self.assertEqual(new_version.location.course_key, target_location_namespace)
|
||||
assert new_version.location.course_key == target_location_namespace
|
||||
|
||||
# Check the values of the fields.
|
||||
# The content and settings fields should be preserved
|
||||
self.assertEqual(new_version.test_content_field, 'Explicitly set')
|
||||
self.assertEqual(new_version.test_settings_field, 'Explicitly set')
|
||||
assert new_version.test_content_field == 'Explicitly set'
|
||||
assert new_version.test_settings_field == 'Explicitly set'
|
||||
|
||||
# Expect that these fields are marked explicitly set
|
||||
self.assertIn(
|
||||
'test_content_field',
|
||||
new_version.get_explicitly_set_fields_by_scope(scope=Scope.content)
|
||||
)
|
||||
self.assertIn(
|
||||
'test_settings_field',
|
||||
new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
|
||||
)
|
||||
assert 'test_content_field' in new_version.get_explicitly_set_fields_by_scope(scope=Scope.content)
|
||||
assert 'test_settings_field' in new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
|
||||
|
||||
def test_remap_namespace_native_xblock_default_values(self):
|
||||
|
||||
@@ -203,18 +197,12 @@ class RemapNamespaceTest(ModuleStoreNoSettings):
|
||||
|
||||
# Check the values of the fields.
|
||||
# The content and settings fields should be the default values
|
||||
self.assertEqual(new_version.test_content_field, 'default value')
|
||||
self.assertEqual(new_version.test_settings_field, 'default value')
|
||||
assert new_version.test_content_field == 'default value'
|
||||
assert new_version.test_settings_field == 'default value'
|
||||
|
||||
# The fields should NOT appear in the explicitly set fields
|
||||
self.assertNotIn(
|
||||
'test_content_field',
|
||||
new_version.get_explicitly_set_fields_by_scope(scope=Scope.content)
|
||||
)
|
||||
self.assertNotIn(
|
||||
'test_settings_field',
|
||||
new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
|
||||
)
|
||||
assert 'test_content_field' not in new_version.get_explicitly_set_fields_by_scope(scope=Scope.content)
|
||||
assert 'test_settings_field' not in new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
|
||||
|
||||
def test_remap_namespace_native_xblock_inherited_values(self):
|
||||
|
||||
@@ -234,12 +222,8 @@ class RemapNamespaceTest(ModuleStoreNoSettings):
|
||||
)
|
||||
|
||||
# Inherited fields should NOT be explicitly set
|
||||
self.assertNotIn(
|
||||
'start', new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
|
||||
)
|
||||
self.assertNotIn(
|
||||
'graded', new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
|
||||
)
|
||||
assert 'start' not in new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
|
||||
assert 'graded' not in new_version.get_explicitly_set_fields_by_scope(scope=Scope.settings)
|
||||
|
||||
def test_xblock_invalid_field_value_type(self):
|
||||
# Setting the wrong field-value in Xblock-field will raise TypeError.
|
||||
@@ -255,7 +239,7 @@ class RemapNamespaceTest(ModuleStoreNoSettings):
|
||||
# clearing the dirty fields and removing value from cache will fetch the value from field-data.
|
||||
self.xblock._dirty_fields = {} # pylint: disable=protected-access
|
||||
self.xblock.fields['test_content_field']._del_cached_value(self.xblock) # lint-amnesty, pylint: disable=protected-access, unsubscriptable-object
|
||||
with self.assertRaises(TypeError):
|
||||
with pytest.raises(TypeError):
|
||||
self.xblock.get_explicitly_set_fields_by_scope(scope=Scope.content)
|
||||
|
||||
|
||||
@@ -326,15 +310,15 @@ class UpdateLocationTest(ModuleStoreNoSettings):
|
||||
new_version = self.xblock # _update_module_location updates in-place
|
||||
|
||||
# Check the XBlock's location
|
||||
self.assertEqual(new_version.location, target_location)
|
||||
assert new_version.location == target_location
|
||||
|
||||
# Check the values of the fields.
|
||||
# The content, settings and children fields should be preserved
|
||||
self.assertEqual(new_version.test_content_field, 'Explicitly set')
|
||||
self.assertEqual(new_version.test_settings_field, 'Explicitly set')
|
||||
self.assertEqual(new_version.test_mutable_content_field, [1, 2, 3])
|
||||
self.assertEqual(new_version.test_mutable_settings_field, ["a", "s", "d"])
|
||||
self.assertEqual(new_version.children, self.fake_children_locations)
|
||||
assert new_version.test_content_field == 'Explicitly set'
|
||||
assert new_version.test_settings_field == 'Explicitly set'
|
||||
assert new_version.test_mutable_content_field == [1, 2, 3]
|
||||
assert new_version.test_mutable_settings_field == ['a', 's', 'd']
|
||||
assert new_version.children == self.fake_children_locations
|
||||
|
||||
# Expect that these fields are marked explicitly set
|
||||
self._check_explicitly_set(new_version, Scope.content, self.CONTENT_FIELDS, should_be_set=True)
|
||||
@@ -343,7 +327,7 @@ class UpdateLocationTest(ModuleStoreNoSettings):
|
||||
|
||||
# Expect these fields pass "is_set_on" test
|
||||
for field in self.CONTENT_FIELDS + self.SETTINGS_FIELDS + self.CHILDREN_FIELDS:
|
||||
self.assertTrue(new_version.fields[field].is_set_on(new_version)) # lint-amnesty, pylint: disable=unsubscriptable-object
|
||||
assert new_version.fields[field].is_set_on(new_version) # pylint: disable=unsubscriptable-object
|
||||
|
||||
|
||||
class StaticContentImporterTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
|
||||
@@ -6,6 +6,7 @@ Test the partitions and partitions service
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
import six
|
||||
from django.test import TestCase
|
||||
from mock import Mock, patch # lint-amnesty, pylint: disable=unused-import
|
||||
@@ -31,14 +32,14 @@ class TestGroup(TestCase):
|
||||
test_id = 10
|
||||
name = "Grendel"
|
||||
group = Group(test_id, name)
|
||||
self.assertEqual(group.id, test_id)
|
||||
self.assertEqual(group.name, name)
|
||||
assert group.id == test_id
|
||||
assert group.name == name
|
||||
|
||||
def test_string_id(self):
|
||||
test_id = "10"
|
||||
name = "Grendel"
|
||||
group = Group(test_id, name)
|
||||
self.assertEqual(group.id, 10)
|
||||
assert group.id == 10
|
||||
|
||||
def test_to_json(self):
|
||||
test_id = 10
|
||||
@@ -50,7 +51,7 @@ class TestGroup(TestCase):
|
||||
"name": name,
|
||||
"version": group.VERSION
|
||||
}
|
||||
self.assertEqual(jsonified, act_jsonified)
|
||||
assert jsonified == act_jsonified
|
||||
|
||||
def test_from_json(self):
|
||||
test_id = 5
|
||||
@@ -61,8 +62,8 @@ class TestGroup(TestCase):
|
||||
"version": Group.VERSION
|
||||
}
|
||||
group = Group.from_json(jsonified)
|
||||
self.assertEqual(group.id, test_id)
|
||||
self.assertEqual(group.name, name)
|
||||
assert group.id == test_id
|
||||
assert group.name == name
|
||||
|
||||
def test_from_json_broken(self):
|
||||
test_id = 5
|
||||
@@ -92,7 +93,7 @@ class TestGroup(TestCase):
|
||||
"programmer": "Cale"
|
||||
}
|
||||
group = Group.from_json(jsonified)
|
||||
self.assertNotIn("programmer", group.to_json())
|
||||
assert 'programmer' not in group.to_json()
|
||||
|
||||
|
||||
class MockUserPartitionScheme(object):
|
||||
@@ -192,12 +193,12 @@ class TestUserPartition(PartitionTestCase):
|
||||
MockUserPartitionScheme(),
|
||||
self.TEST_PARAMETERS,
|
||||
)
|
||||
self.assertEqual(user_partition.id, self.TEST_ID)
|
||||
self.assertEqual(user_partition.name, self.TEST_NAME)
|
||||
self.assertEqual(user_partition.description, self.TEST_DESCRIPTION)
|
||||
self.assertEqual(user_partition.groups, self.TEST_GROUPS)
|
||||
self.assertEqual(user_partition.scheme.name, self.TEST_SCHEME_NAME)
|
||||
self.assertEqual(user_partition.parameters, self.TEST_PARAMETERS)
|
||||
assert user_partition.id == self.TEST_ID
|
||||
assert user_partition.name == self.TEST_NAME
|
||||
assert user_partition.description == self.TEST_DESCRIPTION
|
||||
assert user_partition.groups == self.TEST_GROUPS
|
||||
assert user_partition.scheme.name == self.TEST_SCHEME_NAME
|
||||
assert user_partition.parameters == self.TEST_PARAMETERS
|
||||
|
||||
def test_string_id(self):
|
||||
user_partition = UserPartition(
|
||||
@@ -208,7 +209,7 @@ class TestUserPartition(PartitionTestCase):
|
||||
MockUserPartitionScheme(),
|
||||
self.TEST_PARAMETERS,
|
||||
)
|
||||
self.assertEqual(user_partition.id, 70)
|
||||
assert user_partition.id == 70
|
||||
|
||||
def test_to_json(self):
|
||||
jsonified = self.user_partition.to_json()
|
||||
@@ -222,7 +223,7 @@ class TestUserPartition(PartitionTestCase):
|
||||
"scheme": self.TEST_SCHEME_NAME,
|
||||
"active": True,
|
||||
}
|
||||
self.assertEqual(jsonified, act_jsonified)
|
||||
assert jsonified == act_jsonified
|
||||
|
||||
def test_from_json(self):
|
||||
jsonified = {
|
||||
@@ -235,16 +236,16 @@ class TestUserPartition(PartitionTestCase):
|
||||
"scheme": "mock",
|
||||
}
|
||||
user_partition = UserPartition.from_json(jsonified)
|
||||
self.assertEqual(user_partition.id, self.TEST_ID)
|
||||
self.assertEqual(user_partition.name, self.TEST_NAME)
|
||||
self.assertEqual(user_partition.description, self.TEST_DESCRIPTION)
|
||||
self.assertEqual(user_partition.parameters, self.TEST_PARAMETERS)
|
||||
assert user_partition.id == self.TEST_ID
|
||||
assert user_partition.name == self.TEST_NAME
|
||||
assert user_partition.description == self.TEST_DESCRIPTION
|
||||
assert user_partition.parameters == self.TEST_PARAMETERS
|
||||
|
||||
for act_group in user_partition.groups:
|
||||
self.assertIn(act_group.id, [0, 1])
|
||||
assert act_group.id in [0, 1]
|
||||
exp_group = self.TEST_GROUPS[act_group.id]
|
||||
self.assertEqual(exp_group.id, act_group.id)
|
||||
self.assertEqual(exp_group.name, act_group.name)
|
||||
assert exp_group.id == act_group.id
|
||||
assert exp_group.name == act_group.name
|
||||
|
||||
def test_version_upgrade(self):
|
||||
# Test that version 1 partitions did not have a scheme specified
|
||||
@@ -257,9 +258,9 @@ class TestUserPartition(PartitionTestCase):
|
||||
"version": 1,
|
||||
}
|
||||
user_partition = UserPartition.from_json(jsonified)
|
||||
self.assertEqual(user_partition.scheme.name, "random")
|
||||
self.assertEqual(user_partition.parameters, {})
|
||||
self.assertTrue(user_partition.active)
|
||||
assert user_partition.scheme.name == 'random'
|
||||
assert user_partition.parameters == {}
|
||||
assert user_partition.active
|
||||
|
||||
def test_version_upgrade_2_to_3(self):
|
||||
# Test that version 3 user partition raises error if 'scheme' field is
|
||||
@@ -287,9 +288,9 @@ class TestUserPartition(PartitionTestCase):
|
||||
"scheme": self.TEST_SCHEME_NAME,
|
||||
}
|
||||
user_partition = UserPartition.from_json(jsonified)
|
||||
self.assertEqual(user_partition.scheme.name, self.TEST_SCHEME_NAME)
|
||||
self.assertEqual(user_partition.parameters, {})
|
||||
self.assertTrue(user_partition.active)
|
||||
assert user_partition.scheme.name == self.TEST_SCHEME_NAME
|
||||
assert user_partition.parameters == {}
|
||||
assert user_partition.active
|
||||
|
||||
# now test that parameters dict is present in response with same value
|
||||
# as provided
|
||||
@@ -303,8 +304,8 @@ class TestUserPartition(PartitionTestCase):
|
||||
"scheme": self.TEST_SCHEME_NAME,
|
||||
}
|
||||
user_partition = UserPartition.from_json(jsonified)
|
||||
self.assertEqual(user_partition.parameters, self.TEST_PARAMETERS)
|
||||
self.assertTrue(user_partition.active)
|
||||
assert user_partition.parameters == self.TEST_PARAMETERS
|
||||
assert user_partition.active
|
||||
|
||||
def test_from_json_broken(self):
|
||||
# Missing field
|
||||
@@ -369,7 +370,7 @@ class TestUserPartition(PartitionTestCase):
|
||||
"programmer": "Cale",
|
||||
}
|
||||
user_partition = UserPartition.from_json(jsonified)
|
||||
self.assertNotIn("programmer", user_partition.to_json())
|
||||
assert 'programmer' not in user_partition.to_json()
|
||||
|
||||
# No error on missing parameters key (which is optional)
|
||||
jsonified = {
|
||||
@@ -381,7 +382,7 @@ class TestUserPartition(PartitionTestCase):
|
||||
"scheme": "mock",
|
||||
}
|
||||
user_partition = UserPartition.from_json(jsonified)
|
||||
self.assertEqual(user_partition.parameters, {})
|
||||
assert user_partition.parameters == {}
|
||||
|
||||
def test_get_group(self):
|
||||
"""
|
||||
@@ -389,15 +390,9 @@ class TestUserPartition(PartitionTestCase):
|
||||
`group_id` parameter, or raises NoSuchUserPartitionGroupError when
|
||||
the lookup fails.
|
||||
"""
|
||||
self.assertEqual(
|
||||
self.user_partition.get_group(self.TEST_GROUPS[0].id),
|
||||
self.TEST_GROUPS[0]
|
||||
)
|
||||
self.assertEqual(
|
||||
self.user_partition.get_group(self.TEST_GROUPS[1].id),
|
||||
self.TEST_GROUPS[1]
|
||||
)
|
||||
with self.assertRaises(NoSuchUserPartitionGroupError):
|
||||
assert self.user_partition.get_group(self.TEST_GROUPS[0].id) == self.TEST_GROUPS[0]
|
||||
assert self.user_partition.get_group(self.TEST_GROUPS[1].id) == self.TEST_GROUPS[1]
|
||||
with pytest.raises(NoSuchUserPartitionGroupError):
|
||||
self.user_partition.get_group(3)
|
||||
|
||||
def test_forward_compatibility(self):
|
||||
@@ -415,8 +410,8 @@ class TestUserPartition(PartitionTestCase):
|
||||
"additional_new_field": "foo",
|
||||
}
|
||||
partition = UserPartition.from_json(newer_version_json)
|
||||
self.assertEqual(partition.id, self.TEST_ID)
|
||||
self.assertEqual(partition.name, self.TEST_NAME)
|
||||
assert partition.id == self.TEST_ID
|
||||
assert partition.name == self.TEST_NAME
|
||||
|
||||
|
||||
class MockPartitionService(PartitionService):
|
||||
@@ -506,10 +501,7 @@ class TestPartitionService(PartitionServiceBaseClass):
|
||||
# Make sure our partition services all return the right thing, but skip
|
||||
# ps_shared_cache_2 so we can see if its cache got updated anyway.
|
||||
for part_svc in [ps_shared_cache_1, ps_diff_cache, ps_uncached]:
|
||||
self.assertEqual(
|
||||
first_group.id,
|
||||
part_svc.get_user_group_id_for_partition(self.user, user_partition_id)
|
||||
)
|
||||
assert first_group.id == part_svc.get_user_group_id_for_partition(self.user, user_partition_id)
|
||||
|
||||
# Now select a new target group
|
||||
second_group = self.user_partition.groups[1]
|
||||
@@ -519,23 +511,14 @@ class TestPartitionService(PartitionServiceBaseClass):
|
||||
# ps_shared_cache_2, which was never asked for the value the first time
|
||||
# Likewise, our separately cached piece should return the original answer
|
||||
for part_svc in [ps_shared_cache_1, ps_shared_cache_2, ps_diff_cache]:
|
||||
self.assertEqual(
|
||||
first_group.id,
|
||||
part_svc.get_user_group_id_for_partition(self.user, user_partition_id)
|
||||
)
|
||||
assert first_group.id == part_svc.get_user_group_id_for_partition(self.user, user_partition_id)
|
||||
|
||||
# Our uncached service should be accurate.
|
||||
self.assertEqual(
|
||||
second_group.id,
|
||||
ps_uncached.get_user_group_id_for_partition(self.user, user_partition_id)
|
||||
)
|
||||
assert second_group.id == ps_uncached.get_user_group_id_for_partition(self.user, user_partition_id)
|
||||
|
||||
# And a newly created service should see the right thing
|
||||
ps_new_cache = self._create_service(username, {})
|
||||
self.assertEqual(
|
||||
second_group.id,
|
||||
ps_new_cache.get_user_group_id_for_partition(self.user, user_partition_id)
|
||||
)
|
||||
assert second_group.id == ps_new_cache.get_user_group_id_for_partition(self.user, user_partition_id)
|
||||
|
||||
def test_get_group(self):
|
||||
"""
|
||||
@@ -546,12 +529,12 @@ class TestPartitionService(PartitionServiceBaseClass):
|
||||
# assign first group and verify that it is returned for the user
|
||||
self.user_partition.scheme.current_group = groups[0]
|
||||
group1 = self.partition_service.get_group(self.user, self.user_partition)
|
||||
self.assertEqual(group1, groups[0])
|
||||
assert group1 == groups[0]
|
||||
|
||||
# switch to the second group and verify that it is returned for the user
|
||||
self.user_partition.scheme.current_group = groups[1]
|
||||
group2 = self.partition_service.get_group(self.user, self.user_partition)
|
||||
self.assertEqual(group2, groups[1])
|
||||
assert group2 == groups[1]
|
||||
|
||||
|
||||
class TestGetCourseUserPartitions(PartitionServiceBaseClass):
|
||||
@@ -575,12 +558,12 @@ class TestGetCourseUserPartitions(PartitionServiceBaseClass):
|
||||
Test that the dynamic enrollment track scheme is added if there is no conflict with the user partition ID.
|
||||
"""
|
||||
all_partitions = get_all_partitions_for_course(self.course)
|
||||
self.assertEqual(2, len(all_partitions))
|
||||
self.assertEqual(self.TEST_SCHEME_NAME, all_partitions[0].scheme.name)
|
||||
assert 2 == len(all_partitions)
|
||||
assert self.TEST_SCHEME_NAME == all_partitions[0].scheme.name
|
||||
enrollment_track_partition = all_partitions[1]
|
||||
self.assertEqual(self.ENROLLMENT_TRACK_SCHEME_NAME, enrollment_track_partition.scheme.name)
|
||||
self.assertEqual(six.text_type(self.course.id), enrollment_track_partition.parameters['course_id'])
|
||||
self.assertEqual(ENROLLMENT_TRACK_PARTITION_ID, enrollment_track_partition.id)
|
||||
assert self.ENROLLMENT_TRACK_SCHEME_NAME == enrollment_track_partition.scheme.name
|
||||
assert six.text_type(self.course.id) == enrollment_track_partition.parameters['course_id']
|
||||
assert ENROLLMENT_TRACK_PARTITION_ID == enrollment_track_partition.id
|
||||
|
||||
def test_enrollment_track_partition_not_added_if_conflict(self):
|
||||
"""
|
||||
@@ -596,8 +579,8 @@ class TestGetCourseUserPartitions(PartitionServiceBaseClass):
|
||||
)
|
||||
self.course.user_partitions = [self.user_partition]
|
||||
all_partitions = get_all_partitions_for_course(self.course)
|
||||
self.assertEqual(1, len(all_partitions))
|
||||
self.assertEqual(self.TEST_SCHEME_NAME, all_partitions[0].scheme.name)
|
||||
assert 1 == len(all_partitions)
|
||||
assert self.TEST_SCHEME_NAME == all_partitions[0].scheme.name
|
||||
|
||||
def test_enrollment_track_partition_not_added_if_disabled(self):
|
||||
"""
|
||||
@@ -605,8 +588,8 @@ class TestGetCourseUserPartitions(PartitionServiceBaseClass):
|
||||
"""
|
||||
TestGetCourseUserPartitions._enable_enrollment_track_partition(False)
|
||||
all_partitions = get_all_partitions_for_course(self.course)
|
||||
self.assertEqual(1, len(all_partitions))
|
||||
self.assertEqual(self.TEST_SCHEME_NAME, all_partitions[0].scheme.name)
|
||||
assert 1 == len(all_partitions)
|
||||
assert self.TEST_SCHEME_NAME == all_partitions[0].scheme.name
|
||||
|
||||
def test_filter_inactive_user_partitions(self):
|
||||
"""
|
||||
@@ -624,10 +607,10 @@ class TestGetCourseUserPartitions(PartitionServiceBaseClass):
|
||||
self.course.user_partitions = [self.user_partition]
|
||||
|
||||
all_partitions = get_all_partitions_for_course(self.course, active_only=True)
|
||||
self.assertEqual(1, len(all_partitions))
|
||||
self.assertEqual(self.ENROLLMENT_TRACK_SCHEME_NAME, all_partitions[0].scheme.name)
|
||||
assert 1 == len(all_partitions)
|
||||
assert self.ENROLLMENT_TRACK_SCHEME_NAME == all_partitions[0].scheme.name
|
||||
|
||||
all_partitions = get_all_partitions_for_course(self.course, active_only=False)
|
||||
self.assertEqual(2, len(all_partitions))
|
||||
self.assertEqual(self.TEST_SCHEME_NAME, all_partitions[0].scheme.name)
|
||||
self.assertEqual(self.ENROLLMENT_TRACK_SCHEME_NAME, all_partitions[1].scheme.name)
|
||||
assert 2 == len(all_partitions)
|
||||
assert self.TEST_SCHEME_NAME == all_partitions[0].scheme.name
|
||||
assert self.ENROLLMENT_TRACK_SCHEME_NAME == all_partitions[1].scheme.name
|
||||
|
||||
@@ -187,7 +187,7 @@ class ModelsTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-cl
|
||||
def test_load_class(self):
|
||||
vc = XModuleDescriptor.load_class('sequential')
|
||||
vc_str = "<class 'xmodule.seq_module.SequenceDescriptor'>"
|
||||
self.assertEqual(str(vc), vc_str)
|
||||
assert str(vc) == vc_str
|
||||
|
||||
|
||||
class LogicTest(unittest.TestCase):
|
||||
@@ -307,24 +307,18 @@ class CourseComparisonTest(TestCase):
|
||||
elif isinstance(reference_field, ReferenceValueDict):
|
||||
expected = {key: extract_key(val) for (key, val) in six.iteritems(expected)}
|
||||
actual = {key: extract_key(val) for (key, val) in six.iteritems(actual)}
|
||||
self.assertEqual(
|
||||
expected,
|
||||
actual,
|
||||
LazyFormat(
|
||||
"Field {} doesn't match between usages {} and {}: {!r} != {!r}",
|
||||
reference_field.name,
|
||||
expected_block.scope_ids.usage_id,
|
||||
actual_block.scope_ids.usage_id,
|
||||
expected,
|
||||
actual
|
||||
)
|
||||
)
|
||||
assert expected == actual,\
|
||||
LazyFormat("Field {} doesn't match between usages {} and {}: {!r} != {!r}",
|
||||
reference_field.name,
|
||||
expected_block.scope_ids.usage_id,
|
||||
actual_block.scope_ids.usage_id,
|
||||
expected, actual)
|
||||
|
||||
def assertBlocksEqualByFields(self, expected_block, actual_block):
|
||||
"""
|
||||
Compare block fields to check for equivalence.
|
||||
"""
|
||||
self.assertEqual(expected_block.fields, actual_block.fields)
|
||||
assert expected_block.fields == actual_block.fields
|
||||
for field in expected_block.fields.values():
|
||||
self.assertFieldEqual(field, expected_block, actual_block)
|
||||
|
||||
@@ -337,18 +331,12 @@ class CourseComparisonTest(TestCase):
|
||||
else:
|
||||
expected = field.read_from(expected_block)
|
||||
actual = field.read_from(actual_block)
|
||||
self.assertEqual(
|
||||
expected,
|
||||
actual,
|
||||
LazyFormat(
|
||||
"Field {} doesn't match between usages {} and {}: {!r} != {!r}",
|
||||
field.name,
|
||||
expected_block.scope_ids.usage_id,
|
||||
actual_block.scope_ids.usage_id,
|
||||
expected,
|
||||
actual
|
||||
)
|
||||
)
|
||||
assert expected == actual,\
|
||||
LazyFormat("Field {} doesn't match between usages {} and {}: {!r} != {!r}",
|
||||
field.name,
|
||||
expected_block.scope_ids.usage_id,
|
||||
actual_block.scope_ids.usage_id,
|
||||
expected, actual)
|
||||
|
||||
def assertCoursesEqual(self, expected_store, expected_course_key, actual_store, actual_course_key):
|
||||
"""
|
||||
@@ -364,7 +352,7 @@ class CourseComparisonTest(TestCase):
|
||||
with actual_store.branch_setting(ModuleStoreEnum.Branch.published_only, actual_course_key):
|
||||
expected_items = expected_store.get_items(expected_course_key, revision=ModuleStoreEnum.RevisionOption.published_only) # lint-amnesty, pylint: disable=line-too-long
|
||||
actual_items = actual_store.get_items(actual_course_key, revision=ModuleStoreEnum.RevisionOption.published_only) # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertGreater(len(expected_items), 0)
|
||||
assert len(expected_items) > 0
|
||||
self._assertCoursesEqual(expected_items, actual_items, actual_course_key)
|
||||
|
||||
# if the modulestore supports having a draft branch
|
||||
@@ -389,7 +377,7 @@ class CourseComparisonTest(TestCase):
|
||||
Actual algorithm to compare courses.
|
||||
"""
|
||||
|
||||
self.assertEqual(len(expected_items), len(actual_items))
|
||||
assert len(expected_items) == len(actual_items)
|
||||
|
||||
def map_key(usage_key):
|
||||
return (usage_key.block_type, usage_key.block_id)
|
||||
@@ -416,11 +404,11 @@ class CourseComparisonTest(TestCase):
|
||||
actual_item_location = actual_item_location.replace(name='course')
|
||||
actual_item = actual_item_map.get(map_key(actual_item_location))
|
||||
# Formatting the message slows down tests of large courses significantly, so only do it if it would be used
|
||||
self.assertIn(map_key(actual_item_location), list(actual_item_map.keys()))
|
||||
assert map_key(actual_item_location) in list(actual_item_map.keys())
|
||||
if actual_item is None:
|
||||
continue
|
||||
# compare fields
|
||||
self.assertEqual(expected_item.fields, actual_item.fields)
|
||||
assert expected_item.fields == actual_item.fields
|
||||
for field_name, field in six.iteritems(expected_item.fields):
|
||||
if (expected_item.scope_ids.usage_id, field_name) in self.field_exclusions:
|
||||
continue
|
||||
@@ -431,7 +419,7 @@ class CourseComparisonTest(TestCase):
|
||||
continue
|
||||
self.assertFieldEqual(field, expected_item, actual_item)
|
||||
# compare children
|
||||
self.assertEqual(expected_item.has_children, actual_item.has_children)
|
||||
assert expected_item.has_children == actual_item.has_children
|
||||
if expected_item.has_children:
|
||||
expected_children = [
|
||||
(expected_item_child.location.block_type, expected_item_child.location.block_id)
|
||||
@@ -443,7 +431,7 @@ class CourseComparisonTest(TestCase):
|
||||
# get_children() rather than children to strip privates from public parents
|
||||
for item_child in actual_item.get_children()
|
||||
]
|
||||
self.assertEqual(expected_children, actual_children)
|
||||
assert expected_children == actual_children
|
||||
|
||||
def assertAssetEqual(self, expected_course_key, expected_asset, actual_course_key, actual_asset):
|
||||
"""
|
||||
@@ -457,20 +445,20 @@ class CourseComparisonTest(TestCase):
|
||||
|
||||
expected_key = expected_asset.pop('asset_key')
|
||||
actual_key = actual_asset.pop('asset_key')
|
||||
self.assertEqual(expected_key.map_into_course(actual_course_key), actual_key)
|
||||
self.assertEqual(expected_key, actual_key.map_into_course(expected_course_key))
|
||||
assert expected_key.map_into_course(actual_course_key) == actual_key
|
||||
assert expected_key == actual_key.map_into_course(expected_course_key)
|
||||
|
||||
expected_filename = expected_asset.pop('filename')
|
||||
actual_filename = actual_asset.pop('filename')
|
||||
self.assertEqual(text_type(expected_key), expected_filename)
|
||||
self.assertEqual(text_type(actual_key), actual_filename)
|
||||
self.assertEqual(expected_asset, actual_asset)
|
||||
assert text_type(expected_key) == expected_filename
|
||||
assert text_type(actual_key) == actual_filename
|
||||
assert expected_asset == actual_asset
|
||||
|
||||
def _assertAssetsEqual(self, expected_course_key, expected_assets, actual_course_key, actual_assets): # pylint: disable=invalid-name
|
||||
"""
|
||||
Private helper method for assertAssetsEqual
|
||||
"""
|
||||
self.assertEqual(len(expected_assets), len(actual_assets))
|
||||
assert len(expected_assets) == len(actual_assets)
|
||||
|
||||
actual_assets_map = {asset['asset_key']: asset for asset in actual_assets}
|
||||
for expected_item in expected_assets:
|
||||
@@ -486,7 +474,7 @@ class CourseComparisonTest(TestCase):
|
||||
expected_content, expected_count = expected_store.get_all_content_for_course(expected_course_key)
|
||||
actual_content, actual_count = actual_store.get_all_content_for_course(actual_course_key)
|
||||
|
||||
self.assertEqual(expected_count, actual_count)
|
||||
assert expected_count == actual_count
|
||||
self._assertAssetsEqual(expected_course_key, expected_content, actual_course_key, actual_content)
|
||||
expected_thumbs = expected_store.get_all_content_thumbnails_for_course(expected_course_key)
|
||||
actual_thumbs = actual_store.get_all_content_thumbnails_for_course(actual_course_key)
|
||||
@@ -503,10 +491,10 @@ class CourseComparisonTest(TestCase):
|
||||
actual_course_assets = actual_modulestore.get_all_asset_metadata(
|
||||
actual_course_key, None, sort=('displayname', ModuleStoreEnum.SortOrder.descending)
|
||||
)
|
||||
self.assertEqual(len(expected_course_assets), len(actual_course_assets))
|
||||
assert len(expected_course_assets) == len(actual_course_assets)
|
||||
for idx, __ in enumerate(expected_course_assets):
|
||||
for attr in AssetMetadata.ATTRS_ALLOWED_TO_UPDATE:
|
||||
if attr in ('edited_on',):
|
||||
# edited_on is updated upon import.
|
||||
continue
|
||||
self.assertEqual(getattr(expected_course_assets[idx], attr), getattr(actual_course_assets[idx], attr))
|
||||
assert getattr(expected_course_assets[idx], attr) == getattr(actual_course_assets[idx], attr)
|
||||
|
||||
@@ -51,7 +51,7 @@ class AnnotatableBlockTestCase(unittest.TestCase): # lint-amnesty, pylint: disa
|
||||
|
||||
actual_attr = self.annotatable._get_annotation_data_attr(0, el) # lint-amnesty, pylint: disable=protected-access
|
||||
|
||||
self.assertIsInstance(actual_attr, dict)
|
||||
assert isinstance(actual_attr, dict)
|
||||
self.assertDictEqual(expected_attr, actual_attr)
|
||||
|
||||
def test_annotation_class_attr_default(self):
|
||||
@@ -61,7 +61,7 @@ class AnnotatableBlockTestCase(unittest.TestCase): # lint-amnesty, pylint: disa
|
||||
expected_attr = {'class': {'value': 'annotatable-span highlight'}}
|
||||
actual_attr = self.annotatable._get_annotation_class_attr(0, el) # lint-amnesty, pylint: disable=protected-access
|
||||
|
||||
self.assertIsInstance(actual_attr, dict)
|
||||
assert isinstance(actual_attr, dict)
|
||||
self.assertDictEqual(expected_attr, actual_attr)
|
||||
|
||||
def test_annotation_class_attr_with_valid_highlight(self):
|
||||
@@ -79,7 +79,7 @@ class AnnotatableBlockTestCase(unittest.TestCase): # lint-amnesty, pylint: disa
|
||||
}
|
||||
actual_attr = self.annotatable._get_annotation_class_attr(0, el) # lint-amnesty, pylint: disable=protected-access
|
||||
|
||||
self.assertIsInstance(actual_attr, dict)
|
||||
assert isinstance(actual_attr, dict)
|
||||
self.assertDictEqual(expected_attr, actual_attr)
|
||||
|
||||
def test_annotation_class_attr_with_invalid_highlight(self):
|
||||
@@ -95,7 +95,7 @@ class AnnotatableBlockTestCase(unittest.TestCase): # lint-amnesty, pylint: disa
|
||||
}
|
||||
actual_attr = self.annotatable._get_annotation_class_attr(0, el) # lint-amnesty, pylint: disable=protected-access
|
||||
|
||||
self.assertIsInstance(actual_attr, dict)
|
||||
assert isinstance(actual_attr, dict)
|
||||
self.assertDictEqual(expected_attr, actual_attr)
|
||||
|
||||
def test_render_annotation(self):
|
||||
@@ -105,33 +105,33 @@ class AnnotatableBlockTestCase(unittest.TestCase): # lint-amnesty, pylint: disa
|
||||
actual_el = etree.fromstring('<annotation title="x" body="y" problem="0" highlight="yellow">z</annotation>')
|
||||
self.annotatable._render_annotation(0, actual_el) # lint-amnesty, pylint: disable=protected-access
|
||||
|
||||
self.assertEqual(expected_el.tag, actual_el.tag)
|
||||
self.assertEqual(expected_el.text, actual_el.text)
|
||||
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)
|
||||
|
||||
self.assertEqual('div', el.tag, 'root tag is a div')
|
||||
assert 'div' == el.tag, 'root tag is a div'
|
||||
|
||||
expected_num_annotations = 5
|
||||
actual_num_annotations = el.xpath('count(//span[contains(@class,"annotatable-span")])')
|
||||
self.assertEqual(expected_num_annotations, actual_num_annotations, 'check number of annotations')
|
||||
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']:
|
||||
self.assertIn(key, context)
|
||||
assert key in context
|
||||
|
||||
def test_extract_instructions(self):
|
||||
xmltree = etree.fromstring(self.sample_xml)
|
||||
|
||||
expected_xml = u"<div>Read the text.</div>"
|
||||
actual_xml = self.annotatable._extract_instructions(xmltree) # lint-amnesty, pylint: disable=protected-access
|
||||
self.assertIsNotNone(actual_xml)
|
||||
self.assertEqual(expected_xml.strip(), actual_xml.strip())
|
||||
assert actual_xml is not None
|
||||
assert expected_xml.strip() == actual_xml.strip()
|
||||
|
||||
xmltree = etree.fromstring('<annotatable>foo</annotatable>')
|
||||
actual = self.annotatable._extract_instructions(xmltree) # lint-amnesty, pylint: disable=protected-access
|
||||
self.assertIsNone(actual)
|
||||
assert actual is None
|
||||
|
||||
@@ -32,12 +32,12 @@ class HelperFunctionTest(unittest.TestCase):
|
||||
|
||||
expected_xml = u"<div><p>Helper Test Instructions.</p></div>"
|
||||
actual_xml = get_instructions(xmltree)
|
||||
self.assertIsNotNone(actual_xml)
|
||||
self.assertEqual(expected_xml.strip(), actual_xml.strip())
|
||||
assert actual_xml is not None
|
||||
assert expected_xml.strip() == actual_xml.strip()
|
||||
|
||||
xmltree = etree.fromstring('<annotatable>foo</annotatable>')
|
||||
actual = get_instructions(xmltree)
|
||||
self.assertIsNone(actual)
|
||||
assert actual is None
|
||||
|
||||
def test_get_extension(self):
|
||||
"""
|
||||
@@ -47,10 +47,10 @@ class HelperFunctionTest(unittest.TestCase):
|
||||
expectednotyoutube = 'video/mp4'
|
||||
result1 = get_extension(self.sample_sourceurl)
|
||||
result2 = get_extension(self.sample_youtubeurl)
|
||||
self.assertEqual(expectedyoutube, result2)
|
||||
self.assertEqual(expectednotyoutube, result1)
|
||||
assert expectedyoutube == result2
|
||||
assert expectednotyoutube == result1
|
||||
|
||||
def test_html_to_text(self):
|
||||
expectedtext = "Testing here and not bolded here"
|
||||
result = html_to_text(self.sample_html)
|
||||
self.assertEqual(expectedtext, result)
|
||||
assert expectedtext == result
|
||||
|
||||
@@ -12,6 +12,7 @@ import random
|
||||
import textwrap
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import requests
|
||||
import six
|
||||
@@ -194,22 +195,21 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
def test_import(self):
|
||||
module = CapaFactory.create()
|
||||
self.assertEqual(module.get_score().raw_earned, 0)
|
||||
assert module.get_score().raw_earned == 0
|
||||
|
||||
other_module = CapaFactory.create()
|
||||
self.assertEqual(module.get_score().raw_earned, 0)
|
||||
self.assertNotEqual(module.url_name, other_module.url_name,
|
||||
"Factory should be creating unique names for each problem")
|
||||
assert module.get_score().raw_earned == 0
|
||||
assert module.url_name != other_module.url_name, 'Factory should be creating unique names for each problem'
|
||||
|
||||
def test_correct(self):
|
||||
"""
|
||||
Check that the factory creates correct and incorrect problems properly.
|
||||
"""
|
||||
module = CapaFactory.create()
|
||||
self.assertEqual(module.get_score().raw_earned, 0)
|
||||
assert module.get_score().raw_earned == 0
|
||||
|
||||
other_module = CapaFactory.create(correct=True)
|
||||
self.assertEqual(other_module.get_score().raw_earned, 1)
|
||||
assert other_module.get_score().raw_earned == 1
|
||||
|
||||
def test_get_score(self):
|
||||
"""
|
||||
@@ -222,17 +222,17 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module = CapaFactory.create(correct=True, override_get_score=False)
|
||||
module.lcp.correct_map = correct_map
|
||||
module.lcp.student_answers = student_answers
|
||||
self.assertEqual(module.get_score().raw_earned, 0.0)
|
||||
assert module.get_score().raw_earned == 0.0
|
||||
module.set_score(module.score_from_lcp(module.lcp))
|
||||
self.assertEqual(module.get_score().raw_earned, 0.9)
|
||||
assert module.get_score().raw_earned == 0.9
|
||||
|
||||
other_correct_map = CorrectMap(answer_id='1_2_1', correctness="incorrect", npoints=0.1)
|
||||
other_module = CapaFactory.create(correct=False, override_get_score=False)
|
||||
other_module.lcp.correct_map = other_correct_map
|
||||
other_module.lcp.student_answers = student_answers
|
||||
self.assertEqual(other_module.get_score().raw_earned, 0.0)
|
||||
assert other_module.get_score().raw_earned == 0.0
|
||||
other_module.set_score(other_module.score_from_lcp(other_module.lcp))
|
||||
self.assertEqual(other_module.get_score().raw_earned, 0.1)
|
||||
assert other_module.get_score().raw_earned == 0.1
|
||||
|
||||
def test_showanswer_default(self):
|
||||
"""
|
||||
@@ -241,7 +241,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# default, no due date, showanswer 'closed', so problem is open, and show_answer
|
||||
# not visible.
|
||||
problem = CapaFactory.create()
|
||||
self.assertFalse(problem.answer_available())
|
||||
assert not problem.answer_available()
|
||||
|
||||
@ddt.data(
|
||||
(requests.exceptions.ReadTimeout, (1, 'failed to read from the server')),
|
||||
@@ -257,13 +257,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
with patch.object(xqueue_interface.session, 'post', side_effect=exception):
|
||||
# pylint: disable = protected-access
|
||||
response = xqueue_interface._http_post('http://some/fake/url', {})
|
||||
self.assertEqual(response, result)
|
||||
assert response == result
|
||||
|
||||
def test_showanswer_attempted(self):
|
||||
problem = CapaFactory.create(showanswer='attempted')
|
||||
self.assertFalse(problem.answer_available())
|
||||
assert not problem.answer_available()
|
||||
problem.attempts = 1
|
||||
self.assertTrue(problem.answer_available())
|
||||
assert problem.answer_available()
|
||||
|
||||
@ddt.data(
|
||||
# If show_correctness=always, Answer is visible after attempted
|
||||
@@ -285,9 +285,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
if 'due' in problem_data:
|
||||
problem_data['due'] = getattr(self, problem_data['due'])
|
||||
problem = CapaFactory.create(**problem_data)
|
||||
self.assertEqual(problem.answer_available(), answer_available_no_attempt)
|
||||
assert problem.answer_available() == answer_available_no_attempt
|
||||
problem.attempts = 1
|
||||
self.assertEqual(problem.answer_available(), answer_available_after_attempt)
|
||||
assert problem.answer_available() == answer_available_after_attempt
|
||||
|
||||
def test_showanswer_closed(self):
|
||||
|
||||
@@ -296,7 +296,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
max_attempts="1",
|
||||
attempts="1",
|
||||
due=self.tomorrow_str)
|
||||
self.assertTrue(used_all_attempts.answer_available())
|
||||
assert used_all_attempts.answer_available()
|
||||
|
||||
# can see after due date
|
||||
after_due_date = CapaFactory.create(showanswer='closed',
|
||||
@@ -304,14 +304,14 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts="0",
|
||||
due=self.yesterday_str)
|
||||
|
||||
self.assertTrue(after_due_date.answer_available())
|
||||
assert after_due_date.answer_available()
|
||||
|
||||
# can't see because attempts left
|
||||
attempts_left_open = CapaFactory.create(showanswer='closed',
|
||||
max_attempts="1",
|
||||
attempts="0",
|
||||
due=self.tomorrow_str)
|
||||
self.assertFalse(attempts_left_open.answer_available())
|
||||
assert not attempts_left_open.answer_available()
|
||||
|
||||
# Can't see because grace period hasn't expired
|
||||
still_in_grace = CapaFactory.create(showanswer='closed',
|
||||
@@ -319,7 +319,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts="0",
|
||||
due=self.yesterday_str,
|
||||
graceperiod=self.two_day_delta_str)
|
||||
self.assertFalse(still_in_grace.answer_available())
|
||||
assert not still_in_grace.answer_available()
|
||||
|
||||
def test_showanswer_correct_or_past_due(self):
|
||||
"""
|
||||
@@ -333,14 +333,14 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts="0",
|
||||
due=self.tomorrow_str,
|
||||
correct=True)
|
||||
self.assertTrue(answer_correct.answer_available())
|
||||
assert answer_correct.answer_available()
|
||||
|
||||
# can see after due date, even when answer isn't correct
|
||||
past_due_date = CapaFactory.create(showanswer='correct_or_past_due',
|
||||
max_attempts="1",
|
||||
attempts="0",
|
||||
due=self.yesterday_str)
|
||||
self.assertTrue(past_due_date.answer_available())
|
||||
assert past_due_date.answer_available()
|
||||
|
||||
# can also see after due date when answer _is_ correct
|
||||
past_due_date_correct = CapaFactory.create(showanswer='correct_or_past_due',
|
||||
@@ -348,7 +348,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts="0",
|
||||
due=self.yesterday_str,
|
||||
correct=True)
|
||||
self.assertTrue(past_due_date_correct.answer_available())
|
||||
assert past_due_date_correct.answer_available()
|
||||
|
||||
# Can't see because grace period hasn't expired and answer isn't correct
|
||||
still_in_grace = CapaFactory.create(showanswer='correct_or_past_due',
|
||||
@@ -356,7 +356,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts="1",
|
||||
due=self.yesterday_str,
|
||||
graceperiod=self.two_day_delta_str)
|
||||
self.assertFalse(still_in_grace.answer_available())
|
||||
assert not still_in_grace.answer_available()
|
||||
|
||||
def test_showanswer_past_due(self):
|
||||
"""
|
||||
@@ -369,21 +369,21 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
max_attempts="1",
|
||||
attempts="1",
|
||||
due=self.tomorrow_str)
|
||||
self.assertFalse(used_all_attempts.answer_available())
|
||||
assert not used_all_attempts.answer_available()
|
||||
|
||||
# can see after due date
|
||||
past_due_date = CapaFactory.create(showanswer='past_due',
|
||||
max_attempts="1",
|
||||
attempts="0",
|
||||
due=self.yesterday_str)
|
||||
self.assertTrue(past_due_date.answer_available())
|
||||
assert past_due_date.answer_available()
|
||||
|
||||
# can't see because attempts left
|
||||
attempts_left_open = CapaFactory.create(showanswer='past_due',
|
||||
max_attempts="1",
|
||||
attempts="0",
|
||||
due=self.tomorrow_str)
|
||||
self.assertFalse(attempts_left_open.answer_available())
|
||||
assert not attempts_left_open.answer_available()
|
||||
|
||||
# Can't see because grace period hasn't expired, even though have no more
|
||||
# attempts.
|
||||
@@ -392,7 +392,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts="1",
|
||||
due=self.yesterday_str,
|
||||
graceperiod=self.two_day_delta_str)
|
||||
self.assertFalse(still_in_grace.answer_available())
|
||||
assert not still_in_grace.answer_available()
|
||||
|
||||
def test_showanswer_after_attempts_with_max(self):
|
||||
"""
|
||||
@@ -408,7 +408,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts_before_showanswer_button='3',
|
||||
max_attempts='5',
|
||||
)
|
||||
self.assertFalse(problem.answer_available())
|
||||
assert not problem.answer_available()
|
||||
|
||||
def test_showanswer_after_attempts_no_max(self):
|
||||
"""
|
||||
@@ -423,7 +423,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts='2',
|
||||
attempts_before_showanswer_button='3',
|
||||
)
|
||||
self.assertFalse(problem.answer_available())
|
||||
assert not problem.answer_available()
|
||||
|
||||
def test_showanswer_after_attempts_used_all_attempts(self):
|
||||
"""
|
||||
@@ -440,7 +440,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts='3',
|
||||
due=self.tomorrow_str,
|
||||
)
|
||||
self.assertTrue(problem.answer_available())
|
||||
assert problem.answer_available()
|
||||
|
||||
def test_showanswer_after_attempts_past_due_date(self):
|
||||
"""
|
||||
@@ -455,7 +455,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts='2',
|
||||
due=self.yesterday_str,
|
||||
)
|
||||
self.assertTrue(problem.answer_available())
|
||||
assert problem.answer_available()
|
||||
|
||||
def test_showanswer_after_attempts_still_in_grace(self):
|
||||
"""
|
||||
@@ -471,7 +471,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
due=self.yesterday_str,
|
||||
graceperiod=self.two_day_delta_str,
|
||||
)
|
||||
self.assertTrue(problem.answer_available())
|
||||
assert problem.answer_available()
|
||||
|
||||
def test_showanswer_after_attempts_large(self):
|
||||
"""
|
||||
@@ -487,7 +487,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
max_attempts='3',
|
||||
attempts='3',
|
||||
)
|
||||
self.assertTrue(problem.answer_available())
|
||||
assert problem.answer_available()
|
||||
|
||||
def test_showanswer_after_attempts_zero(self):
|
||||
"""
|
||||
@@ -501,7 +501,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts_before_showanswer_button='0',
|
||||
attempts='0',
|
||||
)
|
||||
self.assertTrue(problem.answer_available())
|
||||
assert problem.answer_available()
|
||||
|
||||
def test_showanswer_finished(self):
|
||||
"""
|
||||
@@ -514,21 +514,21 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
max_attempts="1",
|
||||
attempts="1",
|
||||
due=self.tomorrow_str)
|
||||
self.assertTrue(used_all_attempts.answer_available())
|
||||
assert used_all_attempts.answer_available()
|
||||
|
||||
# can see after due date
|
||||
past_due_date = CapaFactory.create(showanswer='finished',
|
||||
max_attempts="1",
|
||||
attempts="0",
|
||||
due=self.yesterday_str)
|
||||
self.assertTrue(past_due_date.answer_available())
|
||||
assert past_due_date.answer_available()
|
||||
|
||||
# can't see because attempts left and wrong
|
||||
attempts_left_open = CapaFactory.create(showanswer='finished',
|
||||
max_attempts="1",
|
||||
attempts="0",
|
||||
due=self.tomorrow_str)
|
||||
self.assertFalse(attempts_left_open.answer_available())
|
||||
assert not attempts_left_open.answer_available()
|
||||
|
||||
# _can_ see because attempts left and right
|
||||
correct_ans = CapaFactory.create(showanswer='finished',
|
||||
@@ -536,7 +536,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts="0",
|
||||
due=self.tomorrow_str,
|
||||
correct=True)
|
||||
self.assertTrue(correct_ans.answer_available())
|
||||
assert correct_ans.answer_available()
|
||||
|
||||
# Can see even though grace period hasn't expired, because have no more
|
||||
# attempts.
|
||||
@@ -545,7 +545,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
attempts="1",
|
||||
due=self.yesterday_str,
|
||||
graceperiod=self.two_day_delta_str)
|
||||
self.assertTrue(still_in_grace.answer_available())
|
||||
assert still_in_grace.answer_available()
|
||||
|
||||
def test_showanswer_answered(self):
|
||||
"""
|
||||
@@ -560,7 +560,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
due=self.tomorrow_str,
|
||||
correct=False
|
||||
)
|
||||
self.assertFalse(answer_wrong.answer_available())
|
||||
assert not answer_wrong.answer_available()
|
||||
|
||||
# Expect to see "Show Answer" when answer is correct
|
||||
answer_correct = CapaFactory.create(
|
||||
@@ -570,7 +570,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
due=self.tomorrow_str,
|
||||
correct=True
|
||||
)
|
||||
self.assertTrue(answer_correct.answer_available())
|
||||
assert answer_correct.answer_available()
|
||||
|
||||
@ddt.data('', 'other-value')
|
||||
def test_show_correctness_other(self, show_correctness):
|
||||
@@ -579,21 +579,21 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
from SHOW_CORRECTNESS constant.
|
||||
"""
|
||||
problem = CapaFactory.create(show_correctness=show_correctness)
|
||||
self.assertTrue(problem.correctness_available())
|
||||
assert problem.correctness_available()
|
||||
|
||||
def test_show_correctness_default(self):
|
||||
"""
|
||||
Test that correctness is visible by default.
|
||||
"""
|
||||
problem = CapaFactory.create()
|
||||
self.assertTrue(problem.correctness_available())
|
||||
assert problem.correctness_available()
|
||||
|
||||
def test_show_correctness_never(self):
|
||||
"""
|
||||
Test that correctness is hidden when show_correctness turned off.
|
||||
"""
|
||||
problem = CapaFactory.create(show_correctness='never')
|
||||
self.assertFalse(problem.correctness_available())
|
||||
assert not problem.correctness_available()
|
||||
|
||||
@ddt.data(
|
||||
# Correctness not visible if due date in the future, even after using up all attempts
|
||||
@@ -616,34 +616,34 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
if 'graceperiod' in problem_data:
|
||||
problem_data['graceperiod'] = getattr(self, problem_data['graceperiod'])
|
||||
problem = CapaFactory.create(**problem_data)
|
||||
self.assertEqual(problem.correctness_available(), expected_result)
|
||||
assert problem.correctness_available() == expected_result
|
||||
|
||||
def test_closed(self):
|
||||
|
||||
# Attempts < Max attempts --> NOT closed
|
||||
module = CapaFactory.create(max_attempts="1", attempts="0")
|
||||
self.assertFalse(module.closed())
|
||||
assert not module.closed()
|
||||
|
||||
# Attempts < Max attempts --> NOT closed
|
||||
module = CapaFactory.create(max_attempts="2", attempts="1")
|
||||
self.assertFalse(module.closed())
|
||||
assert not module.closed()
|
||||
|
||||
# Attempts = Max attempts --> closed
|
||||
module = CapaFactory.create(max_attempts="1", attempts="1")
|
||||
self.assertTrue(module.closed())
|
||||
assert module.closed()
|
||||
|
||||
# Attempts > Max attempts --> closed
|
||||
module = CapaFactory.create(max_attempts="1", attempts="2")
|
||||
self.assertTrue(module.closed())
|
||||
assert module.closed()
|
||||
|
||||
# Max attempts = 0 --> closed
|
||||
module = CapaFactory.create(max_attempts="0", attempts="2")
|
||||
self.assertTrue(module.closed())
|
||||
assert module.closed()
|
||||
|
||||
# Past due --> closed
|
||||
module = CapaFactory.create(max_attempts="1", attempts="0",
|
||||
due=self.yesterday_str)
|
||||
self.assertTrue(module.closed())
|
||||
assert module.closed()
|
||||
|
||||
def test_parse_get_params(self):
|
||||
|
||||
@@ -664,25 +664,25 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# and that we get the same values back
|
||||
for key in result.keys(): # lint-amnesty, pylint: disable=consider-iterating-dictionary
|
||||
original_key = "input_" + key
|
||||
self.assertIn(original_key, valid_get_dict, "Output dict should have key %s" % original_key)
|
||||
self.assertEqual(valid_get_dict[original_key], result[key])
|
||||
assert original_key in valid_get_dict, ('Output dict should have key %s' % original_key)
|
||||
assert valid_get_dict[original_key] == result[key]
|
||||
|
||||
# Valid GET param dict with list keys
|
||||
# Each tuple represents a single parameter in the query string
|
||||
valid_get_dict = MultiDict((('input_2[]', 'test1'), ('input_2[]', 'test2')))
|
||||
result = ProblemBlock.make_dict_of_responses(valid_get_dict)
|
||||
self.assertIn('2', result)
|
||||
self.assertEqual(['test1', 'test2'], result['2'])
|
||||
assert '2' in result
|
||||
assert ['test1', 'test2'] == result['2']
|
||||
|
||||
# If we use [] at the end of a key name, we should always
|
||||
# get a list, even if there's just one value
|
||||
valid_get_dict = MultiDict({'input_1[]': 'test'})
|
||||
result = ProblemBlock.make_dict_of_responses(valid_get_dict)
|
||||
self.assertEqual(result['1'], ['test'])
|
||||
assert result['1'] == ['test']
|
||||
|
||||
# If we have no underscores in the name, then the key is invalid
|
||||
invalid_get_dict = MultiDict({'input': 'test'})
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
result = ProblemBlock.make_dict_of_responses(invalid_get_dict)
|
||||
|
||||
# Two equivalent names (one list, one non-list)
|
||||
@@ -690,7 +690,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# and raise an exception
|
||||
invalid_get_dict = MultiDict({'input_1[]': 'test 1',
|
||||
'input_1': 'test 2'})
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
result = ProblemBlock.make_dict_of_responses(invalid_get_dict)
|
||||
|
||||
def test_submit_problem_correct(self):
|
||||
@@ -710,15 +710,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem is marked correct
|
||||
self.assertEqual(result['success'], 'correct')
|
||||
assert result['success'] == 'correct'
|
||||
|
||||
# Expect that we get the (mocked) HTML
|
||||
self.assertEqual(result['contents'], 'Test HTML')
|
||||
assert result['contents'] == 'Test HTML'
|
||||
|
||||
# Expect that the number of attempts is incremented by 1
|
||||
self.assertEqual(module.attempts, 2)
|
||||
assert module.attempts == 2
|
||||
# and that this was considered attempt number 2 for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 2)
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
|
||||
def test_submit_problem_incorrect(self):
|
||||
|
||||
@@ -733,12 +733,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem is marked correct
|
||||
self.assertEqual(result['success'], 'incorrect')
|
||||
assert result['success'] == 'incorrect'
|
||||
|
||||
# Expect that the number of attempts is incremented by 1
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
# and that this is considered the first attempt
|
||||
self.assertEqual(module.lcp.context['attempt'], 1)
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
|
||||
def test_submit_problem_closed(self):
|
||||
module = CapaFactory.create(attempts=3)
|
||||
@@ -747,12 +747,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Simulate that ProblemBlock.closed() always returns True
|
||||
with patch('xmodule.capa_module.ProblemBlock.closed') as mock_closed:
|
||||
mock_closed.return_value = True
|
||||
with self.assertRaises(xmodule.exceptions.NotFoundError):
|
||||
with pytest.raises(xmodule.exceptions.NotFoundError):
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that number of attempts NOT incremented
|
||||
self.assertEqual(module.attempts, 3)
|
||||
assert module.attempts == 3
|
||||
|
||||
@ddt.data(
|
||||
RANDOMIZATION.ALWAYS,
|
||||
@@ -766,12 +766,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.done = True
|
||||
|
||||
# Expect that we cannot submit
|
||||
with self.assertRaises(xmodule.exceptions.NotFoundError):
|
||||
with pytest.raises(xmodule.exceptions.NotFoundError):
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that number of attempts NOT incremented
|
||||
self.assertEqual(module.attempts, 0)
|
||||
assert module.attempts == 0
|
||||
|
||||
@ddt.data(
|
||||
RANDOMIZATION.NEVER,
|
||||
@@ -786,11 +786,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
result = module.submit_problem(get_request_dict)
|
||||
|
||||
self.assertEqual(result['success'], 'correct')
|
||||
assert result['success'] == 'correct'
|
||||
|
||||
# Expect that number of attempts IS incremented, still same attempt
|
||||
self.assertEqual(module.attempts, 1)
|
||||
self.assertEqual(module.lcp.context['attempt'], 1)
|
||||
assert module.attempts == 1
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
|
||||
def test_submit_problem_queued(self):
|
||||
module = CapaFactory.create(attempts=1)
|
||||
@@ -809,10 +809,10 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success'
|
||||
self.assertIn('You must wait', result['success'])
|
||||
assert 'You must wait' in result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
|
||||
def test_submit_problem_with_files(self):
|
||||
# Check a problem with uploaded files, using the submit_problem API.
|
||||
@@ -859,11 +859,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# )
|
||||
# pylint: enable=line-too-long
|
||||
|
||||
self.assertEqual(xqueue_interface._http_post.call_count, 1)
|
||||
assert xqueue_interface._http_post.call_count == 1
|
||||
_, kwargs = xqueue_interface._http_post.call_args
|
||||
six.assertCountEqual(self, fpaths, list(kwargs['files'].keys()))
|
||||
for fpath, fileobj in six.iteritems(kwargs['files']):
|
||||
self.assertEqual(fpath, fileobj.name)
|
||||
assert fpath == fileobj.name
|
||||
|
||||
def test_submit_problem_with_files_as_xblock(self):
|
||||
# Check a problem with uploaded files, using the XBlock API.
|
||||
@@ -892,11 +892,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
module.handle('xmodule_handler', request, 'problem_check')
|
||||
|
||||
self.assertEqual(xqueue_interface._http_post.call_count, 1)
|
||||
assert xqueue_interface._http_post.call_count == 1
|
||||
_, kwargs = xqueue_interface._http_post.call_args
|
||||
six.assertCountEqual(self, fnames, list(kwargs['files'].keys()))
|
||||
for fpath, fileobj in six.iteritems(kwargs['files']):
|
||||
self.assertEqual(fpath, fileobj.name)
|
||||
assert fpath == fileobj.name
|
||||
|
||||
def test_submit_problem_error(self):
|
||||
|
||||
@@ -918,12 +918,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Expect an AJAX alert message in 'success'
|
||||
expected_msg = 'test error'
|
||||
|
||||
self.assertEqual(expected_msg, result['success'])
|
||||
assert expected_msg == result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
# but that this was considered attempt number 2 for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 2)
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
|
||||
def test_submit_problem_error_with_codejail_exception(self):
|
||||
|
||||
@@ -953,12 +953,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Expect an AJAX alert message in 'success' without the text of the stack trace
|
||||
expected_msg = 'Couldn\'t execute jailed code'
|
||||
self.assertEqual(expected_msg, result['success'])
|
||||
assert expected_msg == result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
# but that this was considered the second attempt for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 2)
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
|
||||
def test_submit_problem_other_errors(self):
|
||||
"""
|
||||
@@ -981,7 +981,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success'
|
||||
self.assertIn(error_msg, result['success'])
|
||||
assert error_msg in result['success']
|
||||
|
||||
def test_submit_problem_zero_max_grade(self):
|
||||
"""
|
||||
@@ -1017,12 +1017,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Expect an AJAX alert message in 'success'
|
||||
expected_msg = u'ȧƈƈḗƞŧḗḓ ŧḗẋŧ ƒǿř ŧḗşŧīƞɠ'
|
||||
|
||||
self.assertEqual(expected_msg, result['success'])
|
||||
assert expected_msg == result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
# but that this was considered the second attempt for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 2)
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
|
||||
def test_submit_problem_error_with_staff_user(self):
|
||||
|
||||
@@ -1041,15 +1041,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect an AJAX alert message in 'success'
|
||||
self.assertIn('test error', result['success'])
|
||||
assert 'test error' in result['success']
|
||||
|
||||
# We DO include traceback information for staff users
|
||||
self.assertIn('Traceback', result['success'])
|
||||
assert 'Traceback' in result['success']
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
# but that it was considered the second attempt for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 2)
|
||||
assert module.lcp.context['attempt'] == 2
|
||||
|
||||
@ddt.data(
|
||||
("never", True, None, 'submitted'),
|
||||
@@ -1075,12 +1075,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = json.loads(json_result)
|
||||
|
||||
# Expect that the AJAX result withholds correctness and score
|
||||
self.assertEqual(result['current_score'], expected_score)
|
||||
self.assertEqual(result['success'], expected_success)
|
||||
assert result['current_score'] == expected_score
|
||||
assert result['success'] == expected_success
|
||||
|
||||
# Expect that the number of attempts is incremented by 1
|
||||
self.assertEqual(module.attempts, 1)
|
||||
self.assertEqual(module.lcp.context['attempt'], 1)
|
||||
assert module.attempts == 1
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
|
||||
def test_reset_problem(self):
|
||||
module = CapaFactory.create(done=True)
|
||||
@@ -1096,11 +1096,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.reset_problem(get_request_dict)
|
||||
|
||||
# Expect that the request was successful
|
||||
self.assertTrue('success' in result and result['success'])
|
||||
assert (('success' in result) and result['success'])
|
||||
|
||||
# Expect that the problem HTML is retrieved
|
||||
self.assertIn('html', result)
|
||||
self.assertEqual(result['html'], "<div>Test HTML</div>")
|
||||
assert 'html' in result
|
||||
assert result['html'] == '<div>Test HTML</div>'
|
||||
|
||||
# Expect that the problem was reset
|
||||
module.new_lcp.assert_called_once_with(None)
|
||||
@@ -1118,7 +1118,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.reset_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem was NOT reset
|
||||
self.assertTrue('success' in result and not result['success'])
|
||||
assert (('success' in result) and (not result['success']))
|
||||
|
||||
def test_reset_problem_not_done(self):
|
||||
# Simulate that the problem is NOT done
|
||||
@@ -1129,7 +1129,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.reset_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem was NOT reset
|
||||
self.assertTrue('success' in result and not result['success'])
|
||||
assert (('success' in result) and (not result['success']))
|
||||
|
||||
def test_rescore_problem_correct(self):
|
||||
|
||||
@@ -1152,12 +1152,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.rescore(only_if_higher=False)
|
||||
|
||||
# Expect that the problem is marked correct
|
||||
self.assertEqual(module.is_correct(), True)
|
||||
assert module.is_correct() is True
|
||||
|
||||
# Expect that the number of attempts is not incremented
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
# and that this was considered attempt number 1 for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 1)
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
|
||||
def test_rescore_problem_additional_correct(self):
|
||||
# make sure it also works when new correct answer has been added
|
||||
@@ -1169,13 +1169,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that the problem is marked incorrect and user didn't earn score
|
||||
self.assertEqual(result['success'], 'incorrect')
|
||||
self.assertEqual(module.get_score(), (0, 1))
|
||||
self.assertEqual(module.correct_map[answer_id]['correctness'], 'incorrect')
|
||||
assert result['success'] == 'incorrect'
|
||||
assert module.get_score() == (0, 1)
|
||||
assert module.correct_map[answer_id]['correctness'] == 'incorrect'
|
||||
|
||||
# Expect that the number of attempts has incremented to 1
|
||||
self.assertEqual(module.attempts, 1)
|
||||
self.assertEqual(module.lcp.context['attempt'], 1)
|
||||
assert module.attempts == 1
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
|
||||
# Simulate that after making an incorrect answer to the correct answer
|
||||
# the new calculated score is (1,1)
|
||||
@@ -1191,12 +1191,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.rescore(only_if_higher=True)
|
||||
|
||||
# Expect that the problem is marked correct and user earned the score
|
||||
self.assertEqual(module.get_score(), (1, 1))
|
||||
self.assertEqual(module.correct_map[answer_id]['correctness'], 'correct')
|
||||
assert module.get_score() == (1, 1)
|
||||
assert module.correct_map[answer_id]['correctness'] == 'correct'
|
||||
# Expect that the number of attempts is not incremented
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
# and hence that this was still considered the first attempt for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 1)
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
|
||||
def test_rescore_problem_incorrect(self):
|
||||
# make sure it also works when attempts have been reset,
|
||||
@@ -1210,19 +1210,19 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.rescore(only_if_higher=False)
|
||||
|
||||
# Expect that the problem is marked incorrect
|
||||
self.assertEqual(module.is_correct(), False)
|
||||
assert module.is_correct() is False
|
||||
|
||||
# Expect that the number of attempts is not incremented
|
||||
self.assertEqual(module.attempts, 0)
|
||||
assert module.attempts == 0
|
||||
# and that this is treated as the first attempt for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 1)
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
|
||||
def test_rescore_problem_not_done(self):
|
||||
# Simulate that the problem is NOT done
|
||||
module = CapaFactory.create(done=False)
|
||||
|
||||
# Try to rescore the problem, and get exception
|
||||
with self.assertRaises(xmodule.exceptions.NotFoundError):
|
||||
with pytest.raises(xmodule.exceptions.NotFoundError):
|
||||
module.rescore(only_if_higher=False)
|
||||
|
||||
def test_rescore_problem_not_supported(self):
|
||||
@@ -1231,7 +1231,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Try to rescore the problem, and get exception
|
||||
with patch('capa.capa_problem.LoncapaProblem.supports_rescoring') as mock_supports_rescoring:
|
||||
mock_supports_rescoring.return_value = False
|
||||
with self.assertRaises(NotImplementedError):
|
||||
with pytest.raises(NotImplementedError):
|
||||
module.rescore(only_if_higher=False)
|
||||
|
||||
def _rescore_problem_error_helper(self, exception_class):
|
||||
@@ -1242,13 +1242,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Simulate answering a problem that raises the exception
|
||||
with patch('capa.capa_problem.LoncapaProblem.get_grade_from_current_answers') as mock_rescore:
|
||||
mock_rescore.side_effect = exception_class(u'test error \u03a9')
|
||||
with self.assertRaises(exception_class):
|
||||
with pytest.raises(exception_class):
|
||||
module.rescore(only_if_higher=False)
|
||||
|
||||
# Expect that the number of attempts is NOT incremented
|
||||
self.assertEqual(module.attempts, 1)
|
||||
assert module.attempts == 1
|
||||
# and that this was considered the first attempt for grading purposes
|
||||
self.assertEqual(module.lcp.context['attempt'], 1)
|
||||
assert module.lcp.context['attempt'] == 1
|
||||
|
||||
def test_rescore_problem_student_input_error(self):
|
||||
self._rescore_problem_error_helper(StudentInputError)
|
||||
@@ -1268,10 +1268,10 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# Expect that answers are saved to the problem
|
||||
expected_answers = {CapaFactory.answer_key(): '3.14'}
|
||||
self.assertEqual(module.lcp.student_answers, expected_answers)
|
||||
assert module.lcp.student_answers == expected_answers
|
||||
|
||||
# Expect that the result is success
|
||||
self.assertTrue('success' in result and result['success'])
|
||||
assert (('success' in result) and result['success'])
|
||||
|
||||
def test_save_problem_closed(self):
|
||||
module = CapaFactory.create(done=False)
|
||||
@@ -1285,7 +1285,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.save_problem(get_request_dict)
|
||||
|
||||
# Expect that the result is failure
|
||||
self.assertTrue('success' in result and not result['success'])
|
||||
assert (('success' in result) and (not result['success']))
|
||||
|
||||
@ddt.data(
|
||||
RANDOMIZATION.ALWAYS,
|
||||
@@ -1300,7 +1300,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.save_problem(get_request_dict)
|
||||
|
||||
# Expect that we cannot save
|
||||
self.assertTrue('success' in result and not result['success'])
|
||||
assert (('success' in result) and (not result['success']))
|
||||
|
||||
@ddt.data(
|
||||
RANDOMIZATION.NEVER,
|
||||
@@ -1316,15 +1316,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
result = module.save_problem(get_request_dict)
|
||||
|
||||
# Expect that we succeed
|
||||
self.assertTrue('success' in result and result['success'])
|
||||
assert (('success' in result) and result['success'])
|
||||
|
||||
def test_submit_button_name(self):
|
||||
module = CapaFactory.create(attempts=0)
|
||||
self.assertEqual(module.submit_button_name(), "Submit")
|
||||
assert module.submit_button_name() == 'Submit'
|
||||
|
||||
def test_submit_button_submitting_name(self):
|
||||
module = CapaFactory.create(attempts=1, max_attempts=10)
|
||||
self.assertEqual(module.submit_button_submitting_name(), "Submitting")
|
||||
assert module.submit_button_submitting_name() == 'Submitting'
|
||||
|
||||
def test_should_enable_submit_button(self):
|
||||
|
||||
@@ -1332,41 +1332,41 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# If we're after the deadline, disable the submit button
|
||||
module = CapaFactory.create(due=self.yesterday_str)
|
||||
self.assertFalse(module.should_enable_submit_button())
|
||||
assert not module.should_enable_submit_button()
|
||||
|
||||
# If user is out of attempts, disable the submit button
|
||||
module = CapaFactory.create(attempts=attempts, max_attempts=attempts)
|
||||
self.assertFalse(module.should_enable_submit_button())
|
||||
assert not module.should_enable_submit_button()
|
||||
|
||||
# If survey question (max_attempts = 0), disable the submit button
|
||||
module = CapaFactory.create(max_attempts=0)
|
||||
self.assertFalse(module.should_enable_submit_button())
|
||||
assert not module.should_enable_submit_button()
|
||||
|
||||
# If user submitted a problem but hasn't reset,
|
||||
# disable the submit button
|
||||
# Note: we can only reset when rerandomize="always" or "true"
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
self.assertFalse(module.should_enable_submit_button())
|
||||
assert not module.should_enable_submit_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize="true", done=True)
|
||||
self.assertFalse(module.should_enable_submit_button())
|
||||
assert not module.should_enable_submit_button()
|
||||
|
||||
# Otherwise, enable the submit button
|
||||
module = CapaFactory.create()
|
||||
self.assertTrue(module.should_enable_submit_button())
|
||||
assert module.should_enable_submit_button()
|
||||
|
||||
# If the user has submitted the problem
|
||||
# and we do NOT have a reset button, then we can enable the submit button
|
||||
# Setting rerandomize to "never" or "false" ensures that the reset button
|
||||
# is not shown
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, done=True)
|
||||
self.assertTrue(module.should_enable_submit_button())
|
||||
assert module.should_enable_submit_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize="false", done=True)
|
||||
self.assertTrue(module.should_enable_submit_button())
|
||||
assert module.should_enable_submit_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.PER_STUDENT, done=True)
|
||||
self.assertTrue(module.should_enable_submit_button())
|
||||
assert module.should_enable_submit_button()
|
||||
|
||||
def test_should_show_reset_button(self):
|
||||
|
||||
@@ -1374,43 +1374,43 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# If we're after the deadline, do NOT show the reset button
|
||||
module = CapaFactory.create(due=self.yesterday_str, done=True)
|
||||
self.assertFalse(module.should_show_reset_button())
|
||||
assert not module.should_show_reset_button()
|
||||
|
||||
# If the user is out of attempts, do NOT show the reset button
|
||||
module = CapaFactory.create(attempts=attempts, max_attempts=attempts, done=True)
|
||||
self.assertFalse(module.should_show_reset_button())
|
||||
assert not module.should_show_reset_button()
|
||||
|
||||
# pre studio default value, DO show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
self.assertTrue(module.should_show_reset_button())
|
||||
assert module.should_show_reset_button()
|
||||
|
||||
# If survey question for capa (max_attempts = 0),
|
||||
# DO show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True)
|
||||
self.assertTrue(module.should_show_reset_button())
|
||||
assert module.should_show_reset_button()
|
||||
|
||||
# If the question is not correct
|
||||
# DO show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True, correct=False)
|
||||
self.assertTrue(module.should_show_reset_button())
|
||||
assert module.should_show_reset_button()
|
||||
|
||||
# If the question is correct and randomization is never
|
||||
# DO not show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, max_attempts=0, done=True, correct=True)
|
||||
self.assertFalse(module.should_show_reset_button())
|
||||
assert not module.should_show_reset_button()
|
||||
|
||||
# If the question is correct and randomization is always
|
||||
# Show the reset button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, max_attempts=0, done=True, correct=True)
|
||||
self.assertTrue(module.should_show_reset_button())
|
||||
assert module.should_show_reset_button()
|
||||
|
||||
# Don't show reset button if randomization is turned on and the question is not done
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, show_reset_button=False, done=False)
|
||||
self.assertFalse(module.should_show_reset_button())
|
||||
assert not module.should_show_reset_button()
|
||||
|
||||
# Show reset button if randomization is turned on and the problem is done
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, show_reset_button=False, done=True)
|
||||
self.assertTrue(module.should_show_reset_button())
|
||||
assert module.should_show_reset_button()
|
||||
|
||||
def test_should_show_save_button(self):
|
||||
|
||||
@@ -1418,49 +1418,49 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# If we're after the deadline, do NOT show the save button
|
||||
module = CapaFactory.create(due=self.yesterday_str, done=True)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
# If the user is out of attempts, do NOT show the save button
|
||||
module = CapaFactory.create(attempts=attempts, max_attempts=attempts, done=True)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
# If user submitted a problem but hasn't reset, do NOT show the save button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=True)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize="true", done=True)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
# If the user has unlimited attempts and we are not randomizing,
|
||||
# then do NOT show a save button
|
||||
# because they can keep using "Check"
|
||||
module = CapaFactory.create(max_attempts=None, rerandomize=RANDOMIZATION.NEVER, done=False)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(max_attempts=None, rerandomize="false", done=True)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(max_attempts=None, rerandomize=RANDOMIZATION.PER_STUDENT, done=True)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
# pre-studio default, DO show the save button
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.ALWAYS, done=False)
|
||||
self.assertTrue(module.should_show_save_button())
|
||||
assert module.should_show_save_button()
|
||||
|
||||
# If we're not randomizing and we have limited attempts, then we can save
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.NEVER, max_attempts=2, done=True)
|
||||
self.assertTrue(module.should_show_save_button())
|
||||
assert module.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize="false", max_attempts=2, done=True)
|
||||
self.assertTrue(module.should_show_save_button())
|
||||
assert module.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(rerandomize=RANDOMIZATION.PER_STUDENT, max_attempts=2, done=True)
|
||||
self.assertTrue(module.should_show_save_button())
|
||||
assert module.should_show_save_button()
|
||||
|
||||
# If survey question for capa (max_attempts = 0),
|
||||
# DO show the save button
|
||||
module = CapaFactory.create(max_attempts=0, done=False)
|
||||
self.assertTrue(module.should_show_save_button())
|
||||
assert module.should_show_save_button()
|
||||
|
||||
def test_should_show_save_button_force_save_button(self):
|
||||
# If we're after the deadline, do NOT show the save button
|
||||
@@ -1468,7 +1468,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module = CapaFactory.create(due=self.yesterday_str,
|
||||
force_save_button="true",
|
||||
done=True)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
# If the user is out of attempts, do NOT show the save button
|
||||
attempts = random.randint(1, 10)
|
||||
@@ -1476,7 +1476,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
max_attempts=attempts,
|
||||
force_save_button="true",
|
||||
done=True)
|
||||
self.assertFalse(module.should_show_save_button())
|
||||
assert not module.should_show_save_button()
|
||||
|
||||
# Otherwise, if we force the save button,
|
||||
# then show it even if we would ordinarily
|
||||
@@ -1484,17 +1484,17 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module = CapaFactory.create(force_save_button="true",
|
||||
rerandomize=RANDOMIZATION.ALWAYS,
|
||||
done=True)
|
||||
self.assertTrue(module.should_show_save_button())
|
||||
assert module.should_show_save_button()
|
||||
|
||||
module = CapaFactory.create(force_save_button="true",
|
||||
rerandomize="true",
|
||||
done=True)
|
||||
self.assertTrue(module.should_show_save_button())
|
||||
assert module.should_show_save_button()
|
||||
|
||||
def test_no_max_attempts(self):
|
||||
module = CapaFactory.create(max_attempts='')
|
||||
html = module.get_problem_html()
|
||||
self.assertIsNotNone(html)
|
||||
assert html is not None
|
||||
# assert that we got here without exploding
|
||||
|
||||
def test_get_problem_html(self):
|
||||
@@ -1524,24 +1524,24 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
html_encapsulated = module.get_problem_html(encapsulate=True)
|
||||
|
||||
# Expect that we get the rendered template back
|
||||
self.assertEqual(html, "<div>Test Template HTML</div>")
|
||||
assert html == '<div>Test Template HTML</div>'
|
||||
|
||||
# Check the rendering context
|
||||
render_args, _ = module.system.render_template.call_args
|
||||
self.assertEqual(len(render_args), 2)
|
||||
assert len(render_args) == 2
|
||||
|
||||
template_name = render_args[0]
|
||||
self.assertEqual(template_name, "problem.html")
|
||||
assert template_name == 'problem.html'
|
||||
|
||||
context = render_args[1]
|
||||
self.assertEqual(context['problem']['html'], "<div>Test Problem HTML</div>")
|
||||
self.assertEqual(bool(context['should_enable_submit_button']), enable_submit_button)
|
||||
self.assertEqual(bool(context['reset_button']), show_reset_button)
|
||||
self.assertEqual(bool(context['save_button']), show_save_button)
|
||||
self.assertFalse(context['demand_hint_possible'])
|
||||
assert context['problem']['html'] == '<div>Test Problem HTML</div>'
|
||||
assert bool(context['should_enable_submit_button']) == enable_submit_button
|
||||
assert bool(context['reset_button']) == show_reset_button
|
||||
assert bool(context['save_button']) == show_save_button
|
||||
assert not context['demand_hint_possible']
|
||||
|
||||
# Assert that the encapsulated html contains the original html
|
||||
self.assertIn(html, html_encapsulated)
|
||||
assert html in html_encapsulated
|
||||
|
||||
demand_xml = """
|
||||
<problem>
|
||||
@@ -1565,21 +1565,21 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module = CapaFactory.create(xml=self.demand_xml)
|
||||
module.get_problem_html() # ignoring html result
|
||||
context = module.system.render_template.call_args[0][1]
|
||||
self.assertTrue(context['demand_hint_possible'])
|
||||
self.assertTrue(context['should_enable_next_hint'])
|
||||
assert context['demand_hint_possible']
|
||||
assert context['should_enable_next_hint']
|
||||
|
||||
# Check the AJAX call that gets the hint by index
|
||||
result = module.get_demand_hint(0)
|
||||
self.assertEqual(result['hint_index'], 0)
|
||||
self.assertTrue(result['should_enable_next_hint'])
|
||||
assert result['hint_index'] == 0
|
||||
assert result['should_enable_next_hint']
|
||||
|
||||
result = module.get_demand_hint(1)
|
||||
self.assertEqual(result['hint_index'], 1)
|
||||
self.assertFalse(result['should_enable_next_hint'])
|
||||
assert result['hint_index'] == 1
|
||||
assert not result['should_enable_next_hint']
|
||||
|
||||
result = module.get_demand_hint(2) # here the server wraps around to index 0
|
||||
self.assertEqual(result['hint_index'], 0)
|
||||
self.assertTrue(result['should_enable_next_hint'])
|
||||
assert result['hint_index'] == 0
|
||||
assert result['should_enable_next_hint']
|
||||
|
||||
def test_single_demand_hint(self):
|
||||
"""
|
||||
@@ -1602,13 +1602,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module = CapaFactory.create(xml=test_xml)
|
||||
module.get_problem_html() # ignoring html result
|
||||
context = module.system.render_template.call_args[0][1]
|
||||
self.assertTrue(context['demand_hint_possible'])
|
||||
self.assertTrue(context['should_enable_next_hint'])
|
||||
assert context['demand_hint_possible']
|
||||
assert context['should_enable_next_hint']
|
||||
|
||||
# Check the AJAX call that gets the hint by index
|
||||
result = module.get_demand_hint(0)
|
||||
self.assertEqual(result['hint_index'], 0)
|
||||
self.assertFalse(result['should_enable_next_hint'])
|
||||
assert result['hint_index'] == 0
|
||||
assert not result['should_enable_next_hint']
|
||||
|
||||
def test_image_hint(self):
|
||||
"""
|
||||
@@ -1633,13 +1633,13 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module = CapaFactory.create(xml=test_xml)
|
||||
module.get_problem_html() # ignoring html result
|
||||
context = module.system.render_template.call_args[0][1]
|
||||
self.assertTrue(context['demand_hint_possible'])
|
||||
self.assertTrue(context['should_enable_next_hint'])
|
||||
assert context['demand_hint_possible']
|
||||
assert context['should_enable_next_hint']
|
||||
|
||||
# Check the AJAX call that gets the hint by index
|
||||
result = module.get_demand_hint(0)
|
||||
self.assertEqual(result['hint_index'], 0)
|
||||
self.assertFalse(result['should_enable_next_hint'])
|
||||
assert result['hint_index'] == 0
|
||||
assert not result['should_enable_next_hint']
|
||||
|
||||
def test_demand_hint_logging(self):
|
||||
def mock_location_text(self): # lint-amnesty, pylint: disable=unused-argument
|
||||
@@ -1671,12 +1671,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
|
||||
# check to make sure that the input_state and the keys have the same values
|
||||
module1.set_state_from_lcp()
|
||||
self.assertEqual(list(module1.lcp.inputs.keys()), list(module1.input_state.keys()))
|
||||
assert list(module1.lcp.inputs.keys()) == list(module1.input_state.keys())
|
||||
|
||||
module2.set_state_from_lcp()
|
||||
|
||||
intersection = set(module2.input_state.keys()).intersection(set(module1.input_state.keys()))
|
||||
self.assertEqual(len(intersection), 0)
|
||||
assert len(intersection) == 0
|
||||
|
||||
def test_get_problem_html_error(self):
|
||||
"""
|
||||
@@ -1702,15 +1702,15 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Try to render the module with DEBUG turned off
|
||||
html = module.get_problem_html()
|
||||
|
||||
self.assertIsNotNone(html)
|
||||
assert html is not None
|
||||
|
||||
# Check the rendering context
|
||||
render_args, _ = module.system.render_template.call_args
|
||||
context = render_args[1]
|
||||
self.assertIn("error", context['problem']['html'])
|
||||
assert 'error' in context['problem']['html']
|
||||
|
||||
# Expect that the module has created a new dummy problem with the error
|
||||
self.assertNotEqual(original_problem, module.lcp)
|
||||
assert original_problem != module.lcp
|
||||
|
||||
def test_get_problem_html_error_w_debug(self):
|
||||
"""
|
||||
@@ -1732,12 +1732,12 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Try to render the module with DEBUG turned on
|
||||
html = module.get_problem_html()
|
||||
|
||||
self.assertIsNotNone(html)
|
||||
assert html is not None
|
||||
|
||||
# Check the rendering context
|
||||
render_args, _ = module.system.render_template.call_args
|
||||
context = render_args[1]
|
||||
self.assertIn(error_msg, context['problem']['html'])
|
||||
assert error_msg in context['problem']['html']
|
||||
|
||||
@ddt.data(
|
||||
'false',
|
||||
@@ -1756,26 +1756,25 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Get the seed
|
||||
# By this point, the module should have persisted the seed
|
||||
seed = module.seed
|
||||
self.assertIsNotNone(seed)
|
||||
assert seed is not None
|
||||
|
||||
# If we're not rerandomizing, the seed is always set
|
||||
# to the same value (1)
|
||||
if rerandomize == RANDOMIZATION.NEVER:
|
||||
self.assertEqual(seed, 1,
|
||||
msg="Seed should always be 1 when rerandomize='%s'" % rerandomize)
|
||||
assert seed == 1, "Seed should always be 1 when rerandomize='%s'" % rerandomize
|
||||
|
||||
# Check the problem
|
||||
get_request_dict = {CapaFactory.input_key(): '3.14'}
|
||||
module.submit_problem(get_request_dict)
|
||||
|
||||
# Expect that the seed is the same
|
||||
self.assertEqual(seed, module.seed)
|
||||
assert seed == module.seed
|
||||
|
||||
# Save the problem
|
||||
module.save_problem(get_request_dict)
|
||||
|
||||
# Expect that the seed is the same
|
||||
self.assertEqual(seed, module.seed)
|
||||
assert seed == module.seed
|
||||
|
||||
@ddt.data(
|
||||
'false',
|
||||
@@ -1827,7 +1826,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Get the seed
|
||||
# By this point, the module should have persisted the seed
|
||||
seed = module.seed
|
||||
self.assertIsNotNone(seed)
|
||||
assert seed is not None
|
||||
|
||||
# We do NOT want the seed to reset if rerandomize
|
||||
# is set to 'never' -- it should still be 1
|
||||
@@ -1836,7 +1835,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
if rerandomize in [RANDOMIZATION.NEVER,
|
||||
'false',
|
||||
RANDOMIZATION.PER_STUDENT]:
|
||||
self.assertEqual(seed, _reset_and_get_seed(module))
|
||||
assert seed == _reset_and_get_seed(module)
|
||||
|
||||
# Otherwise, we expect the seed to change
|
||||
# to another valid seed
|
||||
@@ -1847,9 +1846,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# to generate a different seed
|
||||
success = _retry_and_check(10, lambda: _reset_and_get_seed(module) != seed)
|
||||
|
||||
self.assertIsNotNone(module.seed)
|
||||
assert module.seed is not None
|
||||
msg = 'Could not get a new seed from reset after 10 tries'
|
||||
self.assertTrue(success, msg)
|
||||
assert success, msg
|
||||
|
||||
@ddt.data(
|
||||
'false',
|
||||
@@ -1881,10 +1880,10 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
# Get the seed
|
||||
# By this point, the module should have persisted the seed
|
||||
seed = module.seed
|
||||
self.assertIsNotNone(seed)
|
||||
assert seed is not None
|
||||
|
||||
# the seed should never change because the student hasn't finished the problem
|
||||
self.assertEqual(seed, _reset_and_get_seed(module))
|
||||
assert seed == _reset_and_get_seed(module)
|
||||
|
||||
@ddt.data(
|
||||
RANDOMIZATION.ALWAYS,
|
||||
@@ -1911,7 +1910,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
for error_type in error_types:
|
||||
mock_progress.side_effect = error_type
|
||||
module = CapaFactory.create()
|
||||
self.assertIsNone(module.get_progress())
|
||||
assert module.get_progress() is None
|
||||
mock_log.exception.assert_called_once_with('Got bad progress')
|
||||
mock_log.reset_mock()
|
||||
|
||||
@@ -1924,8 +1923,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module = CapaFactory.create()
|
||||
module.weight = 0
|
||||
progress = module.get_progress()
|
||||
self.assertIsNone(progress)
|
||||
self.assertFalse(mock_progress.called)
|
||||
assert progress is None
|
||||
assert not mock_progress.called
|
||||
|
||||
@patch('xmodule.capa_base.Progress')
|
||||
def test_get_progress_calculate_progress_fraction(self, mock_progress):
|
||||
@@ -1960,8 +1959,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
due=self.tomorrow_str)
|
||||
module.weight = 1
|
||||
score, total = module.get_display_progress()
|
||||
self.assertEqual(score, expected_score)
|
||||
self.assertEqual(total, 1)
|
||||
assert score == expected_score
|
||||
assert total == 1
|
||||
|
||||
def test_get_html(self):
|
||||
"""
|
||||
@@ -1977,7 +1976,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
Check that get_problem() returns the expected dictionary.
|
||||
"""
|
||||
module = CapaFactory.create()
|
||||
self.assertEqual(module.get_problem("data"), {'html': module.get_problem_html(encapsulate=False)})
|
||||
assert module.get_problem('data') == {'html': module.get_problem_html(encapsulate=False)}
|
||||
|
||||
# Standard question with shuffle="true" used by a few tests
|
||||
common_shuffle_xml = textwrap.dedent("""
|
||||
@@ -2004,11 +2003,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.submit_problem(get_request_dict)
|
||||
mock_call = mock_track_function.mock_calls[1]
|
||||
event_info = mock_call[1][2]
|
||||
self.assertEqual(event_info['answers'][CapaFactory.answer_key()], 'choice_3')
|
||||
assert event_info['answers'][CapaFactory.answer_key()] == 'choice_3'
|
||||
# 'permutation' key added to record how problem was shown
|
||||
self.assertEqual(event_info['permutation'][CapaFactory.answer_key()],
|
||||
('shuffle', ['choice_3', 'choice_1', 'choice_2', 'choice_0']))
|
||||
self.assertEqual(event_info['success'], 'correct')
|
||||
assert event_info['permutation'][CapaFactory.answer_key()] ==\
|
||||
('shuffle', ['choice_3', 'choice_1', 'choice_2', 'choice_0'])
|
||||
assert event_info['success'] == 'correct'
|
||||
|
||||
@unittest.skip("masking temporarily disabled")
|
||||
def test_save_unmask(self):
|
||||
@@ -2019,8 +2018,8 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.save_problem(get_request_dict)
|
||||
mock_call = mock_track_function.mock_calls[0]
|
||||
event_info = mock_call[1][1]
|
||||
self.assertEqual(event_info['answers'][CapaFactory.answer_key()], 'choice_2')
|
||||
self.assertIsNotNone(event_info['permutation'][CapaFactory.answer_key()])
|
||||
assert event_info['answers'][CapaFactory.answer_key()] == 'choice_2'
|
||||
assert event_info['permutation'][CapaFactory.answer_key()] is not None
|
||||
|
||||
@unittest.skip("masking temporarily disabled")
|
||||
def test_reset_unmask(self):
|
||||
@@ -2033,9 +2032,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.reset_problem(None)
|
||||
mock_call = mock_track_function.mock_calls[0]
|
||||
event_info = mock_call[1][1]
|
||||
self.assertEqual(mock_call[1][0], 'reset_problem')
|
||||
self.assertEqual(event_info['old_state']['student_answers'][CapaFactory.answer_key()], 'choice_2')
|
||||
self.assertIsNotNone(event_info['permutation'][CapaFactory.answer_key()])
|
||||
assert mock_call[1][0] == 'reset_problem'
|
||||
assert event_info['old_state']['student_answers'][CapaFactory.answer_key()] == 'choice_2'
|
||||
assert event_info['permutation'][CapaFactory.answer_key()] is not None
|
||||
|
||||
@unittest.skip("masking temporarily disabled")
|
||||
def test_rescore_unmask(self):
|
||||
@@ -2048,9 +2047,9 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.rescore_problem(only_if_higher=False) # lint-amnesty, pylint: disable=no-member
|
||||
mock_call = mock_track_function.mock_calls[0]
|
||||
event_info = mock_call[1][1]
|
||||
self.assertEqual(mock_call[1][0], 'problem_rescore')
|
||||
self.assertEqual(event_info['state']['student_answers'][CapaFactory.answer_key()], 'choice_2')
|
||||
self.assertIsNotNone(event_info['permutation'][CapaFactory.answer_key()])
|
||||
assert mock_call[1][0] == 'problem_rescore'
|
||||
assert event_info['state']['student_answers'][CapaFactory.answer_key()] == 'choice_2'
|
||||
assert event_info['permutation'][CapaFactory.answer_key()] is not None
|
||||
|
||||
def test_check_unmask_answerpool(self):
|
||||
"""Check answer-pool question track_function uses unmasked names"""
|
||||
@@ -2072,11 +2071,11 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.submit_problem(get_request_dict)
|
||||
mock_call = mock_track_function.mock_calls[1]
|
||||
event_info = mock_call[1][2]
|
||||
self.assertEqual(event_info['answers'][CapaFactory.answer_key()], 'choice_2')
|
||||
assert event_info['answers'][CapaFactory.answer_key()] == 'choice_2'
|
||||
# 'permutation' key added to record how problem was shown
|
||||
self.assertEqual(event_info['permutation'][CapaFactory.answer_key()],
|
||||
('answerpool', ['choice_1', 'choice_3', 'choice_2', 'choice_0']))
|
||||
self.assertEqual(event_info['success'], 'incorrect')
|
||||
assert event_info['permutation'][CapaFactory.answer_key()] ==\
|
||||
('answerpool', ['choice_1', 'choice_3', 'choice_2', 'choice_0'])
|
||||
assert event_info['success'] == 'incorrect'
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -2090,7 +2089,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
Verify that display_name_with_default works as expected.
|
||||
"""
|
||||
module = CapaFactory.create(display_name=display_name)
|
||||
self.assertEqual(module.display_name_with_default, expected_display_name)
|
||||
assert module.display_name_with_default == expected_display_name
|
||||
|
||||
@ddt.data(
|
||||
'',
|
||||
@@ -2104,7 +2103,7 @@ class ProblemBlockTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
module.get_problem_html()
|
||||
render_args, _ = module.system.render_template.call_args
|
||||
context = render_args[1]
|
||||
self.assertEqual(context['problem']['name'], module.location.block_type)
|
||||
assert context['problem']['name'] == module.location.block_type
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -2476,15 +2475,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
xml = "<problem><{response_tag}></{response_tag}></problem>".format(response_tag=response_tag)
|
||||
name = "Some Capa Problem"
|
||||
descriptor = self._create_descriptor(xml, name=name)
|
||||
self.assertEqual(descriptor.problem_types, {response_tag})
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': [response_tag],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': ''
|
||||
}
|
||||
})
|
||||
assert descriptor.problem_types == {response_tag}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': [response_tag],
|
||||
'content': {'display_name': name, 'capa_content': ''}}
|
||||
|
||||
def test_response_types_ignores_non_response_tags(self):
|
||||
xml = textwrap.dedent("""
|
||||
@@ -2503,15 +2498,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
""")
|
||||
name = "Test Capa Problem"
|
||||
descriptor = self._create_descriptor(xml, name=name)
|
||||
self.assertEqual(descriptor.problem_types, {"multiplechoiceresponse"})
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["multiplechoiceresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': ' Label Some comment Apple Banana Chocolate Donut '
|
||||
}
|
||||
})
|
||||
assert descriptor.problem_types == {'multiplechoiceresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['multiplechoiceresponse'],
|
||||
'content': {'display_name': name, 'capa_content': ' Label Some comment Apple Banana Chocolate Donut '}}
|
||||
|
||||
def test_response_types_multiple_tags(self):
|
||||
xml = textwrap.dedent("""
|
||||
@@ -2535,7 +2526,7 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
""")
|
||||
name = "Other Test Capa Problem"
|
||||
descriptor = self._create_descriptor(xml, name=name)
|
||||
self.assertEqual(descriptor.problem_types, {"multiplechoiceresponse", "optionresponse"})
|
||||
assert descriptor.problem_types == {'multiplechoiceresponse', 'optionresponse'}
|
||||
|
||||
# We are converting problem_types to a set to compare it later without taking into account the order
|
||||
# the reasoning behind is that the problem_types (property) is represented by dict and when it is converted
|
||||
@@ -2580,16 +2571,10 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
""")
|
||||
name = "Blank Common Capa Problem"
|
||||
descriptor = self._create_descriptor(xml, name=name)
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': [],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': ' '
|
||||
}
|
||||
}
|
||||
)
|
||||
'content': {'display_name': name, 'capa_content': ' '}}
|
||||
|
||||
def test_indexing_checkboxes(self):
|
||||
name = "Checkboxes"
|
||||
@@ -2606,18 +2591,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
Hungarian
|
||||
Note: Make sure you select all of the correct options—there may be more than one!
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"choiceresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(),
|
||||
{
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["choiceresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'choiceresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['choiceresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_dropdown(self):
|
||||
name = "Dropdown"
|
||||
@@ -2628,17 +2606,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
You can use the following example problem as a model.
|
||||
Which of the following countries celebrates its independence on August 15? 'India','Spain','China','Bermuda'
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"optionresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["optionresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'optionresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['optionresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_multiple_choice(self):
|
||||
name = "Multiple Choice"
|
||||
@@ -2653,17 +2625,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
Indonesia
|
||||
Russia
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"multiplechoiceresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["multiplechoiceresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'multiplechoiceresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['multiplechoiceresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_numerical_input(self):
|
||||
name = "Numerical Input"
|
||||
@@ -2681,17 +2647,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
How many miles away from Earth is the sun? Use scientific notation to answer.
|
||||
The square of what number is -100?
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"numericalresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["numericalresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'numericalresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['numericalresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_text_input(self):
|
||||
name = "Text Input"
|
||||
@@ -2706,17 +2666,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
You can use the following example problem as a model.
|
||||
What was the first post-secondary school in China to allow both male and female students?
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"stringresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["stringresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'stringresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['stringresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_non_latin_problem(self):
|
||||
sample_text_input_problem_xml = textwrap.dedent("""
|
||||
@@ -2730,9 +2684,7 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
capa_content = " FX1_VAL='Καλημέρα' Δοκιμή με μεταβλητές με Ελληνικούς χαρακτήρες μέσα σε python: $FX1_VAL "
|
||||
|
||||
descriptor_dict = descriptor.index_dictionary()
|
||||
self.assertEqual(
|
||||
descriptor_dict['content']['capa_content'], smart_text(capa_content)
|
||||
)
|
||||
assert descriptor_dict['content']['capa_content'] == smart_text(capa_content)
|
||||
|
||||
def test_indexing_checkboxes_with_hints_and_feedback(self):
|
||||
name = "Checkboxes with Hints and Feedback"
|
||||
@@ -2752,17 +2704,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
potato
|
||||
tomato
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"choiceresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["choiceresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'choiceresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['choiceresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_dropdown_with_hints_and_feedback(self):
|
||||
name = "Dropdown with Hints and Feedback"
|
||||
@@ -2778,17 +2724,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
potato
|
||||
tomato
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"optionresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["optionresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'optionresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['optionresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_multiple_choice_with_hints_and_feedback(self):
|
||||
name = "Multiple Choice with Hints and Feedback"
|
||||
@@ -2804,17 +2744,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
potato
|
||||
tomato
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"multiplechoiceresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["multiplechoiceresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'multiplechoiceresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['multiplechoiceresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_numerical_input_with_hints_and_feedback(self):
|
||||
name = "Numerical Input with Hints and Feedback"
|
||||
@@ -2828,17 +2762,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
Use the following example problem as a model.
|
||||
What is the arithmetic mean for the following set of numbers? (1, 5, 6, 3, 5)
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"numericalresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["numericalresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'numericalresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['numericalresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_text_input_with_hints_and_feedback(self):
|
||||
name = "Text Input with Hints and Feedback"
|
||||
@@ -2852,17 +2780,11 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
Use the following example problem as a model.
|
||||
Which U.S. state has the largest land area?
|
||||
""")
|
||||
self.assertEqual(descriptor.problem_types, {"stringresponse"})
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ["stringresponse"],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
assert descriptor.problem_types == {'stringresponse'}
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': ['stringresponse'],
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_indexing_problem_with_html_tags(self):
|
||||
sample_problem_xml = textwrap.dedent("""
|
||||
@@ -2885,16 +2807,10 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
This has HTML comment in it.
|
||||
HTML end.
|
||||
""")
|
||||
self.assertEqual(
|
||||
descriptor.index_dictionary(), {
|
||||
'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content_type': ProblemBlock.INDEX_CONTENT_TYPE,
|
||||
'problem_types': [],
|
||||
'content': {
|
||||
'display_name': name,
|
||||
'capa_content': capa_content.replace("\n", " ")
|
||||
}
|
||||
}
|
||||
)
|
||||
'content': {'display_name': name, 'capa_content': capa_content.replace('\n', ' ')}}
|
||||
|
||||
def test_invalid_xml_handling(self):
|
||||
"""
|
||||
@@ -2905,7 +2821,7 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
<problem>
|
||||
</proble-oh no my finger broke and I can't close the problem tag properly...
|
||||
""")
|
||||
with self.assertRaises(etree.XMLSyntaxError):
|
||||
with pytest.raises(etree.XMLSyntaxError):
|
||||
self._create_descriptor(sample_invalid_xml, name="Invalid XML")
|
||||
|
||||
def test_invalid_dropdown_xml(self):
|
||||
@@ -2915,7 +2831,8 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
problem_xml = textwrap.dedent("""
|
||||
<problem>
|
||||
<optionresponse>
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for dropdown problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<p>You can use this template as a guide to the simple editor markdown and OLX markup to use for dropdown
|
||||
problems. Edit this component to replace this template with your own assessment.</p>
|
||||
<label>Add the question text, or prompt, here. This text is required.</label>
|
||||
<description>You can add an optional tip or note related to the prompt like this. </description>
|
||||
<optioninput>
|
||||
@@ -2926,7 +2843,7 @@ class ProblemBlockXMLTest(unittest.TestCase): # lint-amnesty, pylint: disable=m
|
||||
</optionresponse>
|
||||
</problem>
|
||||
""")
|
||||
with self.assertRaises(Exception):
|
||||
with pytest.raises(Exception):
|
||||
CapaFactory.create(xml=problem_xml)
|
||||
|
||||
|
||||
@@ -2939,7 +2856,8 @@ class ComplexEncoderTest(unittest.TestCase): # lint-amnesty, pylint: disable=mi
|
||||
complex_num = 1 - 1j
|
||||
expected_str = '1-1*j'
|
||||
json_str = json.dumps(complex_num, cls=ComplexEncoder)
|
||||
self.assertEqual(expected_str, json_str[1:-1]) # ignore quotes
|
||||
assert expected_str == json_str[1:(- 1)]
|
||||
# ignore quotes
|
||||
|
||||
|
||||
class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
@@ -2993,35 +2911,27 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
}
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
|
||||
self.assertEqual(event['submission'], {
|
||||
factory.answer_key(2): {
|
||||
'question': 'What color is the open ocean on a sunny day?',
|
||||
'answer': 'blue',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'variant': '',
|
||||
},
|
||||
factory.answer_key(3): {
|
||||
'question': 'Which piece of furniture is built for sitting?',
|
||||
'answer': u'<text>a table</text>',
|
||||
'response_type': 'multiplechoiceresponse',
|
||||
'input_type': 'choicegroup',
|
||||
'correct': False,
|
||||
'group_label': '',
|
||||
'variant': '',
|
||||
},
|
||||
factory.answer_key(4): {
|
||||
'question': 'Which of the following are musical instruments?',
|
||||
'answer': [u'a piano', u'a tree'],
|
||||
'response_type': 'choiceresponse',
|
||||
'input_type': 'checkboxgroup',
|
||||
'correct': False,
|
||||
'group_label': '',
|
||||
'variant': '',
|
||||
},
|
||||
})
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2): {'question': 'What color is the open ocean on a sunny day?',
|
||||
'answer': 'blue', 'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'variant': ''},
|
||||
factory.answer_key(3): {'question': 'Which piece of furniture is built for sitting?',
|
||||
'answer': u'<text>a table</text>',
|
||||
'response_type': 'multiplechoiceresponse',
|
||||
'input_type': 'choicegroup',
|
||||
'correct': False,
|
||||
'group_label': '',
|
||||
'variant': ''},
|
||||
factory.answer_key(4): {'question': 'Which of the following are musical instruments?',
|
||||
'answer': [u'a piano', u'a tree'],
|
||||
'response_type': 'choiceresponse',
|
||||
'input_type': 'checkboxgroup',
|
||||
'correct': False,
|
||||
'group_label': '',
|
||||
'variant': ''}}
|
||||
|
||||
def capa_factory_for_problem_xml(self, xml): # lint-amnesty, pylint: disable=missing-function-docstring
|
||||
class CustomCapaFactory(CapaFactory):
|
||||
@@ -3036,7 +2946,7 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
with patch.object(module.runtime, 'publish') as mock_track_function:
|
||||
module.submit_problem(answer_input_dict)
|
||||
|
||||
self.assertGreaterEqual(len(mock_track_function.mock_calls), 2)
|
||||
assert len(mock_track_function.mock_calls) >= 2
|
||||
# There are potentially 2 track logs: answers and hint. [-1]=answers.
|
||||
mock_call = mock_track_function.mock_calls[-1]
|
||||
event = mock_call[1][2]
|
||||
@@ -3052,17 +2962,13 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
self.assertEqual(event['submission'], {
|
||||
factory.answer_key(2): {
|
||||
'question': '',
|
||||
'answer': '3.14',
|
||||
'response_type': 'numericalresponse',
|
||||
'input_type': 'textline',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'variant': '',
|
||||
}
|
||||
})
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2): {'question': '', 'answer': '3.14',
|
||||
'response_type': 'numericalresponse',
|
||||
'input_type': 'textline',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'variant': ''}}
|
||||
|
||||
def test_multiple_inputs(self):
|
||||
group_label = 'Choose the correct color'
|
||||
@@ -3084,26 +2990,19 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
self.assertEqual(event['submission'], {
|
||||
factory.answer_key(2, 1): {
|
||||
'group_label': group_label,
|
||||
'question': input1_label,
|
||||
'answer': 'blue',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': True,
|
||||
'variant': '',
|
||||
},
|
||||
factory.answer_key(2, 2): {
|
||||
'group_label': group_label,
|
||||
'question': input2_label,
|
||||
'answer': 'yellow',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': False,
|
||||
'variant': '',
|
||||
},
|
||||
})
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2, 1): {'group_label': group_label,
|
||||
'question': input1_label,
|
||||
'answer': 'blue',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': True, 'variant': ''},
|
||||
factory.answer_key(2, 2): {'group_label': group_label,
|
||||
'question': input2_label,
|
||||
'answer': 'yellow',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': False, 'variant': ''}}
|
||||
|
||||
def test_optioninput_extended_xml(self):
|
||||
"""Test the new XML form of writing with <option> tag instead of options= attribute."""
|
||||
@@ -3154,26 +3053,19 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
self.assertEqual(event['submission'], {
|
||||
factory.answer_key(2, 1): {
|
||||
'group_label': group_label,
|
||||
'question': input1_label,
|
||||
'answer': 'apple',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': True,
|
||||
'variant': '',
|
||||
},
|
||||
factory.answer_key(2, 2): {
|
||||
'group_label': group_label,
|
||||
'question': input2_label,
|
||||
'answer': 'cucumber',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': False,
|
||||
'variant': '',
|
||||
},
|
||||
})
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2, 1): {'group_label': group_label,
|
||||
'question': input1_label,
|
||||
'answer': 'apple',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': True, 'variant': ''},
|
||||
factory.answer_key(2, 2): {'group_label': group_label,
|
||||
'question': input2_label,
|
||||
'answer': 'cucumber',
|
||||
'response_type': 'optionresponse',
|
||||
'input_type': 'optioninput',
|
||||
'correct': False, 'variant': ''}}
|
||||
|
||||
def test_rerandomized_inputs(self):
|
||||
factory = CapaFactory
|
||||
@@ -3184,17 +3076,14 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
self.assertEqual(event['submission'], {
|
||||
factory.answer_key(2): {
|
||||
'question': '',
|
||||
'answer': '3.14',
|
||||
'response_type': 'numericalresponse',
|
||||
'input_type': 'textline',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'variant': module.seed,
|
||||
}
|
||||
})
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2): {'question': '',
|
||||
'answer': '3.14',
|
||||
'response_type': 'numericalresponse',
|
||||
'input_type': 'textline',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'variant': module.seed}}
|
||||
|
||||
def test_file_inputs(self):
|
||||
fnames = ["prog1.py", "prog2.py", "prog3.py"]
|
||||
@@ -3217,26 +3106,21 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
}
|
||||
|
||||
event = self.get_event_for_answers(module, answer_input_dict)
|
||||
self.assertEqual(event['submission'], {
|
||||
factory.answer_key(2): {
|
||||
'question': '',
|
||||
'answer': fpaths,
|
||||
'response_type': 'coderesponse',
|
||||
'input_type': 'filesubmission',
|
||||
'correct': False,
|
||||
'group_label': '',
|
||||
'variant': '',
|
||||
},
|
||||
factory.answer_key(3): {
|
||||
'answer': 'None',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'question': '',
|
||||
'response_type': 'customresponse',
|
||||
'input_type': 'textline',
|
||||
'variant': ''
|
||||
}
|
||||
})
|
||||
assert event['submission'] ==\
|
||||
{factory.answer_key(2): {'question': '',
|
||||
'answer': fpaths,
|
||||
'response_type': 'coderesponse',
|
||||
'input_type': 'filesubmission',
|
||||
'correct': False,
|
||||
'group_label': '',
|
||||
'variant': ''},
|
||||
factory.answer_key(3): {'answer': 'None',
|
||||
'correct': True,
|
||||
'group_label': '',
|
||||
'question': '',
|
||||
'response_type': 'customresponse',
|
||||
'input_type': 'textline',
|
||||
'variant': ''}}
|
||||
|
||||
def test_get_answer_with_jump_to_id_urls(self):
|
||||
"""
|
||||
@@ -3262,7 +3146,7 @@ class ProblemCheckTrackingTest(unittest.TestCase):
|
||||
problem = CapaFactory.create(showanswer='always', xml=problem_xml)
|
||||
problem.runtime.replace_jump_to_id_urls = Mock()
|
||||
problem.get_answer(data)
|
||||
self.assertTrue(problem.runtime.replace_jump_to_id_urls.called)
|
||||
assert problem.runtime.replace_jump_to_id_urls.called
|
||||
|
||||
|
||||
class ProblemBlockReportGenerationTest(unittest.TestCase):
|
||||
@@ -3314,13 +3198,13 @@ class ProblemBlockReportGenerationTest(unittest.TestCase):
|
||||
def test_generate_report_data_not_implemented(self):
|
||||
scope_ids = Mock(block_type='noproblem')
|
||||
descriptor = ProblemBlock(get_test_system(), scope_ids=scope_ids)
|
||||
with self.assertRaises(NotImplementedError):
|
||||
with pytest.raises(NotImplementedError):
|
||||
next(descriptor.generate_report_data(iter([])))
|
||||
|
||||
def test_generate_report_data_limit_responses(self):
|
||||
descriptor = self._get_descriptor()
|
||||
report_data = list(descriptor.generate_report_data(self._mock_user_state_generator(), 2))
|
||||
self.assertEqual(2, len(report_data))
|
||||
assert 2 == len(report_data)
|
||||
|
||||
def test_generate_report_data_dont_limit_responses(self):
|
||||
descriptor = self._get_descriptor()
|
||||
@@ -3332,10 +3216,10 @@ class ProblemBlockReportGenerationTest(unittest.TestCase):
|
||||
response_count=response_count,
|
||||
)
|
||||
))
|
||||
self.assertEqual(user_count * response_count, len(report_data))
|
||||
assert (user_count * response_count) == len(report_data)
|
||||
|
||||
def test_generate_report_data_skip_dynamath(self):
|
||||
descriptor = self._get_descriptor()
|
||||
iterator = iter([self._user_state(suffix='_dynamath')])
|
||||
report_data = list(descriptor.generate_report_data(iterator))
|
||||
self.assertEqual(0, len(report_data))
|
||||
assert 0 == len(report_data)
|
||||
|
||||
@@ -159,7 +159,7 @@ class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
for icon_class in ['other', 'problem', 'video']:
|
||||
modules['source_module'].is_attempted = attempted
|
||||
modules['child_module'].get_icon_class = lambda: icon_class # lint-amnesty, pylint: disable=cell-var-from-loop
|
||||
self.assertEqual(modules['cond_module'].get_icon_class(), icon_class)
|
||||
assert modules['cond_module'].get_icon_class() == icon_class
|
||||
|
||||
def test_get_html(self):
|
||||
modules = ConditionalFactory.create(self.test_system)
|
||||
@@ -171,7 +171,7 @@ class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
'element_id': u'i4x-edX-conditional_test-conditional-SampleConditional',
|
||||
'depends': u'i4x-edX-conditional_test-problem-SampleProblem',
|
||||
})
|
||||
self.assertEqual(expected, html)
|
||||
assert expected == html
|
||||
|
||||
def test_handle_ajax(self):
|
||||
modules = ConditionalFactory.create(self.test_system)
|
||||
@@ -180,7 +180,7 @@ class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
ajax = json.loads(modules['cond_module'].handle_ajax('', ''))
|
||||
print("ajax: ", ajax)
|
||||
fragments = ajax['fragments']
|
||||
self.assertFalse(any(['This is a secret' in item['content'] for item in fragments]))
|
||||
assert not any([('This is a secret' in item['content']) for item in fragments])
|
||||
|
||||
# now change state of the capa problem to make it completed
|
||||
modules['source_module'].is_attempted = "true"
|
||||
@@ -188,7 +188,7 @@ class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
modules['cond_module'].save()
|
||||
print("post-attempt ajax: ", ajax)
|
||||
fragments = ajax['fragments']
|
||||
self.assertTrue(any(['This is a secret' in item['content'] for item in fragments]))
|
||||
assert any([('This is a secret' in item['content']) for item in fragments])
|
||||
|
||||
def test_error_as_source(self):
|
||||
'''
|
||||
@@ -199,7 +199,7 @@ class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
modules['cond_module'].save()
|
||||
ajax = json.loads(modules['cond_module'].handle_ajax('', ''))
|
||||
fragments = ajax['fragments']
|
||||
self.assertFalse(any(['This is a secret' in item['content'] for item in fragments]))
|
||||
assert not any([('This is a secret' in item['content']) for item in fragments])
|
||||
|
||||
@patch('xmodule.conditional_module.log')
|
||||
def test_conditional_with_staff_only_source_module(self, mock_log):
|
||||
@@ -211,8 +211,8 @@ class ConditionalBlockBasicTest(unittest.TestCase):
|
||||
cond_module.save()
|
||||
cond_module.is_attempted = "false"
|
||||
cond_module.handle_ajax('', '')
|
||||
self.assertFalse(mock_log.warn.called)
|
||||
self.assertIn(None, cond_module.get_required_blocks)
|
||||
assert not mock_log.warn.called
|
||||
assert None in cond_module.get_required_blocks
|
||||
|
||||
|
||||
class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
@@ -236,7 +236,7 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
modulestore = XMLModuleStore(DATA_DIR, source_dirs=[name])
|
||||
courses = modulestore.get_courses()
|
||||
self.modulestore = modulestore # lint-amnesty, pylint: disable=attribute-defined-outside-init
|
||||
self.assertEqual(len(courses), 1)
|
||||
assert len(courses) == 1
|
||||
return courses[0]
|
||||
|
||||
@patch('xmodule.x_module.descriptor_global_local_resource_url')
|
||||
@@ -285,7 +285,7 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
'depends': u'i4x-HarvardX-ER22x-problem-choiceprob'
|
||||
}
|
||||
)
|
||||
self.assertEqual(html, html_expect)
|
||||
assert html == html_expect
|
||||
|
||||
gdi = module.get_display_items()
|
||||
print("gdi=", gdi)
|
||||
@@ -294,7 +294,7 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
module.save()
|
||||
print("ajax: ", ajax)
|
||||
fragments = ajax['fragments']
|
||||
self.assertFalse(any(['This is a secret' in item['content'] for item in fragments]))
|
||||
assert not any([('This is a secret' in item['content']) for item in fragments])
|
||||
|
||||
# Now change state of the capa problem to make it completed
|
||||
inner_module = inner_get_module(location.replace(category="problem", name='choiceprob'))
|
||||
@@ -306,7 +306,7 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
module.save()
|
||||
print("post-attempt ajax: ", ajax)
|
||||
fragments = ajax['fragments']
|
||||
self.assertTrue(any(['This is a secret' in item['content'] for item in fragments]))
|
||||
assert any([('This is a secret' in item['content']) for item in fragments])
|
||||
|
||||
maxDiff = None
|
||||
|
||||
@@ -331,12 +331,8 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
new_run = conditional.location.course_key.run # lint-amnesty, pylint: disable=unused-variable
|
||||
self.assertEqual(
|
||||
conditional.sources_list[0],
|
||||
BlockUsageLocator.from_string(
|
||||
conditional.xml_attributes['sources']
|
||||
).replace(run=dummy_location.course_key.run)
|
||||
)
|
||||
assert conditional.sources_list[0] == BlockUsageLocator.from_string(conditional.xml_attributes['sources'])\
|
||||
.replace(run=dummy_location.course_key.run)
|
||||
|
||||
def test_conditional_module_parse_sources(self):
|
||||
dummy_system = Mock()
|
||||
@@ -353,10 +349,8 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
dummy_field_data,
|
||||
dummy_scope_ids,
|
||||
)
|
||||
self.assertEqual(
|
||||
conditional.parse_sources(conditional.xml_attributes),
|
||||
['i4x://HarvardX/ER22x/poll_question/T15_poll', 'i4x://HarvardX/ER22x/poll_question/T16_poll']
|
||||
)
|
||||
assert conditional.parse_sources(conditional.xml_attributes) == ['i4x://HarvardX/ER22x/poll_question/T15_poll',
|
||||
'i4x://HarvardX/ER22x/poll_question/T16_poll']
|
||||
|
||||
def test_conditional_module_parse_attr_values(self):
|
||||
root = '<conditional attempted="false"></conditional>'
|
||||
@@ -369,7 +363,7 @@ class ConditionalBlockXmlTest(unittest.TestCase):
|
||||
'conditional_message': ''
|
||||
}
|
||||
|
||||
self.assertEqual(definition, expected_definition)
|
||||
assert definition == expected_definition
|
||||
|
||||
def test_presence_attributes_in_xml_attributes(self):
|
||||
modules = ConditionalFactory.create(self.test_system)
|
||||
@@ -430,18 +424,18 @@ class ConditionalBlockStudioTest(XModuleXmlImportTest):
|
||||
|
||||
context = create_studio_context(self.conditional, False)
|
||||
html = self.module_system.render(self.conditional, AUTHOR_VIEW, context).content
|
||||
self.assertIn('This is a secret HTML', html)
|
||||
assert 'This is a secret HTML' in html
|
||||
|
||||
context = create_studio_context(self.sequence, True)
|
||||
html = self.module_system.render(self.conditional, AUTHOR_VIEW, context).content
|
||||
self.assertNotIn('This is a secret HTML', html)
|
||||
assert 'This is a secret HTML' not in html
|
||||
|
||||
def test_non_editable_settings(self):
|
||||
"""
|
||||
Test the settings that are marked as "non-editable".
|
||||
"""
|
||||
non_editable_metadata_fields = self.conditional.non_editable_metadata_fields
|
||||
self.assertIn(ConditionalBlock.due, non_editable_metadata_fields)
|
||||
assert ConditionalBlock.due in non_editable_metadata_fields
|
||||
|
||||
def test_validation_messages(self):
|
||||
"""
|
||||
@@ -449,10 +443,7 @@ class ConditionalBlockStudioTest(XModuleXmlImportTest):
|
||||
"""
|
||||
self.conditional.sources_list = None
|
||||
validation = self.conditional.validate()
|
||||
self.assertEqual(
|
||||
validation.summary.text,
|
||||
u"This component has no source components configured yet."
|
||||
)
|
||||
self.assertEqual(validation.summary.type, StudioValidationMessage.NOT_CONFIGURED)
|
||||
self.assertEqual(validation.summary.action_class, 'edit-button')
|
||||
self.assertEqual(validation.summary.action_label, u"Configure list of sources")
|
||||
assert validation.summary.text == u'This component has no source components configured yet.'
|
||||
assert validation.summary.type == StudioValidationMessage.NOT_CONFIGURED
|
||||
assert validation.summary.action_class == 'edit-button'
|
||||
assert validation.summary.action_label == u'Configure list of sources'
|
||||
|
||||
@@ -106,10 +106,10 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
# We had a bug where a thumbnail location of None was getting transformed into a Location tuple, with
|
||||
# all elements being None. It is important that the location be just None for rendering.
|
||||
content = StaticContent('loc', 'name', 'content_type', 'data', None, None, None)
|
||||
self.assertIsNone(content.thumbnail_location)
|
||||
assert content.thumbnail_location is None
|
||||
|
||||
content = StaticContent('loc', 'name', 'content_type', 'data')
|
||||
self.assertIsNone(content.thumbnail_location)
|
||||
assert content.thumbnail_location is None
|
||||
|
||||
@ddt.data(
|
||||
(u"monsters__.jpg", u"monsters__.jpg"),
|
||||
@@ -123,11 +123,9 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
content = Content(AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'asset', original_filename),
|
||||
None)
|
||||
(thumbnail_content, thumbnail_file_location) = content_store.generate_thumbnail(content)
|
||||
self.assertIsNone(thumbnail_content)
|
||||
self.assertEqual(
|
||||
AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'thumbnail', thumbnail_filename),
|
||||
thumbnail_file_location
|
||||
)
|
||||
assert thumbnail_content is None
|
||||
assert AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'thumbnail', thumbnail_filename) ==\
|
||||
thumbnail_file_location
|
||||
|
||||
@patch('xmodule.contentstore.content.Image')
|
||||
def test_image_is_closed_when_generating_thumbnail(self, image_class_mock):
|
||||
@@ -141,8 +139,8 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
"image/jpeg")
|
||||
content.data = b'mock data'
|
||||
content_store.generate_thumbnail(content)
|
||||
self.assertTrue(image_class_mock.open.called, "Image.open not called")
|
||||
self.assertTrue(mock_image.close.called, "mock_image.close not called")
|
||||
assert image_class_mock.open.called, 'Image.open not called'
|
||||
assert mock_image.close.called, 'mock_image.close not called'
|
||||
|
||||
def test_store_svg_as_thumbnail(self):
|
||||
# We had a bug that caused generate_thumbnail to attempt to pass SVG to PIL to generate a thumbnail.
|
||||
@@ -154,11 +152,9 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
'image/svg+xml')
|
||||
content.data = b'mock svg file'
|
||||
(thumbnail_content, thumbnail_file_location) = content_store.generate_thumbnail(content)
|
||||
self.assertEqual(thumbnail_content.data.read(), b'mock svg file')
|
||||
self.assertEqual(
|
||||
AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'thumbnail', thumbnail_filename),
|
||||
thumbnail_file_location
|
||||
)
|
||||
assert thumbnail_content.data.read() == b'mock svg file'
|
||||
assert AssetLocator(CourseLocator(u'mitX', u'800', u'ignore_run'), u'thumbnail', thumbnail_filename) ==\
|
||||
thumbnail_file_location
|
||||
|
||||
def test_compute_location(self):
|
||||
# We had a bug that __ got converted into a single _. Make sure that substitution of INVALID_CHARS (like space)
|
||||
@@ -166,19 +162,13 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
asset_location = StaticContent.compute_location(
|
||||
CourseKey.from_string('mitX/400/ignore'), 'subs__1eo_jXvZnE .srt.sjson'
|
||||
)
|
||||
self.assertEqual(
|
||||
AssetLocator(CourseLocator(u'mitX', u'400', u'ignore', deprecated=True),
|
||||
u'asset', u'subs__1eo_jXvZnE_.srt.sjson'),
|
||||
asset_location
|
||||
)
|
||||
assert AssetLocator(CourseLocator(u'mitX', u'400', u'ignore', deprecated=True),
|
||||
u'asset', u'subs__1eo_jXvZnE_.srt.sjson') == asset_location
|
||||
|
||||
def test_get_location_from_path(self):
|
||||
asset_location = StaticContent.get_location_from_path(u'/c4x/a/b/asset/images_course_image.jpg')
|
||||
self.assertEqual(
|
||||
AssetLocator(CourseLocator(u'a', u'b', None, deprecated=True),
|
||||
u'asset', u'images_course_image.jpg', deprecated=True),
|
||||
asset_location
|
||||
)
|
||||
assert AssetLocator(CourseLocator(u'a', u'b', None, deprecated=True),
|
||||
u'asset', u'images_course_image.jpg', deprecated=True) == asset_location
|
||||
|
||||
def test_static_content_stream_stream_data(self):
|
||||
"""
|
||||
@@ -193,7 +183,7 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
for chunck in stream:
|
||||
total_length += len(chunck)
|
||||
|
||||
self.assertEqual(total_length, static_content_stream.length)
|
||||
assert total_length == static_content_stream.length
|
||||
|
||||
def test_static_content_stream_stream_data_in_range(self):
|
||||
"""
|
||||
@@ -214,7 +204,7 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
for chunck in stream:
|
||||
total_length += len(chunck)
|
||||
|
||||
self.assertEqual(total_length, last_byte - first_byte + 1)
|
||||
assert total_length == ((last_byte - first_byte) + 1)
|
||||
|
||||
def test_static_content_write_js(self):
|
||||
"""
|
||||
@@ -223,5 +213,5 @@ class ContentTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-c
|
||||
output_root = path(u'common/static/xmodule/descriptors/js')
|
||||
file_owners = _write_js(output_root, _list_descriptors(), 'get_studio_view_js')
|
||||
js_file_paths = set(file_path for file_path in sum(list(file_owners.values()), []) if os.path.basename(file_path).startswith('000-')) # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertEqual(len(js_file_paths), 1)
|
||||
self.assertIn("XModule.Descriptor = (function() {", open(js_file_paths.pop()).read())
|
||||
assert len(js_file_paths) == 1
|
||||
assert 'XModule.Descriptor = (function() {' in open(js_file_paths.pop()).read()
|
||||
|
||||
@@ -8,7 +8,7 @@ from datetime import datetime, timedelta
|
||||
from unittest import TestCase
|
||||
|
||||
from pytz import utc
|
||||
|
||||
import pytest
|
||||
from xmodule.block_metadata_utils import (
|
||||
display_name_with_default,
|
||||
display_name_with_default_escaped,
|
||||
@@ -179,10 +179,10 @@ class CourseMetadataUtilsTestCase(TestCase):
|
||||
for function_test in function_tests:
|
||||
for scenario in function_test.scenarios:
|
||||
actual_return = function_test.function(*scenario.arguments)
|
||||
self.assertEqual(actual_return, scenario.expected_return)
|
||||
assert actual_return == scenario.expected_return
|
||||
|
||||
# Even though we don't care about testing mock_strftime_localized,
|
||||
# we still need to test it with a bad format string in order to
|
||||
# satisfy the coverage checker.
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
mock_strftime_localized(test_datetime, 'BAD_FORMAT_SPECIFIER')
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import itertools
|
||||
import unittest
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
from dateutil import parser
|
||||
from django.conf import settings
|
||||
@@ -32,10 +32,7 @@ _NEXT_WEEK = _TODAY + timedelta(days=7)
|
||||
class CourseFieldsTestCase(unittest.TestCase):
|
||||
|
||||
def test_default_start_date(self):
|
||||
self.assertEqual(
|
||||
xmodule.course_module.CourseFields.start.default,
|
||||
datetime(2030, 1, 1, tzinfo=utc)
|
||||
)
|
||||
assert xmodule.course_module.CourseFields.start.default == datetime(2030, 1, 1, tzinfo=utc)
|
||||
|
||||
|
||||
class DummySystem(ImportSystem): # lint-amnesty, pylint: disable=abstract-method, missing-class-docstring
|
||||
@@ -132,21 +129,21 @@ class HasEndedMayCertifyTestCase(unittest.TestCase):
|
||||
|
||||
def test_has_ended(self):
|
||||
"""Check that has_ended correctly tells us when a course is over."""
|
||||
self.assertTrue(self.past_show_certs.has_ended())
|
||||
self.assertTrue(self.past_show_certs_no_info.has_ended())
|
||||
self.assertTrue(self.past_noshow_certs.has_ended())
|
||||
self.assertFalse(self.future_show_certs.has_ended())
|
||||
self.assertFalse(self.future_show_certs_no_info.has_ended())
|
||||
self.assertFalse(self.future_noshow_certs.has_ended())
|
||||
assert self.past_show_certs.has_ended()
|
||||
assert self.past_show_certs_no_info.has_ended()
|
||||
assert self.past_noshow_certs.has_ended()
|
||||
assert not self.future_show_certs.has_ended()
|
||||
assert not self.future_show_certs_no_info.has_ended()
|
||||
assert not self.future_noshow_certs.has_ended()
|
||||
|
||||
def test_may_certify(self):
|
||||
"""Check that may_certify correctly tells us when a course may wrap."""
|
||||
self.assertTrue(self.past_show_certs.may_certify())
|
||||
self.assertTrue(self.past_noshow_certs.may_certify())
|
||||
self.assertTrue(self.past_show_certs_no_info.may_certify())
|
||||
self.assertTrue(self.future_show_certs.may_certify())
|
||||
self.assertTrue(self.future_show_certs_no_info.may_certify())
|
||||
self.assertFalse(self.future_noshow_certs.may_certify())
|
||||
assert self.past_show_certs.may_certify()
|
||||
assert self.past_noshow_certs.may_certify()
|
||||
assert self.past_show_certs_no_info.may_certify()
|
||||
assert self.future_show_certs.may_certify()
|
||||
assert self.future_show_certs_no_info.may_certify()
|
||||
assert not self.future_noshow_certs.may_certify()
|
||||
|
||||
|
||||
class CourseSummaryHasEnded(unittest.TestCase):
|
||||
@@ -156,7 +153,7 @@ class CourseSummaryHasEnded(unittest.TestCase):
|
||||
test_course = get_dummy_course("2012-01-01T12:00")
|
||||
bad_end_date = parser.parse("2012-02-21 10:28:45")
|
||||
summary = xmodule.course_module.CourseSummary(test_course.id, end=bad_end_date)
|
||||
self.assertTrue(summary.has_ended())
|
||||
assert summary.has_ended()
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -229,17 +226,17 @@ class IsNewCourseTestCase(unittest.TestCase):
|
||||
def test_start_date_is_default(self):
|
||||
for s in self.start_advertised_settings:
|
||||
d = get_dummy_course(start=s[0], advertised_start=s[1])
|
||||
self.assertEqual(d.start_date_is_still_default, s[3])
|
||||
assert d.start_date_is_still_default == s[3]
|
||||
|
||||
def test_display_organization(self):
|
||||
descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True)
|
||||
self.assertNotEqual(descriptor.location.org, descriptor.display_org_with_default)
|
||||
self.assertEqual(descriptor.display_org_with_default, "{0}_display".format(ORG))
|
||||
assert descriptor.location.org != descriptor.display_org_with_default
|
||||
assert descriptor.display_org_with_default == '{0}_display'.format(ORG)
|
||||
|
||||
def test_display_coursenumber(self):
|
||||
descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True)
|
||||
self.assertNotEqual(descriptor.location.course, descriptor.display_number_with_default)
|
||||
self.assertEqual(descriptor.display_number_with_default, "{0}_display".format(COURSE))
|
||||
assert descriptor.location.course != descriptor.display_number_with_default
|
||||
assert descriptor.display_number_with_default == '{0}_display'.format(COURSE)
|
||||
|
||||
def test_is_newish(self):
|
||||
descriptor = get_dummy_course(start='2012-12-02T12:00', is_new=True)
|
||||
@@ -268,7 +265,7 @@ class DiscussionTopicsTestCase(unittest.TestCase):
|
||||
|
||||
def test_default_discussion_topics(self):
|
||||
d = get_dummy_course('2012-12-02T12:00')
|
||||
self.assertEqual({'General': {'id': 'i4x-test_org-test_course-course-test'}}, d.discussion_topics)
|
||||
assert {'General': {'id': 'i4x-test_org-test_course-course-test'}} == d.discussion_topics
|
||||
|
||||
|
||||
class TeamsConfigurationTestCase(unittest.TestCase):
|
||||
@@ -306,52 +303,49 @@ class TeamsConfigurationTestCase(unittest.TestCase):
|
||||
|
||||
def test_teams_enabled_new_course(self):
|
||||
# Make sure we can detect when no teams exist.
|
||||
self.assertFalse(self.course.teams_enabled)
|
||||
assert not self.course.teams_enabled
|
||||
|
||||
# add topics
|
||||
self.add_team_configuration(max_team_size=4, topics=[self.make_topic()])
|
||||
self.assertTrue(self.course.teams_enabled)
|
||||
assert self.course.teams_enabled
|
||||
|
||||
# remove them again
|
||||
self.add_team_configuration(max_team_size=4, topics=[])
|
||||
self.assertFalse(self.course.teams_enabled)
|
||||
assert not self.course.teams_enabled
|
||||
|
||||
def test_teams_enabled_max_size_only(self):
|
||||
self.add_team_configuration(max_team_size=4)
|
||||
self.assertFalse(self.course.teams_enabled)
|
||||
assert not self.course.teams_enabled
|
||||
|
||||
def test_teams_enabled_no_max_size(self):
|
||||
self.add_team_configuration(max_team_size=None, topics=[self.make_topic()])
|
||||
self.assertTrue(self.course.teams_enabled)
|
||||
assert self.course.teams_enabled
|
||||
|
||||
def test_teams_max_size_no_teams_configuration(self):
|
||||
self.assertEqual(
|
||||
self.course.teams_configuration.default_max_team_size,
|
||||
DEFAULT_COURSE_RUN_MAX_TEAM_SIZE,
|
||||
)
|
||||
assert self.course.teams_configuration.default_max_team_size == DEFAULT_COURSE_RUN_MAX_TEAM_SIZE
|
||||
|
||||
def test_teams_max_size_with_teams_configured(self):
|
||||
size = 4
|
||||
self.add_team_configuration(max_team_size=size, topics=[self.make_topic(), self.make_topic()])
|
||||
self.assertTrue(self.course.teams_enabled)
|
||||
self.assertEqual(size, self.course.teams_configuration.default_max_team_size)
|
||||
assert self.course.teams_enabled
|
||||
assert size == self.course.teams_configuration.default_max_team_size
|
||||
|
||||
def test_teamsets_no_config(self):
|
||||
self.assertEqual(self.course.teamsets, [])
|
||||
assert self.course.teamsets == []
|
||||
|
||||
def test_teamsets_empty(self):
|
||||
self.add_team_configuration(max_team_size=4)
|
||||
self.assertEqual(self.course.teamsets, [])
|
||||
assert self.course.teamsets == []
|
||||
|
||||
def test_teamsets_present(self):
|
||||
topics = [self.make_topic(), self.make_topic()]
|
||||
self.add_team_configuration(max_team_size=4, topics=topics)
|
||||
self.assertTrue(self.course.teams_enabled)
|
||||
assert self.course.teams_enabled
|
||||
expected_teamsets_data = [
|
||||
teamset.cleaned_data
|
||||
for teamset in self.course.teamsets
|
||||
]
|
||||
self.assertEqual(expected_teamsets_data, topics)
|
||||
assert expected_teamsets_data == topics
|
||||
|
||||
def test_teams_conf_cached_by_xblock_field(self):
|
||||
self.add_team_configuration(max_team_size=5, topics=[self.make_topic()])
|
||||
@@ -360,9 +354,9 @@ class TeamsConfigurationTestCase(unittest.TestCase):
|
||||
self.add_team_configuration(max_team_size=5, topics=[self.make_topic(), self.make_topic()])
|
||||
new_cold_cache_conf = self.course.teams_configuration
|
||||
new_warm_cache_conf = self.course.teams_configuration
|
||||
self.assertIs(cold_cache_conf, warm_cache_conf)
|
||||
self.assertIs(new_cold_cache_conf, new_warm_cache_conf)
|
||||
self.assertIsNot(cold_cache_conf, new_cold_cache_conf)
|
||||
assert cold_cache_conf is warm_cache_conf
|
||||
assert new_cold_cache_conf is new_warm_cache_conf
|
||||
assert cold_cache_conf is not new_cold_cache_conf
|
||||
|
||||
|
||||
class SelfPacedTestCase(unittest.TestCase):
|
||||
@@ -373,7 +367,7 @@ class SelfPacedTestCase(unittest.TestCase):
|
||||
self.course = get_dummy_course('2012-12-02T12:00')
|
||||
|
||||
def test_default(self):
|
||||
self.assertFalse(self.course.self_paced)
|
||||
assert not self.course.self_paced
|
||||
|
||||
|
||||
class CourseDescriptorTestCase(unittest.TestCase):
|
||||
@@ -397,29 +391,23 @@ class CourseDescriptorTestCase(unittest.TestCase):
|
||||
"""
|
||||
Test CourseDescriptor.clean_id.
|
||||
"""
|
||||
self.assertEqual(
|
||||
self.course.clean_id(),
|
||||
"course_ORSXG5C7N5ZGOL3UMVZXIX3DN52XE43FF52GK43UL5ZHK3Q="
|
||||
)
|
||||
self.assertEqual(
|
||||
self.course.clean_id(padding_char='$'),
|
||||
"course_ORSXG5C7N5ZGOL3UMVZXIX3DN52XE43FF52GK43UL5ZHK3Q$"
|
||||
)
|
||||
assert self.course.clean_id() == 'course_ORSXG5C7N5ZGOL3UMVZXIX3DN52XE43FF52GK43UL5ZHK3Q='
|
||||
assert self.course.clean_id(padding_char='$') == 'course_ORSXG5C7N5ZGOL3UMVZXIX3DN52XE43FF52GK43UL5ZHK3Q$'
|
||||
|
||||
def test_has_started(self):
|
||||
"""
|
||||
Test CourseDescriptor.has_started.
|
||||
"""
|
||||
self.course.start = _LAST_WEEK
|
||||
self.assertTrue(self.course.has_started())
|
||||
assert self.course.has_started()
|
||||
self.course.start = _NEXT_WEEK
|
||||
self.assertFalse(self.course.has_started())
|
||||
assert not self.course.has_started()
|
||||
|
||||
def test_number(self):
|
||||
"""
|
||||
Test CourseDescriptor.number.
|
||||
"""
|
||||
self.assertEqual(self.course.number, COURSE)
|
||||
assert self.course.number == COURSE
|
||||
|
||||
def test_set_default_certificate_available_date(self):
|
||||
"""
|
||||
@@ -427,7 +415,7 @@ class CourseDescriptorTestCase(unittest.TestCase):
|
||||
after the course end date.
|
||||
"""
|
||||
expected_certificate_available_date = self.course.end + timedelta(days=2)
|
||||
self.assertEqual(expected_certificate_available_date, self.course.certificate_available_date)
|
||||
assert expected_certificate_available_date == self.course.certificate_available_date
|
||||
|
||||
|
||||
class ProctoringProviderTestCase(unittest.TestCase):
|
||||
@@ -451,7 +439,7 @@ class ProctoringProviderTestCase(unittest.TestCase):
|
||||
|
||||
# we expect the validated value to be equivalent to the value passed in,
|
||||
# since there are no validation errors or missing data
|
||||
self.assertEqual(self.proctoring_provider.from_json(default_provider), default_provider)
|
||||
assert self.proctoring_provider.from_json(default_provider) == default_provider
|
||||
|
||||
def test_from_json_with_invalid_provider(self):
|
||||
"""
|
||||
@@ -461,13 +449,11 @@ class ProctoringProviderTestCase(unittest.TestCase):
|
||||
provider = 'invalid-provider'
|
||||
allowed_proctoring_providers = [u'mock', u'mock_proctoring_without_rules']
|
||||
|
||||
with self.assertRaises(ValueError) as context_manager:
|
||||
with pytest.raises(ValueError) as context_manager:
|
||||
self.proctoring_provider.from_json(provider)
|
||||
self.assertEqual(
|
||||
context_manager.exception.args[0],
|
||||
['The selected proctoring provider, {}, is not a valid provider. Please select from one of {}.'
|
||||
.format(provider, allowed_proctoring_providers)]
|
||||
)
|
||||
assert context_manager.exception.args[0] ==\
|
||||
[f'The selected proctoring provider, {provider},'
|
||||
f' is not a valid provider. Please select from one of {allowed_proctoring_providers}.']
|
||||
|
||||
def test_from_json_adds_platform_default_for_missing_provider(self):
|
||||
"""
|
||||
@@ -476,7 +462,7 @@ class ProctoringProviderTestCase(unittest.TestCase):
|
||||
"""
|
||||
default_provider = 'mock'
|
||||
|
||||
self.assertEqual(self.proctoring_provider.from_json(None), default_provider)
|
||||
assert self.proctoring_provider.from_json(None) == default_provider
|
||||
|
||||
@override_settings(
|
||||
PROCTORING_BACKENDS={
|
||||
@@ -488,7 +474,7 @@ class ProctoringProviderTestCase(unittest.TestCase):
|
||||
"""
|
||||
Test that, when the platform defaults are not set, the default is correct.
|
||||
"""
|
||||
self. assertEqual(self.proctoring_provider.default, None)
|
||||
assert self.proctoring_provider.default is None
|
||||
|
||||
@override_settings(PROCTORING_BACKENDS=None)
|
||||
def test_default_with_no_platform_configuration(self):
|
||||
@@ -496,4 +482,4 @@ class ProctoringProviderTestCase(unittest.TestCase):
|
||||
Test that, when the platform default is not specified, the default is correct.
|
||||
"""
|
||||
default = self.proctoring_provider.default
|
||||
self.assertEqual(default, None)
|
||||
assert default is None
|
||||
|
||||
@@ -12,6 +12,7 @@ import datetime
|
||||
import textwrap
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
from mock import Mock
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
from pytz import UTC
|
||||
@@ -156,8 +157,8 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
)
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
self.assertEqual(result['success'], 'correct')
|
||||
self.assertEqual(module.attempts, num_attempts + 1)
|
||||
assert result['success'] == 'correct'
|
||||
assert module.attempts == (num_attempts + 1)
|
||||
|
||||
def test_no_wait_time(self):
|
||||
num_attempts = 1
|
||||
@@ -168,8 +169,8 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
)
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
self.assertEqual(result['success'], 'correct')
|
||||
self.assertEqual(module.attempts, num_attempts + 1)
|
||||
assert result['success'] == 'correct'
|
||||
assert module.attempts == (num_attempts + 1)
|
||||
|
||||
def test_submit_quiz_in_rapid_succession(self):
|
||||
# Already attempted once (just now) and thus has a submitted time
|
||||
@@ -182,7 +183,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least.*")
|
||||
self.assertEqual(module.attempts, num_attempts)
|
||||
assert module.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_too_soon(self):
|
||||
# Already attempted once (just now)
|
||||
@@ -196,7 +197,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 3 minutes between submissions. 2 minutes remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertEqual(module.attempts, num_attempts)
|
||||
assert module.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_1_second_too_soon(self):
|
||||
# Already attempted once (just now)
|
||||
@@ -210,7 +211,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 3 minutes between submissions. 1 second remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertEqual(module.attempts, num_attempts)
|
||||
assert module.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_as_soon_as_allowed(self):
|
||||
# Already attempted once (just now)
|
||||
@@ -223,8 +224,8 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
)
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
self.assertEqual(result['success'], 'correct')
|
||||
self.assertEqual(module.attempts, num_attempts + 1)
|
||||
assert result['success'] == 'correct'
|
||||
assert module.attempts == (num_attempts + 1)
|
||||
|
||||
def test_submit_quiz_after_delay_expired(self):
|
||||
# Already attempted once (just now)
|
||||
@@ -237,14 +238,14 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
)
|
||||
# Successfully submitted and answered
|
||||
# Also, the number of attempts should increment by 1
|
||||
self.assertEqual(result['success'], 'correct')
|
||||
self.assertEqual(module.attempts, num_attempts + 1)
|
||||
assert result['success'] == 'correct'
|
||||
assert module.attempts == (num_attempts + 1)
|
||||
|
||||
def test_still_cannot_submit_after_max_attempts(self):
|
||||
# Already attempted once (just now) and thus has a submitted time
|
||||
num_attempts = 99
|
||||
# Regular create_and_check should fail
|
||||
with self.assertRaises(xmodule.exceptions.NotFoundError):
|
||||
with pytest.raises(xmodule.exceptions.NotFoundError):
|
||||
(module, unused_result) = self.create_and_check(
|
||||
num_attempts=num_attempts,
|
||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
||||
@@ -261,7 +262,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
skip_submit_problem=True
|
||||
)
|
||||
# Expect that number of attempts NOT incremented
|
||||
self.assertEqual(module.attempts, num_attempts)
|
||||
assert module.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_with_long_delay(self):
|
||||
# Already attempted once (just now)
|
||||
@@ -275,7 +276,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 2 hours between submissions. 2 minutes 1 second remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertEqual(module.attempts, num_attempts)
|
||||
assert module.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_with_involved_pretty_print(self):
|
||||
# Already attempted once (just now)
|
||||
@@ -289,7 +290,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 2 hours 1 minute 3 seconds between submissions. 1 hour 2 minutes 59 seconds remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertEqual(module.attempts, num_attempts)
|
||||
assert module.attempts == num_attempts
|
||||
|
||||
def test_submit_quiz_with_nonplural_pretty_print(self):
|
||||
# Already attempted once (just now)
|
||||
@@ -303,4 +304,4 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
||||
# You should get a dialog that tells you to wait 2 minutes
|
||||
# Also, the number of attempts should not be incremented
|
||||
self.assertRegex(result['success'], r"You must wait at least 1 minute between submissions. 1 minute remaining\..*") # lint-amnesty, pylint: disable=line-too-long
|
||||
self.assertEqual(module.attempts, num_attempts)
|
||||
assert module.attempts == num_attempts
|
||||
|
||||
@@ -70,8 +70,8 @@ class TabsEditingDescriptorTestCase(unittest.TestCase):
|
||||
test_css_file = os.path.join(current_dir, 'test_files/test_tabseditingdescriptor.scss')
|
||||
with open(test_css_file) as new_css:
|
||||
added_css = new_css.read()
|
||||
self.assertEqual(css['scss'].pop().decode('utf-8'), added_css)
|
||||
self.assertEqual(css['css'].pop().decode('utf-8'), added_css)
|
||||
assert css['scss'].pop().decode('utf-8') == added_css
|
||||
assert css['css'].pop().decode('utf-8') == added_css
|
||||
|
||||
def test_get_context(self):
|
||||
""""test get_context"""
|
||||
|
||||
@@ -5,6 +5,7 @@ Tests for ErrorBlock and NonStaffErrorBlock
|
||||
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
from mock import MagicMock, Mock, patch
|
||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||
from xblock.field_data import DictFieldData
|
||||
@@ -42,11 +43,11 @@ class TestErrorBlock(SetupTestErrorBlock):
|
||||
CourseLocationManager(self.course_id),
|
||||
self.error_msg
|
||||
)
|
||||
self.assertIsInstance(descriptor, ErrorBlock)
|
||||
assert isinstance(descriptor, ErrorBlock)
|
||||
descriptor.xmodule_runtime = self.system
|
||||
context_repr = self.system.render(descriptor, STUDENT_VIEW).content
|
||||
self.assertIn(self.error_msg, context_repr)
|
||||
self.assertIn(repr(self.valid_xml), context_repr)
|
||||
assert self.error_msg in context_repr
|
||||
assert repr(self.valid_xml) in context_repr
|
||||
|
||||
def test_error_block_from_descriptor(self):
|
||||
descriptor = MagicMock(
|
||||
@@ -57,11 +58,11 @@ class TestErrorBlock(SetupTestErrorBlock):
|
||||
|
||||
error_descriptor = ErrorBlock.from_descriptor(
|
||||
descriptor, self.error_msg)
|
||||
self.assertIsInstance(error_descriptor, ErrorBlock)
|
||||
assert isinstance(error_descriptor, ErrorBlock)
|
||||
error_descriptor.xmodule_runtime = self.system
|
||||
context_repr = self.system.render(error_descriptor, STUDENT_VIEW).content
|
||||
self.assertIn(self.error_msg, context_repr)
|
||||
self.assertIn(repr(descriptor), context_repr)
|
||||
assert self.error_msg in context_repr
|
||||
assert repr(descriptor) in context_repr
|
||||
|
||||
|
||||
class TestNonStaffErrorBlock(SetupTestErrorBlock):
|
||||
@@ -75,7 +76,7 @@ class TestNonStaffErrorBlock(SetupTestErrorBlock):
|
||||
self.system,
|
||||
CourseLocationManager(self.course_id)
|
||||
)
|
||||
self.assertIsInstance(descriptor, NonStaffErrorBlock)
|
||||
assert isinstance(descriptor, NonStaffErrorBlock)
|
||||
|
||||
def test_from_xml_render(self):
|
||||
descriptor = NonStaffErrorBlock.from_xml(
|
||||
@@ -85,8 +86,8 @@ class TestNonStaffErrorBlock(SetupTestErrorBlock):
|
||||
)
|
||||
descriptor.xmodule_runtime = self.system
|
||||
context_repr = self.system.render(descriptor, STUDENT_VIEW).content
|
||||
self.assertNotIn(self.error_msg, context_repr)
|
||||
self.assertNotIn(repr(self.valid_xml), context_repr)
|
||||
assert self.error_msg not in context_repr
|
||||
assert repr(self.valid_xml) not in context_repr
|
||||
|
||||
def test_error_block_from_descriptor(self):
|
||||
descriptor = MagicMock(
|
||||
@@ -97,11 +98,11 @@ class TestNonStaffErrorBlock(SetupTestErrorBlock):
|
||||
|
||||
error_descriptor = NonStaffErrorBlock.from_descriptor(
|
||||
descriptor, self.error_msg)
|
||||
self.assertIsInstance(error_descriptor, ErrorBlock)
|
||||
assert isinstance(error_descriptor, ErrorBlock)
|
||||
error_descriptor.xmodule_runtime = self.system
|
||||
context_repr = self.system.render(error_descriptor, STUDENT_VIEW).content
|
||||
self.assertNotIn(self.error_msg, context_repr)
|
||||
self.assertNotIn(str(descriptor), context_repr)
|
||||
assert self.error_msg not in context_repr
|
||||
assert str(descriptor) not in context_repr
|
||||
|
||||
|
||||
class BrokenModule(XModule): # lint-amnesty, pylint: disable=abstract-method
|
||||
@@ -149,14 +150,14 @@ class TestErrorBlockConstruction(unittest.TestCase):
|
||||
get an ErrorBlock back from XModuleDescriptor._xmodule
|
||||
"""
|
||||
module = self.descriptor._xmodule # lint-amnesty, pylint: disable=protected-access
|
||||
self.assertIsInstance(module, ErrorBlock)
|
||||
assert isinstance(module, ErrorBlock)
|
||||
|
||||
@patch.object(ErrorBlock, '__init__', Mock(side_effect=TestException))
|
||||
def test_broken_error_descriptor(self):
|
||||
"""
|
||||
Test that a broken block descriptor doesn't cause an infinite loop
|
||||
"""
|
||||
with self.assertRaises(TestException):
|
||||
with pytest.raises(TestException):
|
||||
module = self.descriptor._xmodule # lint-amnesty, pylint: disable=protected-access, unused-variable
|
||||
|
||||
@patch.object(ErrorBlock, '__init__', Mock(side_effect=TestException))
|
||||
@@ -164,5 +165,5 @@ class TestErrorBlockConstruction(unittest.TestCase):
|
||||
"""
|
||||
Test that a broken block module doesn't cause an infinite loop
|
||||
"""
|
||||
with self.assertRaises(TestException):
|
||||
with pytest.raises(TestException):
|
||||
module = self.descriptor._xmodule # lint-amnesty, pylint: disable=protected-access, unused-variable
|
||||
|
||||
@@ -9,7 +9,7 @@ import unittest
|
||||
from datetime import datetime, timedelta, tzinfo
|
||||
from tempfile import mkdtemp
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import lxml.etree
|
||||
import mock
|
||||
@@ -104,7 +104,7 @@ class RoundTripTestCase(unittest.TestCase):
|
||||
initial_import = XMLModuleStore(root_dir, source_dirs=[course_dir], xblock_mixins=(XModuleMixin,))
|
||||
|
||||
courses = initial_import.get_courses()
|
||||
self.assertEqual(len(courses), 1)
|
||||
assert len(courses) == 1
|
||||
initial_course = courses[0]
|
||||
|
||||
# export to the same directory--that way things like the custom_tags/ folder
|
||||
@@ -122,7 +122,7 @@ class RoundTripTestCase(unittest.TestCase):
|
||||
second_import = XMLModuleStore(root_dir, source_dirs=[course_dir], xblock_mixins=(XModuleMixin,))
|
||||
|
||||
courses2 = second_import.get_courses()
|
||||
self.assertEqual(len(courses2), 1)
|
||||
assert len(courses2) == 1
|
||||
exported_course = courses2[0]
|
||||
|
||||
print("Checking course equality")
|
||||
@@ -132,8 +132,8 @@ class RoundTripTestCase(unittest.TestCase):
|
||||
strip_filenames(initial_course)
|
||||
strip_filenames(exported_course)
|
||||
|
||||
self.assertTrue(blocks_are_equivalent(initial_course, exported_course))
|
||||
self.assertEqual(initial_course.id, exported_course.id)
|
||||
assert blocks_are_equivalent(initial_course, exported_course)
|
||||
assert initial_course.id == exported_course.id
|
||||
course_id = initial_course.id
|
||||
|
||||
print("Checking key equality")
|
||||
@@ -146,10 +146,8 @@ class RoundTripTestCase(unittest.TestCase):
|
||||
print("Checking module equality")
|
||||
for location in initial_import.modules[course_id].keys():
|
||||
print(("Checking", location))
|
||||
self.assertTrue(blocks_are_equivalent(
|
||||
initial_import.modules[course_id][location],
|
||||
second_import.modules[course_id][location]
|
||||
))
|
||||
assert blocks_are_equivalent(initial_import.modules[course_id][location],
|
||||
second_import.modules[course_id][location])
|
||||
|
||||
|
||||
class TestEdxJsonEncoder(unittest.TestCase):
|
||||
@@ -177,42 +175,27 @@ class TestEdxJsonEncoder(unittest.TestCase):
|
||||
|
||||
def test_encode_location(self):
|
||||
loc = BlockUsageLocator(CourseLocator('org', 'course', 'run'), 'category', 'name')
|
||||
self.assertEqual(text_type(loc), self.encoder.default(loc))
|
||||
assert text_type(loc) == self.encoder.default(loc)
|
||||
|
||||
loc = BlockUsageLocator(CourseLocator('org', 'course', 'run', branch='version'), 'category', 'name')
|
||||
self.assertEqual(text_type(loc), self.encoder.default(loc))
|
||||
assert text_type(loc) == self.encoder.default(loc)
|
||||
|
||||
def test_encode_naive_datetime(self):
|
||||
self.assertEqual(
|
||||
"2013-05-03T10:20:30.000100",
|
||||
self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 100))
|
||||
)
|
||||
self.assertEqual(
|
||||
"2013-05-03T10:20:30",
|
||||
self.encoder.default(datetime(2013, 5, 3, 10, 20, 30))
|
||||
)
|
||||
assert '2013-05-03T10:20:30.000100' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 100))
|
||||
assert '2013-05-03T10:20:30' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30))
|
||||
|
||||
def test_encode_utc_datetime(self):
|
||||
self.assertEqual(
|
||||
"2013-05-03T10:20:30+00:00",
|
||||
self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, pytz.UTC))
|
||||
)
|
||||
assert '2013-05-03T10:20:30+00:00' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, pytz.UTC))
|
||||
|
||||
self.assertEqual(
|
||||
"2013-05-03T10:20:30+04:00",
|
||||
self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, self.offset_tz))
|
||||
)
|
||||
assert '2013-05-03T10:20:30+04:00' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, self.offset_tz))
|
||||
|
||||
self.assertEqual(
|
||||
"2013-05-03T10:20:30Z",
|
||||
self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, self.null_utc_tz))
|
||||
)
|
||||
assert '2013-05-03T10:20:30Z' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, self.null_utc_tz))
|
||||
|
||||
def test_fallthrough(self):
|
||||
with self.assertRaises(TypeError):
|
||||
with pytest.raises(TypeError):
|
||||
self.encoder.default(None)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
with pytest.raises(TypeError):
|
||||
self.encoder.default({})
|
||||
|
||||
def test_encode_unicode_lazy_text(self):
|
||||
@@ -224,7 +207,4 @@ class TestEdxJsonEncoder(unittest.TestCase):
|
||||
unicode_text = u"Your 𝓟𝓵𝓪𝓽𝓯𝓸𝓻𝓶 Name Here"
|
||||
lazy_text = ugettext_lazy(unicode_text) # lint-amnesty, pylint: disable=translation-of-non-string
|
||||
|
||||
self.assertEqual(
|
||||
unicode_text,
|
||||
self.encoder.default(lazy_text)
|
||||
)
|
||||
assert unicode_text == self.encoder.default(lazy_text)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import datetime
|
||||
import unittest
|
||||
|
||||
import pytest
|
||||
from pytz import UTC
|
||||
|
||||
from xmodule.fields import Date, RelativeTime, Timedelta
|
||||
@@ -14,11 +14,7 @@ class DateTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-clas
|
||||
date = Date()
|
||||
|
||||
def compare_dates(self, dt1, dt2, expected_delta):
|
||||
self.assertEqual(
|
||||
dt1 - dt2,
|
||||
expected_delta,
|
||||
str(dt1) + "-" + str(dt2) + "!=" + str(expected_delta)
|
||||
)
|
||||
assert (dt1 - dt2) == expected_delta, ((((str(dt1) + '-') + str(dt2)) + '!=') + str(expected_delta))
|
||||
|
||||
def test_from_json(self):
|
||||
"""Test conversion from iso compatible date strings to struct_time"""
|
||||
@@ -54,40 +50,27 @@ class DateTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-clas
|
||||
)
|
||||
|
||||
def test_enforce_type(self):
|
||||
self.assertEqual(DateTest.date.enforce_type(None), None)
|
||||
self.assertEqual(DateTest.date.enforce_type(""), None)
|
||||
self.assertEqual(
|
||||
DateTest.date.enforce_type("2012-12-31T23:00:01"),
|
||||
datetime.datetime(2012, 12, 31, 23, 0, 1, tzinfo=UTC)
|
||||
)
|
||||
self.assertEqual(
|
||||
DateTest.date.enforce_type(1234567890000),
|
||||
datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=UTC)
|
||||
)
|
||||
self.assertEqual(
|
||||
DateTest.date.enforce_type(datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC)),
|
||||
datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC)
|
||||
)
|
||||
with self.assertRaises(TypeError):
|
||||
assert DateTest.date.enforce_type(None) is None
|
||||
assert DateTest.date.enforce_type('') is None
|
||||
assert DateTest.date.enforce_type('2012-12-31T23:00:01') ==\
|
||||
datetime.datetime(2012, 12, 31, 23, 0, 1, tzinfo=UTC)
|
||||
assert DateTest.date.enforce_type(1234567890000) == datetime.datetime(2009, 2, 13, 23, 31, 30, tzinfo=UTC)
|
||||
assert DateTest.date.enforce_type(datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC)) ==\
|
||||
datetime.datetime(2014, 5, 9, 21, 1, 27, tzinfo=UTC)
|
||||
with pytest.raises(TypeError):
|
||||
DateTest.date.enforce_type([1])
|
||||
|
||||
def test_return_None(self):
|
||||
self.assertIsNone(DateTest.date.from_json(""))
|
||||
self.assertIsNone(DateTest.date.from_json(None))
|
||||
with self.assertRaises(TypeError):
|
||||
assert DateTest.date.from_json('') is None
|
||||
assert DateTest.date.from_json(None) is None
|
||||
with pytest.raises(TypeError):
|
||||
DateTest.date.from_json(['unknown value'])
|
||||
|
||||
def test_old_due_date_format(self):
|
||||
current = datetime.datetime.today()
|
||||
self.assertEqual(
|
||||
datetime.datetime(current.year, 3, 12, 12, tzinfo=UTC),
|
||||
DateTest.date.from_json("March 12 12:00")
|
||||
)
|
||||
self.assertEqual(
|
||||
datetime.datetime(current.year, 12, 4, 16, 30, tzinfo=UTC),
|
||||
DateTest.date.from_json("December 4 16:30")
|
||||
)
|
||||
self.assertIsNone(DateTest.date.from_json("12 12:00"))
|
||||
assert datetime.datetime(current.year, 3, 12, 12, tzinfo=UTC) == DateTest.date.from_json('March 12 12:00')
|
||||
assert datetime.datetime(current.year, 12, 4, 16, 30, tzinfo=UTC) == DateTest.date.from_json('December 4 16:30')
|
||||
assert DateTest.date.from_json('12 12:00') is None
|
||||
|
||||
def test_non_std_from_json(self):
|
||||
"""
|
||||
@@ -95,30 +78,20 @@ class DateTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-clas
|
||||
"""
|
||||
now = datetime.datetime.now(UTC)
|
||||
delta = now - datetime.datetime.fromtimestamp(0, UTC)
|
||||
self.assertEqual(
|
||||
DateTest.date.from_json(delta.total_seconds() * 1000),
|
||||
now
|
||||
)
|
||||
assert DateTest.date.from_json((delta.total_seconds() * 1000)) == now
|
||||
yesterday = datetime.datetime.now(UTC) - datetime.timedelta(days=-1)
|
||||
self.assertEqual(DateTest.date.from_json(yesterday), yesterday)
|
||||
assert DateTest.date.from_json(yesterday) == yesterday
|
||||
|
||||
def test_to_json(self):
|
||||
"""
|
||||
Test converting time reprs to iso dates
|
||||
"""
|
||||
self.assertEqual(
|
||||
DateTest.date.to_json(datetime.datetime.strptime("2012-12-31T23:59:59Z", "%Y-%m-%dT%H:%M:%SZ")),
|
||||
"2012-12-31T23:59:59Z"
|
||||
)
|
||||
self.assertEqual(
|
||||
DateTest.date.to_json(DateTest.date.from_json("2012-12-31T23:59:59Z")),
|
||||
"2012-12-31T23:59:59Z"
|
||||
)
|
||||
self.assertEqual(
|
||||
DateTest.date.to_json(DateTest.date.from_json("2012-12-31T23:00:01-01:00")),
|
||||
"2012-12-31T23:00:01-01:00"
|
||||
)
|
||||
with self.assertRaises(TypeError):
|
||||
assert DateTest.date.to_json(datetime.datetime.strptime('2012-12-31T23:59:59Z', '%Y-%m-%dT%H:%M:%SZ')) ==\
|
||||
'2012-12-31T23:59:59Z'
|
||||
assert DateTest.date.to_json(DateTest.date.from_json('2012-12-31T23:59:59Z')) == '2012-12-31T23:59:59Z'
|
||||
assert DateTest.date.to_json(DateTest.date.from_json('2012-12-31T23:00:01-01:00')) ==\
|
||||
'2012-12-31T23:00:01-01:00'
|
||||
with pytest.raises(TypeError):
|
||||
DateTest.date.to_json('2012-12-31T23:00:01-01:00')
|
||||
|
||||
|
||||
@@ -126,34 +99,22 @@ class TimedeltaTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing
|
||||
delta = Timedelta()
|
||||
|
||||
def test_from_json(self):
|
||||
self.assertEqual(
|
||||
TimedeltaTest.delta.from_json('1 day 12 hours 59 minutes 59 seconds'),
|
||||
datetime.timedelta(days=1, hours=12, minutes=59, seconds=59)
|
||||
)
|
||||
assert TimedeltaTest.delta.from_json('1 day 12 hours 59 minutes 59 seconds') ==\
|
||||
datetime.timedelta(days=1, hours=12, minutes=59, seconds=59)
|
||||
|
||||
self.assertEqual(
|
||||
TimedeltaTest.delta.from_json('1 day 46799 seconds'),
|
||||
datetime.timedelta(days=1, seconds=46799)
|
||||
)
|
||||
assert TimedeltaTest.delta.from_json('1 day 46799 seconds') == datetime.timedelta(days=1, seconds=46799)
|
||||
|
||||
def test_enforce_type(self):
|
||||
self.assertEqual(TimedeltaTest.delta.enforce_type(None), None)
|
||||
self.assertEqual(
|
||||
TimedeltaTest.delta.enforce_type(datetime.timedelta(days=1, seconds=46799)),
|
||||
datetime.timedelta(days=1, seconds=46799)
|
||||
)
|
||||
self.assertEqual(
|
||||
TimedeltaTest.delta.enforce_type('1 day 46799 seconds'),
|
||||
datetime.timedelta(days=1, seconds=46799)
|
||||
)
|
||||
with self.assertRaises(TypeError):
|
||||
assert TimedeltaTest.delta.enforce_type(None) is None
|
||||
assert TimedeltaTest.delta.enforce_type(datetime.timedelta(days=1, seconds=46799)) ==\
|
||||
datetime.timedelta(days=1, seconds=46799)
|
||||
assert TimedeltaTest.delta.enforce_type('1 day 46799 seconds') == datetime.timedelta(days=1, seconds=46799)
|
||||
with pytest.raises(TypeError):
|
||||
TimedeltaTest.delta.enforce_type([1])
|
||||
|
||||
def test_to_json(self):
|
||||
self.assertEqual(
|
||||
'1 days 46799 seconds',
|
||||
TimedeltaTest.delta.to_json(datetime.timedelta(days=1, hours=12, minutes=59, seconds=59))
|
||||
)
|
||||
assert '1 days 46799 seconds' ==\
|
||||
TimedeltaTest.delta.to_json(datetime.timedelta(days=1, hours=12, minutes=59, seconds=59))
|
||||
|
||||
|
||||
class TimeInfoTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -162,10 +123,7 @@ class TimeInfoTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-
|
||||
due_date = datetime.datetime(2000, 4, 14, 10, tzinfo=UTC)
|
||||
grace_pd_string = '1 day 12 hours 59 minutes 59 seconds'
|
||||
timeinfo = TimeInfo(due_date, grace_pd_string)
|
||||
self.assertEqual(
|
||||
timeinfo.close_date,
|
||||
due_date + Timedelta().from_json(grace_pd_string)
|
||||
)
|
||||
assert timeinfo.close_date == (due_date + Timedelta().from_json(grace_pd_string))
|
||||
|
||||
|
||||
class RelativeTimeTest(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -173,66 +131,37 @@ class RelativeTimeTest(unittest.TestCase): # lint-amnesty, pylint: disable=miss
|
||||
delta = RelativeTime()
|
||||
|
||||
def test_from_json(self):
|
||||
self.assertEqual(
|
||||
RelativeTimeTest.delta.from_json('0:05:07'),
|
||||
datetime.timedelta(seconds=307)
|
||||
)
|
||||
assert RelativeTimeTest.delta.from_json('0:05:07') == datetime.timedelta(seconds=307)
|
||||
|
||||
self.assertEqual(
|
||||
RelativeTimeTest.delta.from_json(100.0),
|
||||
datetime.timedelta(seconds=100)
|
||||
)
|
||||
self.assertEqual(
|
||||
RelativeTimeTest.delta.from_json(None),
|
||||
datetime.timedelta(seconds=0)
|
||||
)
|
||||
assert RelativeTimeTest.delta.from_json(100.0) == datetime.timedelta(seconds=100)
|
||||
assert RelativeTimeTest.delta.from_json(None) == datetime.timedelta(seconds=0)
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
with pytest.raises(TypeError):
|
||||
RelativeTimeTest.delta.from_json(1234) # int
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
RelativeTimeTest.delta.from_json("77:77:77")
|
||||
|
||||
def test_enforce_type(self):
|
||||
self.assertEqual(RelativeTimeTest.delta.enforce_type(None), None)
|
||||
self.assertEqual(
|
||||
RelativeTimeTest.delta.enforce_type(datetime.timedelta(days=1, seconds=46799)),
|
||||
datetime.timedelta(days=1, seconds=46799)
|
||||
)
|
||||
self.assertEqual(
|
||||
RelativeTimeTest.delta.enforce_type('0:05:07'),
|
||||
datetime.timedelta(seconds=307)
|
||||
)
|
||||
with self.assertRaises(TypeError):
|
||||
assert RelativeTimeTest.delta.enforce_type(None) is None
|
||||
assert RelativeTimeTest.delta.enforce_type(datetime.timedelta(days=1, seconds=46799)) ==\
|
||||
datetime.timedelta(days=1, seconds=46799)
|
||||
assert RelativeTimeTest.delta.enforce_type('0:05:07') == datetime.timedelta(seconds=307)
|
||||
with pytest.raises(TypeError):
|
||||
RelativeTimeTest.delta.enforce_type([1])
|
||||
|
||||
def test_to_json(self):
|
||||
self.assertEqual(
|
||||
"01:02:03",
|
||||
RelativeTimeTest.delta.to_json(datetime.timedelta(seconds=3723))
|
||||
)
|
||||
self.assertEqual(
|
||||
"00:00:00",
|
||||
RelativeTimeTest.delta.to_json(None)
|
||||
)
|
||||
self.assertEqual(
|
||||
"00:01:40",
|
||||
RelativeTimeTest.delta.to_json(100.0)
|
||||
)
|
||||
assert '01:02:03' == RelativeTimeTest.delta.to_json(datetime.timedelta(seconds=3723))
|
||||
assert '00:00:00' == RelativeTimeTest.delta.to_json(None)
|
||||
assert '00:01:40' == RelativeTimeTest.delta.to_json(100.0)
|
||||
|
||||
error_msg = "RelativeTime max value is 23:59:59=86400.0 seconds, but 90000.0 seconds is passed"
|
||||
with self.assertRaisesRegex(ValueError, error_msg):
|
||||
RelativeTimeTest.delta.to_json(datetime.timedelta(seconds=90000))
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
with pytest.raises(TypeError):
|
||||
RelativeTimeTest.delta.to_json("123")
|
||||
|
||||
def test_str(self):
|
||||
self.assertEqual(
|
||||
"01:02:03",
|
||||
RelativeTimeTest.delta.to_json(datetime.timedelta(seconds=3723))
|
||||
)
|
||||
self.assertEqual(
|
||||
"11:02:03",
|
||||
RelativeTimeTest.delta.to_json(datetime.timedelta(seconds=39723))
|
||||
)
|
||||
assert '01:02:03' == RelativeTimeTest.delta.to_json(datetime.timedelta(seconds=3723))
|
||||
assert '11:02:03' == RelativeTimeTest.delta.to_json(datetime.timedelta(seconds=39723))
|
||||
|
||||
@@ -5,7 +5,7 @@ Grading tests
|
||||
|
||||
import unittest
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
from pytz import UTC
|
||||
import six
|
||||
@@ -28,26 +28,14 @@ class GradesheetTest(unittest.TestCase):
|
||||
|
||||
# No scores
|
||||
all_total, graded_total = aggregate_scores(scores)
|
||||
self.assertEqual(
|
||||
all_total,
|
||||
AggregatedScore(tw_earned=0, tw_possible=0, graded=False, **agg_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
graded_total,
|
||||
AggregatedScore(tw_earned=0, tw_possible=0, graded=True, **agg_fields),
|
||||
)
|
||||
assert all_total == AggregatedScore(tw_earned=0, tw_possible=0, graded=False, **agg_fields)
|
||||
assert graded_total == AggregatedScore(tw_earned=0, tw_possible=0, graded=True, **agg_fields)
|
||||
|
||||
# (0/5 non-graded)
|
||||
scores.append(ProblemScore(weighted_earned=0, weighted_possible=5, graded=False, **prob_fields))
|
||||
all_total, graded_total = aggregate_scores(scores)
|
||||
self.assertEqual(
|
||||
all_total,
|
||||
AggregatedScore(tw_earned=0, tw_possible=5, graded=False, **agg_fields),
|
||||
)
|
||||
self.assertEqual(
|
||||
graded_total,
|
||||
AggregatedScore(tw_earned=0, tw_possible=0, graded=True, **agg_fields),
|
||||
)
|
||||
assert all_total == AggregatedScore(tw_earned=0, tw_possible=5, graded=False, **agg_fields)
|
||||
assert graded_total == AggregatedScore(tw_earned=0, tw_possible=0, graded=True, **agg_fields)
|
||||
|
||||
# (0/5 non-graded) + (3/5 graded) = 3/10 total, 3/5 graded
|
||||
now = datetime.now()
|
||||
@@ -55,26 +43,14 @@ class GradesheetTest(unittest.TestCase):
|
||||
agg_fields['first_attempted'] = now
|
||||
scores.append(ProblemScore(weighted_earned=3, weighted_possible=5, graded=True, **prob_fields))
|
||||
all_total, graded_total = aggregate_scores(scores)
|
||||
self.assertAlmostEqual(
|
||||
all_total,
|
||||
AggregatedScore(tw_earned=3, tw_possible=10, graded=False, **agg_fields),
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
graded_total,
|
||||
AggregatedScore(tw_earned=3, tw_possible=5, graded=True, **agg_fields),
|
||||
)
|
||||
assert round(all_total - AggregatedScore(tw_earned=3, tw_possible=10, graded=False, **agg_fields), 7) >= 0
|
||||
assert round(graded_total - AggregatedScore(tw_earned=3, tw_possible=5, graded=True, **agg_fields), 7) >= 0
|
||||
|
||||
# (0/5 non-graded) + (3/5 graded) + (2/5 graded) = 5/15 total, 5/10 graded
|
||||
scores.append(ProblemScore(weighted_earned=2, weighted_possible=5, graded=True, **prob_fields))
|
||||
all_total, graded_total = aggregate_scores(scores)
|
||||
self.assertAlmostEqual(
|
||||
all_total,
|
||||
AggregatedScore(tw_earned=5, tw_possible=15, graded=False, **agg_fields),
|
||||
)
|
||||
self.assertAlmostEqual(
|
||||
graded_total,
|
||||
AggregatedScore(tw_earned=5, tw_possible=10, graded=True, **agg_fields),
|
||||
)
|
||||
assert round(all_total - AggregatedScore(tw_earned=5, tw_possible=15, graded=False, **agg_fields), 7) >= 0
|
||||
assert round(graded_total - AggregatedScore(tw_earned=5, tw_possible=10, graded=True, **agg_fields), 7) >= 0
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -147,25 +123,28 @@ class GraderTest(unittest.TestCase):
|
||||
homework_grader.grade(self.incomplete_gradesheet),
|
||||
no_drop_grader.grade(self.incomplete_gradesheet),
|
||||
]:
|
||||
self.assertAlmostEqual(graded['percent'], 0.0)
|
||||
assert round(graded['percent'] - 0.0, 7) >= 0
|
||||
# Make sure the breakdown includes 12 sections, plus one summary
|
||||
self.assertEqual(len(graded['section_breakdown']), 12 + 1)
|
||||
assert len(graded['section_breakdown']) == (12 + 1)
|
||||
|
||||
graded = homework_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.11) # 100% + 10% / 10 assignments
|
||||
self.assertEqual(len(graded['section_breakdown']), 12 + 1)
|
||||
assert round(graded['percent'] - 0.11, 7) >= 0
|
||||
# 100% + 10% / 10 assignments
|
||||
assert len(graded['section_breakdown']) == (12 + 1)
|
||||
|
||||
graded = no_drop_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.0916666666666666) # 100% + 10% / 12 assignments
|
||||
self.assertEqual(len(graded['section_breakdown']), 12 + 1)
|
||||
assert round(graded['percent'] - 0.0916666666666666, 7) >= 0
|
||||
# 100% + 10% / 12 assignments
|
||||
assert len(graded['section_breakdown']) == (12 + 1)
|
||||
|
||||
graded = overflow_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.8879999999999999) # 100% + 10% / 5 assignments
|
||||
self.assertEqual(len(graded['section_breakdown']), 7 + 1)
|
||||
assert round(graded['percent'] - 0.8879999999999999, 7) >= 0
|
||||
# 100% + 10% / 5 assignments
|
||||
assert len(graded['section_breakdown']) == (7 + 1)
|
||||
|
||||
graded = lab_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.92249999999999999)
|
||||
self.assertEqual(len(graded['section_breakdown']), 7 + 1)
|
||||
assert round(graded['percent'] - 0.9225, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (7 + 1)
|
||||
|
||||
def test_assignment_format_grader_on_single_section_entry(self):
|
||||
midterm_grader = graders.AssignmentFormatGrader("Midterm", 1, 0)
|
||||
@@ -174,14 +153,14 @@ class GraderTest(unittest.TestCase):
|
||||
midterm_grader.grade(self.empty_gradesheet),
|
||||
midterm_grader.grade(self.incomplete_gradesheet),
|
||||
]:
|
||||
self.assertAlmostEqual(graded['percent'], 0.0)
|
||||
assert round(graded['percent'] - 0.0, 7) >= 0
|
||||
# Make sure the breakdown includes just the one summary
|
||||
self.assertEqual(len(graded['section_breakdown']), 0 + 1)
|
||||
self.assertEqual(graded['section_breakdown'][0]['label'], 'Midterm')
|
||||
assert len(graded['section_breakdown']) == (0 + 1)
|
||||
assert graded['section_breakdown'][0]['label'] == 'Midterm'
|
||||
|
||||
graded = midterm_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.50)
|
||||
self.assertEqual(len(graded['section_breakdown']), 0 + 1)
|
||||
assert round(graded['percent'] - 0.5, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (0 + 1)
|
||||
|
||||
def test_weighted_subsections_grader(self):
|
||||
# First, a few sub graders
|
||||
@@ -218,24 +197,24 @@ class GraderTest(unittest.TestCase):
|
||||
empty_grader = graders.WeightedSubsectionsGrader([])
|
||||
|
||||
graded = weighted_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.50812499999999994)
|
||||
self.assertEqual(len(graded['section_breakdown']), (12 + 1) + (7 + 1) + 1)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 3)
|
||||
assert round(graded['percent'] - 0.5081249999999999, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (((12 + 1) + (7 + 1)) + 1)
|
||||
assert len(graded['grade_breakdown']) == 3
|
||||
|
||||
graded = over_one_weights_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.76624999999999999)
|
||||
self.assertEqual(len(graded['section_breakdown']), (12 + 1) + (7 + 1) + 1)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 3)
|
||||
assert round(graded['percent'] - 0.76625, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (((12 + 1) + (7 + 1)) + 1)
|
||||
assert len(graded['grade_breakdown']) == 3
|
||||
|
||||
graded = zero_weights_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.25)
|
||||
self.assertEqual(len(graded['section_breakdown']), (12 + 1) + (7 + 1) + 1)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 3)
|
||||
assert round(graded['percent'] - 0.25, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (((12 + 1) + (7 + 1)) + 1)
|
||||
assert len(graded['grade_breakdown']) == 3
|
||||
|
||||
graded = all_zero_weights_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.0)
|
||||
self.assertEqual(len(graded['section_breakdown']), (12 + 1) + (7 + 1) + 1)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 3)
|
||||
assert round(graded['percent'] - 0.0, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (((12 + 1) + (7 + 1)) + 1)
|
||||
assert len(graded['grade_breakdown']) == 3
|
||||
|
||||
for graded in [
|
||||
weighted_grader.grade(self.empty_gradesheet),
|
||||
@@ -243,14 +222,14 @@ class GraderTest(unittest.TestCase):
|
||||
zero_weights_grader.grade(self.empty_gradesheet),
|
||||
all_zero_weights_grader.grade(self.empty_gradesheet),
|
||||
]:
|
||||
self.assertAlmostEqual(graded['percent'], 0.0)
|
||||
self.assertEqual(len(graded['section_breakdown']), (12 + 1) + (7 + 1) + 1)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 3)
|
||||
assert round(graded['percent'] - 0.0, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (((12 + 1) + (7 + 1)) + 1)
|
||||
assert len(graded['grade_breakdown']) == 3
|
||||
|
||||
graded = empty_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.0)
|
||||
self.assertEqual(len(graded['section_breakdown']), 0)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 0)
|
||||
assert round(graded['percent'] - 0.0, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == 0
|
||||
assert len(graded['grade_breakdown']) == 0
|
||||
|
||||
def test_grade_with_string_min_count(self):
|
||||
"""
|
||||
@@ -282,9 +261,9 @@ class GraderTest(unittest.TestCase):
|
||||
])
|
||||
|
||||
graded = weighted_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.50812499999999994)
|
||||
self.assertEqual(len(graded['section_breakdown']), (12 + 1) + (7 + 1) + 1)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 3)
|
||||
assert round(graded['percent'] - 0.50812499999999994, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (((12 + 1) + (7 + 1)) + 1)
|
||||
assert len(graded['grade_breakdown']) == 3
|
||||
|
||||
def test_grader_from_conf(self):
|
||||
|
||||
@@ -319,22 +298,22 @@ class GraderTest(unittest.TestCase):
|
||||
empty_grader = graders.grader_from_conf([])
|
||||
|
||||
graded = weighted_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.50812499999999994)
|
||||
self.assertEqual(len(graded['section_breakdown']), (12 + 1) + (7 + 1) + 1)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 3)
|
||||
assert round(graded['percent'] - 0.5081249999999999, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (((12 + 1) + (7 + 1)) + 1)
|
||||
assert len(graded['grade_breakdown']) == 3
|
||||
|
||||
graded = empty_grader.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.0)
|
||||
self.assertEqual(len(graded['section_breakdown']), 0)
|
||||
self.assertEqual(len(graded['grade_breakdown']), 0)
|
||||
assert round(graded['percent'] - 0.0, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == 0
|
||||
assert len(graded['grade_breakdown']) == 0
|
||||
|
||||
# Test that graders can also be used instead of lists of dictionaries
|
||||
homework_grader = graders.AssignmentFormatGrader("Homework", 12, 2)
|
||||
homework_grader2 = graders.grader_from_conf(homework_grader)
|
||||
|
||||
graded = homework_grader2.grade(self.test_gradesheet)
|
||||
self.assertAlmostEqual(graded['percent'], 0.11)
|
||||
self.assertEqual(len(graded['section_breakdown']), 12 + 1)
|
||||
assert round(graded['percent'] - 0.11, 7) >= 0
|
||||
assert len(graded['section_breakdown']) == (12 + 1)
|
||||
|
||||
@ddt.data(
|
||||
(
|
||||
@@ -356,9 +335,9 @@ class GraderTest(unittest.TestCase):
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_grader_with_invalid_conf(self, invalid_conf, expected_error_message):
|
||||
with self.assertRaises(ValueError) as error:
|
||||
with pytest.raises(ValueError) as error:
|
||||
graders.grader_from_conf([invalid_conf])
|
||||
self.assertIn(expected_error_message, text_type(error.exception))
|
||||
assert expected_error_message in text_type(error.exception)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -380,7 +359,7 @@ class ShowCorrectnessTest(unittest.TestCase):
|
||||
"""
|
||||
Test that correctness is visible by default.
|
||||
"""
|
||||
self.assertTrue(ShowCorrectness.correctness_available())
|
||||
assert ShowCorrectness.correctness_available()
|
||||
|
||||
@ddt.data(
|
||||
(ShowCorrectness.ALWAYS, True),
|
||||
@@ -396,20 +375,16 @@ class ShowCorrectnessTest(unittest.TestCase):
|
||||
"""
|
||||
Test that correctness is visible when show_correctness is turned on.
|
||||
"""
|
||||
self.assertTrue(ShowCorrectness.correctness_available(
|
||||
show_correctness=show_correctness,
|
||||
has_staff_access=has_staff_access
|
||||
))
|
||||
assert ShowCorrectness.correctness_available(show_correctness=show_correctness,
|
||||
has_staff_access=has_staff_access)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_show_correctness_never(self, has_staff_access):
|
||||
"""
|
||||
Test that show_correctness="never" hides correctness from learners and course staff.
|
||||
"""
|
||||
self.assertFalse(ShowCorrectness.correctness_available(
|
||||
show_correctness=ShowCorrectness.NEVER,
|
||||
has_staff_access=has_staff_access
|
||||
))
|
||||
assert not ShowCorrectness.correctness_available(show_correctness=ShowCorrectness.NEVER,
|
||||
has_staff_access=has_staff_access)
|
||||
|
||||
@ddt.data(
|
||||
# Correctness not visible to learners if due date in the future
|
||||
@@ -439,7 +414,5 @@ class ShowCorrectnessTest(unittest.TestCase):
|
||||
due_date = None
|
||||
else:
|
||||
due_date = getattr(self, due_date_str)
|
||||
self.assertEqual(
|
||||
ShowCorrectness.correctness_available(ShowCorrectness.PAST_DUE, due_date, has_staff_access),
|
||||
expected_result
|
||||
)
|
||||
assert ShowCorrectness.correctness_available(ShowCorrectness.PAST_DUE, due_date, has_staff_access) ==\
|
||||
expected_result
|
||||
|
||||
@@ -50,10 +50,8 @@ class HtmlBlockCourseApiTestCase(unittest.TestCase):
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
|
||||
with override_settings(**settings):
|
||||
self.assertEqual(module.student_view_data(), dict(
|
||||
enabled=False,
|
||||
message='To enable, set FEATURES["ENABLE_HTML_XBLOCK_STUDENT_VIEW_DATA"]',
|
||||
))
|
||||
assert module.student_view_data() ==\
|
||||
dict(enabled=False, message='To enable, set FEATURES["ENABLE_HTML_XBLOCK_STUDENT_VIEW_DATA"]')
|
||||
|
||||
@ddt.data(
|
||||
'<h1>Some content</h1>', # Valid HTML
|
||||
@@ -78,7 +76,7 @@ class HtmlBlockCourseApiTestCase(unittest.TestCase):
|
||||
field_data = DictFieldData({'data': html})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
self.assertEqual(module.student_view_data(), dict(enabled=True, html=html))
|
||||
assert module.student_view_data() == dict(enabled=True, html=html)
|
||||
|
||||
@ddt.data(
|
||||
STUDENT_VIEW,
|
||||
@@ -93,7 +91,7 @@ class HtmlBlockCourseApiTestCase(unittest.TestCase):
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
rendered = module_system.render(module, view, {}).content
|
||||
self.assertIn(html, rendered)
|
||||
assert html in rendered
|
||||
|
||||
|
||||
class HtmlBlockSubstitutionTestCase(unittest.TestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -103,7 +101,7 @@ class HtmlBlockSubstitutionTestCase(unittest.TestCase): # lint-amnesty, pylint:
|
||||
field_data = DictFieldData({'data': sample_xml})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
self.assertEqual(module.get_html(), str(module_system.anonymous_student_id))
|
||||
assert module.get_html() == str(module_system.anonymous_student_id)
|
||||
|
||||
def test_substitution_course_id(self):
|
||||
sample_xml = '''%%COURSE_ID%%'''
|
||||
@@ -121,7 +119,7 @@ class HtmlBlockSubstitutionTestCase(unittest.TestCase): # lint-amnesty, pylint:
|
||||
block_id='block_id'
|
||||
)
|
||||
module.scope_ids.usage_id = usage_key
|
||||
self.assertEqual(module.get_html(), str(course_key))
|
||||
assert module.get_html() == str(course_key)
|
||||
|
||||
def test_substitution_without_magic_string(self):
|
||||
sample_xml = '''
|
||||
@@ -132,7 +130,7 @@ class HtmlBlockSubstitutionTestCase(unittest.TestCase): # lint-amnesty, pylint:
|
||||
field_data = DictFieldData({'data': sample_xml})
|
||||
module_system = get_test_system()
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
self.assertEqual(module.get_html(), sample_xml)
|
||||
assert module.get_html() == sample_xml
|
||||
|
||||
def test_substitution_without_anonymous_student_id(self):
|
||||
sample_xml = '''%%USER_ID%%'''
|
||||
@@ -140,7 +138,7 @@ class HtmlBlockSubstitutionTestCase(unittest.TestCase): # lint-amnesty, pylint:
|
||||
module_system = get_test_system()
|
||||
module_system.anonymous_student_id = None
|
||||
module = HtmlBlock(module_system, field_data, Mock())
|
||||
self.assertEqual(module.get_html(), sample_xml)
|
||||
assert module.get_html() == sample_xml
|
||||
|
||||
|
||||
class HtmlBlockIndexingTestCase(unittest.TestCase):
|
||||
@@ -155,10 +153,8 @@ class HtmlBlockIndexingTestCase(unittest.TestCase):
|
||||
</html>
|
||||
'''
|
||||
descriptor = instantiate_descriptor(data=sample_xml)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {"html_content": " Hello World! ", "display_name": "Text"},
|
||||
"content_type": "Text"
|
||||
})
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content': {'html_content': ' Hello World! ', 'display_name': 'Text'}, 'content_type': 'Text'}
|
||||
|
||||
def test_index_dictionary_cdata_html_module(self):
|
||||
sample_xml_cdata = '''
|
||||
@@ -168,10 +164,8 @@ class HtmlBlockIndexingTestCase(unittest.TestCase):
|
||||
</html>
|
||||
'''
|
||||
descriptor = instantiate_descriptor(data=sample_xml_cdata)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {"html_content": " This has CDATA in it. ", "display_name": "Text"},
|
||||
"content_type": "Text"
|
||||
})
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content': {'html_content': ' This has CDATA in it. ', 'display_name': 'Text'}, 'content_type': 'Text'}
|
||||
|
||||
def test_index_dictionary_multiple_spaces_html_module(self):
|
||||
sample_xml_tab_spaces = '''
|
||||
@@ -180,10 +174,8 @@ class HtmlBlockIndexingTestCase(unittest.TestCase):
|
||||
</html>
|
||||
'''
|
||||
descriptor = instantiate_descriptor(data=sample_xml_tab_spaces)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {"html_content": " Text has spaces :) ", "display_name": "Text"},
|
||||
"content_type": "Text"
|
||||
})
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content': {'html_content': ' Text has spaces :) ', 'display_name': 'Text'}, 'content_type': 'Text'}
|
||||
|
||||
def test_index_dictionary_html_module_with_comment(self):
|
||||
sample_xml_comment = '''
|
||||
@@ -193,10 +185,7 @@ class HtmlBlockIndexingTestCase(unittest.TestCase):
|
||||
</html>
|
||||
'''
|
||||
descriptor = instantiate_descriptor(data=sample_xml_comment)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {"html_content": " This has HTML comment in it. ", "display_name": "Text"},
|
||||
"content_type": "Text"
|
||||
})
|
||||
assert descriptor.index_dictionary() == {'content': {'html_content': ' This has HTML comment in it. ', 'display_name': 'Text'}, 'content_type': 'Text'} # pylint: disable=line-too-long
|
||||
|
||||
def test_index_dictionary_html_module_with_both_comments_and_cdata(self):
|
||||
sample_xml_mix_comment_cdata = '''
|
||||
@@ -209,10 +198,9 @@ class HtmlBlockIndexingTestCase(unittest.TestCase):
|
||||
</html>
|
||||
'''
|
||||
descriptor = instantiate_descriptor(data=sample_xml_mix_comment_cdata)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {"html_content": " This has HTML comment in it. HTML end. ", "display_name": "Text"},
|
||||
"content_type": "Text"
|
||||
})
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content': {'html_content': ' This has HTML comment in it. HTML end. ',
|
||||
'display_name': 'Text'}, 'content_type': 'Text'}
|
||||
|
||||
def test_index_dictionary_html_module_with_script_and_style_tags(self):
|
||||
sample_xml_style_script_tags = '''
|
||||
@@ -229,10 +217,9 @@ class HtmlBlockIndexingTestCase(unittest.TestCase):
|
||||
</html>
|
||||
'''
|
||||
descriptor = instantiate_descriptor(data=sample_xml_style_script_tags)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {"html_content": " This has HTML comment in it. HTML end. ", "display_name": "Text"},
|
||||
"content_type": "Text"
|
||||
})
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content': {'html_content': ' This has HTML comment in it. HTML end. ',
|
||||
'display_name': 'Text'}, 'content_type': 'Text'}
|
||||
|
||||
|
||||
class CourseInfoBlockTestCase(unittest.TestCase):
|
||||
|
||||
@@ -77,7 +77,7 @@ class BaseCourseTestCase(TestCase):
|
||||
xblock_select=only_xmodules,
|
||||
)
|
||||
courses = modulestore.get_courses()
|
||||
self.assertEqual(len(courses), 1)
|
||||
assert len(courses) == 1
|
||||
return courses[0]
|
||||
|
||||
|
||||
@@ -97,8 +97,8 @@ class PureXBlockImportTest(BaseCourseTestCase):
|
||||
def assert_xblocks_are_good(self, block):
|
||||
"""Assert a number of conditions that must be true for `block` to be good."""
|
||||
scope_ids = block.scope_ids
|
||||
self.assertIsNotNone(scope_ids.usage_id)
|
||||
self.assertIsNotNone(scope_ids.def_id)
|
||||
assert scope_ids.usage_id is not None
|
||||
assert scope_ids.def_id is not None
|
||||
|
||||
for child_id in block.children:
|
||||
child = block.runtime.get_block(child_id)
|
||||
@@ -114,9 +114,9 @@ class PureXBlockImportTest(BaseCourseTestCase):
|
||||
def test_parsing_pure_xblock(self, xml, mock_location):
|
||||
system = self.get_system(load_error_modules=False)
|
||||
descriptor = system.process_xml(xml)
|
||||
self.assertIsInstance(descriptor, GenericXBlock)
|
||||
assert isinstance(descriptor, GenericXBlock)
|
||||
self.assert_xblocks_are_good(descriptor)
|
||||
self.assertFalse(mock_location.called)
|
||||
assert not mock_location.called
|
||||
|
||||
|
||||
class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missing-class-docstring
|
||||
@@ -131,7 +131,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
|
||||
descriptor = system.process_xml(bad_xml)
|
||||
|
||||
self.assertEqual(descriptor.__class__.__name__, 'ErrorBlockWithMixins')
|
||||
assert descriptor.__class__.__name__ == 'ErrorBlockWithMixins'
|
||||
|
||||
def test_unique_url_names(self):
|
||||
'''Check that each error gets its very own url_name'''
|
||||
@@ -142,7 +142,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
descriptor1 = system.process_xml(bad_xml)
|
||||
descriptor2 = system.process_xml(bad_xml2)
|
||||
|
||||
self.assertNotEqual(descriptor1.location, descriptor2.location)
|
||||
assert descriptor1.location != descriptor2.location
|
||||
|
||||
# Check that each vertical gets its very own url_name
|
||||
bad_xml = '''<vertical display_name="abc"><problem url_name="exam1:2013_Spring:abc"/></vertical>'''
|
||||
@@ -151,7 +151,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
descriptor1 = system.process_xml(bad_xml)
|
||||
descriptor2 = system.process_xml(bad_xml2)
|
||||
|
||||
self.assertNotEqual(descriptor1.location, descriptor2.location)
|
||||
assert descriptor1.location != descriptor2.location
|
||||
|
||||
def test_reimport(self):
|
||||
'''Make sure an already-exported error xml tag loads properly'''
|
||||
@@ -165,10 +165,10 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
descriptor.add_xml_to_node(node)
|
||||
re_import_descriptor = system.process_xml(etree.tostring(node))
|
||||
|
||||
self.assertEqual(re_import_descriptor.__class__.__name__, 'ErrorBlockWithMixins')
|
||||
assert re_import_descriptor.__class__.__name__ == 'ErrorBlockWithMixins'
|
||||
|
||||
self.assertEqual(descriptor.contents, re_import_descriptor.contents)
|
||||
self.assertEqual(descriptor.error_msg, re_import_descriptor.error_msg)
|
||||
assert descriptor.contents == re_import_descriptor.contents
|
||||
assert descriptor.error_msg == re_import_descriptor.error_msg
|
||||
|
||||
def test_fixed_xml_tag(self):
|
||||
"""Make sure a tag that's been fixed exports as the original tag type"""
|
||||
@@ -189,7 +189,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
descriptor.add_xml_to_node(node)
|
||||
|
||||
# Now make sure the exported xml is a sequential
|
||||
self.assertEqual(node.tag, 'sequential')
|
||||
assert node.tag == 'sequential'
|
||||
|
||||
def course_descriptor_inheritance_check(self, descriptor, from_date_string, unicorn_color, course_run=RUN):
|
||||
"""
|
||||
@@ -197,16 +197,14 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
"""
|
||||
# pylint: disable=protected-access
|
||||
print((descriptor, descriptor._field_data))
|
||||
self.assertEqual(descriptor.due, ImportTestCase.date.from_json(from_date_string))
|
||||
assert descriptor.due == ImportTestCase.date.from_json(from_date_string)
|
||||
|
||||
# Check that the child inherits due correctly
|
||||
child = descriptor.get_children()[0]
|
||||
self.assertEqual(child.due, ImportTestCase.date.from_json(from_date_string))
|
||||
assert child.due == ImportTestCase.date.from_json(from_date_string)
|
||||
# need to convert v to canonical json b4 comparing
|
||||
self.assertEqual(
|
||||
ImportTestCase.date.to_json(ImportTestCase.date.from_json(from_date_string)),
|
||||
child.xblock_kvs.inherited_settings['due']
|
||||
)
|
||||
assert ImportTestCase.date.to_json(ImportTestCase.date.from_json(from_date_string)) ==\
|
||||
child.xblock_kvs.inherited_settings['due']
|
||||
|
||||
# Now export and check things
|
||||
file_system = OSFS(mkdtemp())
|
||||
@@ -216,30 +214,30 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
|
||||
# Check that the exported xml is just a pointer
|
||||
print(("Exported xml:", etree.tostring(node)))
|
||||
self.assertTrue(is_pointer_tag(node))
|
||||
assert is_pointer_tag(node)
|
||||
# but it's a special case course pointer
|
||||
self.assertEqual(node.attrib['course'], COURSE)
|
||||
self.assertEqual(node.attrib['org'], ORG)
|
||||
assert node.attrib['course'] == COURSE
|
||||
assert node.attrib['org'] == ORG
|
||||
|
||||
# Does the course still have unicorns?
|
||||
with descriptor.runtime.export_fs.open(u'course/{course_run}.xml'.format(course_run=course_run)) as f:
|
||||
course_xml = etree.fromstring(f.read())
|
||||
|
||||
self.assertEqual(course_xml.attrib['unicorn'], unicorn_color)
|
||||
assert course_xml.attrib['unicorn'] == unicorn_color
|
||||
|
||||
# the course and org tags should be _only_ in the pointer
|
||||
self.assertNotIn('course', course_xml.attrib)
|
||||
self.assertNotIn('org', course_xml.attrib)
|
||||
assert 'course' not in course_xml.attrib
|
||||
assert 'org' not in course_xml.attrib
|
||||
|
||||
# did we successfully strip the url_name from the definition contents?
|
||||
self.assertNotIn('url_name', course_xml.attrib)
|
||||
assert 'url_name' not in course_xml.attrib
|
||||
|
||||
# Does the chapter tag now have a due attribute?
|
||||
# hardcoded path to child
|
||||
with descriptor.runtime.export_fs.open(u'chapter/ch.xml') as f:
|
||||
chapter_xml = etree.fromstring(f.read())
|
||||
self.assertEqual(chapter_xml.tag, 'chapter')
|
||||
self.assertNotIn('due', chapter_xml.attrib)
|
||||
assert chapter_xml.tag == 'chapter'
|
||||
assert 'due' not in chapter_xml.attrib
|
||||
|
||||
def test_metadata_import_export(self):
|
||||
"""Two checks:
|
||||
@@ -290,7 +288,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
LibraryXMLModuleStore.patch_descriptor_kvs(descriptor)
|
||||
# '_unwrapped_field_data' is reset in `patch_descriptor_kvs`
|
||||
# pylint: disable=protected-access
|
||||
self.assertIsNot(original_unwrapped, descriptor._unwrapped_field_data)
|
||||
assert original_unwrapped is not descriptor._unwrapped_field_data
|
||||
compute_inherited_metadata(descriptor)
|
||||
# Check the course module, since it has inheritance
|
||||
descriptor = descriptor.get_children()[0]
|
||||
@@ -341,29 +339,23 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
"""
|
||||
Verifies that a default value of None (for due) does not get marked as inherited.
|
||||
"""
|
||||
self.assertEqual(descriptor.due, None)
|
||||
assert descriptor.due is None
|
||||
|
||||
# Check that the child does not inherit a value for due
|
||||
child = descriptor.get_children()[0]
|
||||
self.assertEqual(child.due, None)
|
||||
assert child.due is None
|
||||
|
||||
# Check that the child hasn't started yet
|
||||
self.assertLessEqual(
|
||||
datetime.datetime.now(UTC),
|
||||
child.start
|
||||
)
|
||||
assert datetime.datetime.now(UTC) <= child.start
|
||||
|
||||
def override_metadata_check(self, descriptor, child, course_due, child_due):
|
||||
"""
|
||||
Verifies that due date can be overriden at child level.
|
||||
"""
|
||||
self.assertEqual(descriptor.due, ImportTestCase.date.from_json(course_due))
|
||||
self.assertEqual(child.due, ImportTestCase.date.from_json(child_due))
|
||||
assert descriptor.due == ImportTestCase.date.from_json(course_due)
|
||||
assert child.due == ImportTestCase.date.from_json(child_due)
|
||||
# Test inherited metadata. Due does not appear here (because explicitly set on child).
|
||||
self.assertEqual(
|
||||
ImportTestCase.date.to_json(ImportTestCase.date.from_json(course_due)),
|
||||
child.xblock_kvs.inherited_settings['due']
|
||||
)
|
||||
assert ImportTestCase.date.to_json(ImportTestCase.date.from_json(course_due)) == child.xblock_kvs.inherited_settings['due'] # pylint: disable=line-too-long
|
||||
|
||||
def test_metadata_override_default(self):
|
||||
"""
|
||||
@@ -435,11 +427,11 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
|
||||
for xml_str in yes:
|
||||
print("should be True for {0}".format(xml_str))
|
||||
self.assertTrue(is_pointer_tag(etree.fromstring(xml_str)))
|
||||
assert is_pointer_tag(etree.fromstring(xml_str))
|
||||
|
||||
for xml_str in no:
|
||||
print("should be False for {0}".format(xml_str))
|
||||
self.assertFalse(is_pointer_tag(etree.fromstring(xml_str)))
|
||||
assert not is_pointer_tag(etree.fromstring(xml_str))
|
||||
|
||||
def test_metadata_inherit(self):
|
||||
"""Make sure that metadata is inherited properly"""
|
||||
@@ -450,7 +442,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
def check_for_key(key, node, value):
|
||||
"recursive check for presence of key"
|
||||
print("Checking {0}".format(text_type(node.location)))
|
||||
self.assertEqual(getattr(node, key), value)
|
||||
assert getattr(node, key) == value
|
||||
for c in node.get_children():
|
||||
check_for_key(key, c, value)
|
||||
|
||||
@@ -463,21 +455,21 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
toy = self.get_course('toy')
|
||||
two_toys = self.get_course('two_toys')
|
||||
|
||||
self.assertEqual(toy.url_name, "2012_Fall")
|
||||
self.assertEqual(two_toys.url_name, "TT_2012_Fall")
|
||||
assert toy.url_name == '2012_Fall'
|
||||
assert two_toys.url_name == 'TT_2012_Fall'
|
||||
|
||||
toy_ch = toy.get_children()[0]
|
||||
two_toys_ch = two_toys.get_children()[0]
|
||||
|
||||
self.assertEqual(toy_ch.display_name, "Overview")
|
||||
self.assertEqual(two_toys_ch.display_name, "Two Toy Overview")
|
||||
assert toy_ch.display_name == 'Overview'
|
||||
assert two_toys_ch.display_name == 'Two Toy Overview'
|
||||
|
||||
# Also check that the grading policy loaded
|
||||
self.assertEqual(two_toys.grade_cutoffs['C'], 0.5999)
|
||||
assert two_toys.grade_cutoffs['C'] == 0.5999
|
||||
|
||||
# Also check that keys from policy are run through the
|
||||
# appropriate attribute maps -- 'graded' should be True, not 'true'
|
||||
self.assertEqual(toy.graded, True)
|
||||
assert toy.graded is True
|
||||
|
||||
def test_static_tabs_import(self):
|
||||
"""Make sure that the static tabs are imported correctly"""
|
||||
@@ -487,14 +479,14 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
location_tab_syllabus = BlockUsageLocator(CourseLocator("edX", "toy", "2012_Fall", deprecated=True),
|
||||
"static_tab", "syllabus", deprecated=True)
|
||||
toy_tab_syllabus = modulestore.get_item(location_tab_syllabus)
|
||||
self.assertEqual(toy_tab_syllabus.display_name, 'Syllabus')
|
||||
self.assertEqual(toy_tab_syllabus.course_staff_only, False)
|
||||
assert toy_tab_syllabus.display_name == 'Syllabus'
|
||||
assert toy_tab_syllabus.course_staff_only is False
|
||||
|
||||
location_tab_resources = BlockUsageLocator(CourseLocator("edX", "toy", "2012_Fall", deprecated=True),
|
||||
"static_tab", "resources", deprecated=True)
|
||||
toy_tab_resources = modulestore.get_item(location_tab_resources)
|
||||
self.assertEqual(toy_tab_resources.display_name, 'Resources')
|
||||
self.assertEqual(toy_tab_resources.course_staff_only, True)
|
||||
assert toy_tab_resources.display_name == 'Resources'
|
||||
assert toy_tab_resources.course_staff_only is True
|
||||
|
||||
def test_definition_loading(self):
|
||||
"""When two courses share the same org and course name and
|
||||
@@ -512,8 +504,8 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
location_two = BlockUsageLocator(CourseLocator("edX", "toy", "TT_2012_Fall", deprecated=True),
|
||||
"video", "Welcome", deprecated=True)
|
||||
two_toy_video = modulestore.get_item(location_two)
|
||||
self.assertEqual(toy_video.youtube_id_1_0, "p2Q6BrNhdh8")
|
||||
self.assertEqual(two_toy_video.youtube_id_1_0, "p2Q6BrNhdh9")
|
||||
assert toy_video.youtube_id_1_0 == 'p2Q6BrNhdh8'
|
||||
assert two_toy_video.youtube_id_1_0 == 'p2Q6BrNhdh9'
|
||||
|
||||
def test_colon_in_url_name(self):
|
||||
"""Ensure that colons in url_names convert to file paths properly"""
|
||||
@@ -522,7 +514,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
# Not using get_courses because we need the modulestore object too afterward
|
||||
modulestore = XMLModuleStore(DATA_DIR, source_dirs=['toy'])
|
||||
courses = modulestore.get_courses()
|
||||
self.assertEqual(len(courses), 1)
|
||||
assert len(courses) == 1
|
||||
course = courses[0]
|
||||
|
||||
print("course errors:")
|
||||
@@ -531,20 +523,20 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
print(err)
|
||||
|
||||
chapters = course.get_children()
|
||||
self.assertEqual(len(chapters), 5)
|
||||
assert len(chapters) == 5
|
||||
|
||||
ch2 = chapters[1]
|
||||
self.assertEqual(ch2.url_name, "secret:magic")
|
||||
assert ch2.url_name == 'secret:magic'
|
||||
|
||||
print("Ch2 location: ", ch2.location)
|
||||
|
||||
also_ch2 = modulestore.get_item(ch2.location)
|
||||
self.assertEqual(ch2, also_ch2)
|
||||
assert ch2 == also_ch2
|
||||
|
||||
print("making sure html loaded")
|
||||
loc = course.id.make_usage_key('html', 'secret:toylab')
|
||||
html = modulestore.get_item(loc)
|
||||
self.assertEqual(html.display_name, "Toy lab")
|
||||
assert html.display_name == 'Toy lab'
|
||||
|
||||
def test_unicode(self):
|
||||
"""Check that courses with unicode characters in filenames and in
|
||||
@@ -556,7 +548,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
print("Starting import")
|
||||
modulestore = XMLModuleStore(DATA_DIR, source_dirs=['test_unicode'])
|
||||
courses = modulestore.get_courses()
|
||||
self.assertEqual(len(courses), 1)
|
||||
assert len(courses) == 1
|
||||
course = courses[0]
|
||||
|
||||
print("course errors:")
|
||||
@@ -569,12 +561,9 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
in modulestore.get_course_errors(course.id)
|
||||
]
|
||||
|
||||
self.assertTrue(any(
|
||||
expect in msg or expect in err
|
||||
for msg, err in errors
|
||||
))
|
||||
assert any((((expect in msg) or (expect in err)) for (msg, err) in errors))
|
||||
chapters = course.get_children()
|
||||
self.assertEqual(len(chapters), 4)
|
||||
assert len(chapters) == 4
|
||||
|
||||
def test_url_name_mangling(self):
|
||||
"""
|
||||
@@ -590,13 +579,13 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
ch1 = chapters[0]
|
||||
sections = ch1.get_children()
|
||||
|
||||
self.assertEqual(len(sections), 4)
|
||||
assert len(sections) == 4
|
||||
|
||||
for i in (2, 3):
|
||||
video = sections[i]
|
||||
# Name should be 'video_{hash}'
|
||||
print("video {0} url_name: {1}".format(i, video.url_name))
|
||||
self.assertEqual(len(video.url_name), len('video_') + 12)
|
||||
assert len(video.url_name) == (len('video_') + 12)
|
||||
|
||||
def test_poll_and_conditional_import(self):
|
||||
modulestore = XMLModuleStore(DATA_DIR, source_dirs=['conditional_and_poll'])
|
||||
@@ -606,26 +595,20 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
ch1 = chapters[0]
|
||||
sections = ch1.get_children()
|
||||
|
||||
self.assertEqual(len(sections), 1)
|
||||
assert len(sections) == 1
|
||||
|
||||
conditional_location = course.id.make_usage_key('conditional', 'condone')
|
||||
module = modulestore.get_item(conditional_location)
|
||||
self.assertEqual(len(module.children), 1)
|
||||
assert len(module.children) == 1
|
||||
|
||||
poll_location = course.id.make_usage_key('poll_question', 'first_poll')
|
||||
module = modulestore.get_item(poll_location)
|
||||
self.assertEqual(len(module.get_children()), 0)
|
||||
self.assertEqual(module.voted, False)
|
||||
self.assertEqual(module.poll_answer, '')
|
||||
self.assertEqual(module.poll_answers, {})
|
||||
self.assertEqual(
|
||||
module.answers,
|
||||
[
|
||||
{'text': u'Yes', 'id': 'Yes'},
|
||||
{'text': u'No', 'id': 'No'},
|
||||
{'text': u"Don't know", 'id': 'Dont_know'}
|
||||
]
|
||||
)
|
||||
assert len(module.get_children()) == 0
|
||||
assert module.voted is False
|
||||
assert module.poll_answer == ''
|
||||
assert module.poll_answers == {}
|
||||
assert module.answers ==\
|
||||
[{'text': u'Yes', 'id': 'Yes'}, {'text': u'No', 'id': 'No'}, {'text': u"Don't know", 'id': 'Dont_know'}]
|
||||
|
||||
def test_error_on_import(self):
|
||||
'''Check that when load_error_module is false, an exception is raised, rather than returning an ErrorBlock'''
|
||||
@@ -643,13 +626,13 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
ch1 = chapters[0]
|
||||
sections = ch1.get_children()
|
||||
|
||||
self.assertEqual(len(sections), 1)
|
||||
assert len(sections) == 1
|
||||
|
||||
location = course.id.make_usage_key('word_cloud', 'cloud1')
|
||||
module = modulestore.get_item(location)
|
||||
self.assertEqual(len(module.get_children()), 0)
|
||||
self.assertEqual(module.num_inputs, 5)
|
||||
self.assertEqual(module.num_top_words, 250)
|
||||
assert len(module.get_children()) == 0
|
||||
assert module.num_inputs == 5
|
||||
assert module.num_top_words == 250
|
||||
|
||||
def test_cohort_config(self):
|
||||
"""
|
||||
@@ -665,16 +648,16 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
||||
course = modulestore.get_course(toy_id)
|
||||
|
||||
# No config -> False
|
||||
self.assertFalse(course.is_cohorted)
|
||||
assert not course.is_cohorted
|
||||
|
||||
# empty config -> False
|
||||
course.cohort_config = {}
|
||||
self.assertFalse(course.is_cohorted)
|
||||
assert not course.is_cohorted
|
||||
|
||||
# false config -> False
|
||||
course.cohort_config = {'cohorted': False}
|
||||
self.assertFalse(course.is_cohorted)
|
||||
assert not course.is_cohorted
|
||||
|
||||
# and finally...
|
||||
course.cohort_config = {'cohorted': True}
|
||||
self.assertTrue(course.is_cohorted)
|
||||
assert course.is_cohorted
|
||||
|
||||
@@ -47,10 +47,10 @@ class IgnoredFilesTestCase(unittest.TestCase):
|
||||
static_content_importer.import_static_content_directory()
|
||||
saved_static_content = [call[0][0] for call in content_store.save.call_args_list]
|
||||
name_val = {sc.name: sc.data for sc in saved_static_content}
|
||||
self.assertIn("example.txt", name_val)
|
||||
self.assertIn(".example.txt", name_val)
|
||||
self.assertIn(b"GREEN", name_val["example.txt"])
|
||||
self.assertIn(b"BLUE", name_val[".example.txt"])
|
||||
self.assertNotIn("._example.txt", name_val)
|
||||
self.assertNotIn(".DS_Store", name_val)
|
||||
self.assertNotIn("example.txt~", name_val)
|
||||
assert 'example.txt' in name_val
|
||||
assert '.example.txt' in name_val
|
||||
assert b'GREEN' in name_val['example.txt']
|
||||
assert b'BLUE' in name_val['.example.txt']
|
||||
assert '._example.txt' not in name_val
|
||||
assert '.DS_Store' not in name_val
|
||||
assert 'example.txt~' not in name_val
|
||||
|
||||
@@ -117,7 +117,7 @@ class TestLibraryContentExportImport(LibraryContentTest):
|
||||
exported_olx = f.read()
|
||||
|
||||
# And compare.
|
||||
self.assertEqual(exported_olx, expected_olx)
|
||||
assert exported_olx == expected_olx
|
||||
|
||||
runtime = TestImportSystem(load_error_modules=True, course_id=lc_block.location.course_key)
|
||||
runtime.resources_fs = export_fs
|
||||
@@ -128,14 +128,14 @@ class TestLibraryContentExportImport(LibraryContentTest):
|
||||
imported_lc_block = LibraryContentBlock.parse_xml(olx_element, runtime, None, id_generator)
|
||||
|
||||
# Check the new XBlock has the same properties as the old one.
|
||||
self.assertEqual(imported_lc_block.display_name, lc_block.display_name)
|
||||
self.assertEqual(imported_lc_block.source_library_id, lc_block.source_library_id)
|
||||
self.assertEqual(imported_lc_block.source_library_version, lc_block.source_library_version)
|
||||
self.assertEqual(imported_lc_block.mode, lc_block.mode)
|
||||
self.assertEqual(imported_lc_block.max_count, lc_block.max_count)
|
||||
self.assertEqual(imported_lc_block.capa_type, lc_block.capa_type)
|
||||
self.assertEqual(len(imported_lc_block.children), 4)
|
||||
self.assertEqual(imported_lc_block.children, lc_block.children)
|
||||
assert imported_lc_block.display_name == lc_block.display_name
|
||||
assert imported_lc_block.source_library_id == lc_block.source_library_id
|
||||
assert imported_lc_block.source_library_version == lc_block.source_library_version
|
||||
assert imported_lc_block.mode == lc_block.mode
|
||||
assert imported_lc_block.max_count == lc_block.max_count
|
||||
assert imported_lc_block.capa_type == lc_block.capa_type
|
||||
assert len(imported_lc_block.children) == 4
|
||||
assert imported_lc_block.children == lc_block.children
|
||||
|
||||
|
||||
class LibraryContentBlockTestMixin(object):
|
||||
@@ -175,12 +175,12 @@ class LibraryContentBlockTestMixin(object):
|
||||
# Check that the LibraryContent block has no children initially
|
||||
# Normally the children get added when the "source_libraries" setting
|
||||
# is updated, but the way we do it through a factory doesn't do that.
|
||||
self.assertEqual(len(self.lc_block.children), 0)
|
||||
assert len(self.lc_block.children) == 0
|
||||
# Update the LibraryContent module:
|
||||
self.lc_block.refresh_children()
|
||||
self.lc_block = self.store.get_item(self.lc_block.location)
|
||||
# Check that all blocks from the library are now children of the block:
|
||||
self.assertEqual(len(self.lc_block.children), len(self.lib_blocks))
|
||||
assert len(self.lc_block.children) == len(self.lib_blocks)
|
||||
|
||||
def test_children_seen_by_a_user(self):
|
||||
"""
|
||||
@@ -190,14 +190,14 @@ class LibraryContentBlockTestMixin(object):
|
||||
self.lc_block = self.store.get_item(self.lc_block.location)
|
||||
self._bind_course_module(self.lc_block)
|
||||
# Make sure the runtime knows that the block's children vary per-user:
|
||||
self.assertTrue(self.lc_block.has_dynamic_children())
|
||||
assert self.lc_block.has_dynamic_children()
|
||||
|
||||
self.assertEqual(len(self.lc_block.children), len(self.lib_blocks))
|
||||
assert len(self.lc_block.children) == len(self.lib_blocks)
|
||||
|
||||
# Check how many children each user will see:
|
||||
self.assertEqual(len(self.lc_block.get_child_descriptors()), 1)
|
||||
assert len(self.lc_block.get_child_descriptors()) == 1
|
||||
# Check that get_content_titles() doesn't return titles for hidden/unused children
|
||||
self.assertEqual(len(self.lc_block.get_content_titles()), 1)
|
||||
assert len(self.lc_block.get_content_titles()) == 1
|
||||
|
||||
def test_validation_of_course_libraries(self):
|
||||
"""
|
||||
@@ -207,29 +207,32 @@ class LibraryContentBlockTestMixin(object):
|
||||
# When source_library_id is blank, the validation summary should say this block needs to be configured:
|
||||
self.lc_block.source_library_id = ""
|
||||
result = self.lc_block.validate()
|
||||
self.assertFalse(result) # Validation fails due to at least one warning/message
|
||||
self.assertTrue(result.summary)
|
||||
self.assertEqual(StudioValidationMessage.NOT_CONFIGURED, result.summary.type)
|
||||
assert not result
|
||||
# Validation fails due to at least one warning/message
|
||||
assert result.summary
|
||||
assert StudioValidationMessage.NOT_CONFIGURED == result.summary.type
|
||||
|
||||
# When source_library_id references a non-existent library, we should get an error:
|
||||
self.lc_block.source_library_id = "library-v1:BAD+WOLF"
|
||||
result = self.lc_block.validate()
|
||||
self.assertFalse(result) # Validation fails due to at least one warning/message
|
||||
self.assertTrue(result.summary)
|
||||
self.assertEqual(StudioValidationMessage.ERROR, result.summary.type)
|
||||
self.assertIn("invalid", result.summary.text)
|
||||
assert not result
|
||||
# Validation fails due to at least one warning/message
|
||||
assert result.summary
|
||||
assert StudioValidationMessage.ERROR == result.summary.type
|
||||
assert 'invalid' in result.summary.text
|
||||
|
||||
# When source_library_id is set but the block needs to be updated, the summary should say so:
|
||||
self.lc_block.source_library_id = six.text_type(self.library.location.library_key)
|
||||
result = self.lc_block.validate()
|
||||
self.assertFalse(result) # Validation fails due to at least one warning/message
|
||||
self.assertTrue(result.summary)
|
||||
self.assertEqual(StudioValidationMessage.WARNING, result.summary.type)
|
||||
self.assertIn("out of date", result.summary.text)
|
||||
assert not result
|
||||
# Validation fails due to at least one warning/message
|
||||
assert result.summary
|
||||
assert StudioValidationMessage.WARNING == result.summary.type
|
||||
assert 'out of date' in result.summary.text
|
||||
|
||||
# Now if we update the block, all validation should pass:
|
||||
self.lc_block.refresh_children()
|
||||
self.assertTrue(self.lc_block.validate())
|
||||
assert self.lc_block.validate()
|
||||
|
||||
def test_validation_of_matching_blocks(self):
|
||||
"""
|
||||
@@ -241,76 +244,80 @@ class LibraryContentBlockTestMixin(object):
|
||||
# In the normal studio editing process, editor_saved() calls refresh_children at this point
|
||||
self.lc_block.refresh_children()
|
||||
result = self.lc_block.validate()
|
||||
self.assertFalse(result) # Validation fails due to at least one warning/message
|
||||
self.assertTrue(result.summary)
|
||||
self.assertEqual(StudioValidationMessage.WARNING, result.summary.type)
|
||||
self.assertIn("only 4 matching problems", result.summary.text)
|
||||
assert not result
|
||||
# Validation fails due to at least one warning/message
|
||||
assert result.summary
|
||||
assert StudioValidationMessage.WARNING == result.summary.type
|
||||
assert 'only 4 matching problems' in result.summary.text
|
||||
|
||||
# Add some capa problems so we can check problem type validation messages
|
||||
self.lc_block.max_count = 1
|
||||
self._create_capa_problems()
|
||||
self.lc_block.refresh_children()
|
||||
self.assertTrue(self.lc_block.validate())
|
||||
assert self.lc_block.validate()
|
||||
|
||||
# Existing problem type should pass validation
|
||||
self.lc_block.max_count = 1
|
||||
self.lc_block.capa_type = 'multiplechoiceresponse'
|
||||
self.lc_block.refresh_children()
|
||||
self.assertTrue(self.lc_block.validate())
|
||||
assert self.lc_block.validate()
|
||||
|
||||
# ... unless requested more blocks than exists in library
|
||||
self.lc_block.max_count = 10
|
||||
self.lc_block.capa_type = 'multiplechoiceresponse'
|
||||
self.lc_block.refresh_children()
|
||||
result = self.lc_block.validate()
|
||||
self.assertFalse(result) # Validation fails due to at least one warning/message
|
||||
self.assertTrue(result.summary)
|
||||
self.assertEqual(StudioValidationMessage.WARNING, result.summary.type)
|
||||
self.assertIn("only 1 matching problem", result.summary.text)
|
||||
assert not result
|
||||
# Validation fails due to at least one warning/message
|
||||
assert result.summary
|
||||
assert StudioValidationMessage.WARNING == result.summary.type
|
||||
assert 'only 1 matching problem' in result.summary.text
|
||||
|
||||
# Missing problem type should always fail validation
|
||||
self.lc_block.max_count = 1
|
||||
self.lc_block.capa_type = 'customresponse'
|
||||
self.lc_block.refresh_children()
|
||||
result = self.lc_block.validate()
|
||||
self.assertFalse(result) # Validation fails due to at least one warning/message
|
||||
self.assertTrue(result.summary)
|
||||
self.assertEqual(StudioValidationMessage.WARNING, result.summary.type)
|
||||
self.assertIn("no matching problem types", result.summary.text)
|
||||
assert not result
|
||||
# Validation fails due to at least one warning/message
|
||||
assert result.summary
|
||||
assert StudioValidationMessage.WARNING == result.summary.type
|
||||
assert 'no matching problem types' in result.summary.text
|
||||
|
||||
def test_capa_type_filtering(self):
|
||||
"""
|
||||
Test that the capa type filter is actually filtering children
|
||||
"""
|
||||
self._create_capa_problems()
|
||||
self.assertEqual(len(self.lc_block.children), 0) # precondition check
|
||||
assert len(self.lc_block.children) == 0
|
||||
# precondition check
|
||||
self.lc_block.capa_type = "multiplechoiceresponse"
|
||||
self.lc_block.refresh_children()
|
||||
self.assertEqual(len(self.lc_block.children), 1)
|
||||
assert len(self.lc_block.children) == 1
|
||||
|
||||
self.lc_block.capa_type = "optionresponse"
|
||||
self.lc_block.refresh_children()
|
||||
self.assertEqual(len(self.lc_block.children), 3)
|
||||
assert len(self.lc_block.children) == 3
|
||||
|
||||
self.lc_block.capa_type = "coderesponse"
|
||||
self.lc_block.refresh_children()
|
||||
self.assertEqual(len(self.lc_block.children), 2)
|
||||
assert len(self.lc_block.children) == 2
|
||||
|
||||
self.lc_block.capa_type = "customresponse"
|
||||
self.lc_block.refresh_children()
|
||||
self.assertEqual(len(self.lc_block.children), 0)
|
||||
assert len(self.lc_block.children) == 0
|
||||
|
||||
self.lc_block.capa_type = ANY_CAPA_TYPE_VALUE
|
||||
self.lc_block.refresh_children()
|
||||
self.assertEqual(len(self.lc_block.children), len(self.lib_blocks) + 4)
|
||||
assert len(self.lc_block.children) == (len(self.lib_blocks) + 4)
|
||||
|
||||
def test_non_editable_settings(self):
|
||||
"""
|
||||
Test the settings that are marked as "non-editable".
|
||||
"""
|
||||
non_editable_metadata_fields = self.lc_block.non_editable_metadata_fields
|
||||
self.assertIn(LibraryContentBlock.mode, non_editable_metadata_fields)
|
||||
self.assertNotIn(LibraryContentBlock.display_name, non_editable_metadata_fields)
|
||||
assert LibraryContentBlock.mode in non_editable_metadata_fields
|
||||
assert LibraryContentBlock.display_name not in non_editable_metadata_fields
|
||||
|
||||
def test_overlimit_blocks_chosen_randomly(self):
|
||||
"""
|
||||
@@ -342,7 +349,7 @@ class LibraryContentBlockTestMixin(object):
|
||||
"""
|
||||
self.lc_block.max_count = count
|
||||
selected = self.lc_block.get_child_descriptors()
|
||||
self.assertEqual(len(selected), count)
|
||||
assert len(selected) == count
|
||||
return selected
|
||||
|
||||
|
||||
@@ -396,20 +403,22 @@ class TestLibraryContentRender(LibraryContentTest):
|
||||
""" Test preview view rendering """
|
||||
self.lc_block.refresh_children()
|
||||
self.lc_block = self.store.get_item(self.lc_block.location)
|
||||
self.assertEqual(len(self.lc_block.children), len(self.lib_blocks))
|
||||
assert len(self.lc_block.children) == len(self.lib_blocks)
|
||||
self._bind_course_module(self.lc_block)
|
||||
rendered = self.lc_block.render(AUTHOR_VIEW, {'root_xblock': self.lc_block})
|
||||
self.assertIn("Hello world from block 1", rendered.content)
|
||||
assert 'Hello world from block 1' in rendered.content
|
||||
|
||||
def test_author_view(self):
|
||||
""" Test author view rendering """
|
||||
self.lc_block.refresh_children()
|
||||
self.lc_block = self.store.get_item(self.lc_block.location)
|
||||
self.assertEqual(len(self.lc_block.children), len(self.lib_blocks))
|
||||
assert len(self.lc_block.children) == len(self.lib_blocks)
|
||||
self._bind_course_module(self.lc_block)
|
||||
rendered = self.lc_block.render(AUTHOR_VIEW, {})
|
||||
self.assertEqual("", rendered.content) # content should be empty
|
||||
self.assertEqual("LibraryContentAuthorView", rendered.js_init_fn) # but some js initialization should happen
|
||||
assert '' == rendered.content
|
||||
# content should be empty
|
||||
assert 'LibraryContentAuthorView' == rendered.js_init_fn
|
||||
# but some js initialization should happen
|
||||
|
||||
|
||||
class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
@@ -429,11 +438,11 @@ class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
"""
|
||||
Check that a LibraryContentBlock analytics event was published by self.lc_block.
|
||||
"""
|
||||
self.assertTrue(self.publisher.called)
|
||||
self.assertTrue(len(self.publisher.call_args[0]), 3) # pylint:disable=unsubscriptable-object
|
||||
assert self.publisher.called
|
||||
assert len(self.publisher.call_args[0]) == 3 # pylint:disable=unsubscriptable-object
|
||||
_, event_name, event_data = self.publisher.call_args[0] # pylint:disable=unsubscriptable-object
|
||||
self.assertEqual(event_name, "edx.librarycontentblock.content.{}".format(event_type))
|
||||
self.assertEqual(event_data["location"], six.text_type(self.lc_block.location))
|
||||
assert event_name == 'edx.librarycontentblock.content.{}'.format(event_type)
|
||||
assert event_data['location'] == six.text_type(self.lc_block.location)
|
||||
return event_data
|
||||
|
||||
def test_assigned_event(self):
|
||||
@@ -443,7 +452,7 @@ class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
# In the beginning was the lc_block and it assigned one child to the student:
|
||||
child = self.lc_block.get_child_descriptors()[0]
|
||||
child_lib_location, child_lib_version = self.store.get_block_original_usage(child.location)
|
||||
self.assertIsInstance(child_lib_version, ObjectId)
|
||||
assert isinstance(child_lib_version, ObjectId)
|
||||
event_data = self._assert_event_was_published("assigned")
|
||||
block_info = {
|
||||
"usage_key": six.text_type(child.location),
|
||||
@@ -451,25 +460,23 @@ class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
"original_usage_version": six.text_type(child_lib_version),
|
||||
"descendants": [],
|
||||
}
|
||||
self.assertEqual(event_data, {
|
||||
"location": six.text_type(self.lc_block.location),
|
||||
"added": [block_info],
|
||||
"result": [block_info],
|
||||
"previous_count": 0,
|
||||
"max_count": 1,
|
||||
})
|
||||
assert event_data ==\
|
||||
{'location': six.text_type(self.lc_block.location),
|
||||
'added': [block_info],
|
||||
'result': [block_info],
|
||||
'previous_count': 0, 'max_count': 1}
|
||||
self.publisher.reset_mock()
|
||||
|
||||
# Now increase max_count so that one more child will be added:
|
||||
self.lc_block.max_count = 2
|
||||
children = self.lc_block.get_child_descriptors()
|
||||
self.assertEqual(len(children), 2)
|
||||
assert len(children) == 2
|
||||
child, new_child = children if children[0].location == child.location else reversed(children)
|
||||
event_data = self._assert_event_was_published("assigned")
|
||||
self.assertEqual(event_data["added"][0]["usage_key"], six.text_type(new_child.location))
|
||||
self.assertEqual(len(event_data["result"]), 2)
|
||||
self.assertEqual(event_data["previous_count"], 1)
|
||||
self.assertEqual(event_data["max_count"], 2)
|
||||
assert event_data['added'][0]['usage_key'] == six.text_type(new_child.location)
|
||||
assert len(event_data['result']) == 2
|
||||
assert event_data['previous_count'] == 1
|
||||
assert event_data['max_count'] == 2
|
||||
|
||||
def test_assigned_event_published(self):
|
||||
"""
|
||||
@@ -512,8 +519,9 @@ class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
event_data = self._assert_event_was_published("assigned")
|
||||
|
||||
for block_list in (event_data["added"], event_data["result"]):
|
||||
self.assertEqual(len(block_list), 1) # main_vertical is the only root block added, and is the only result.
|
||||
self.assertEqual(block_list[0]["usage_key"], six.text_type(course_usage_main_vertical))
|
||||
assert len(block_list) == 1
|
||||
# main_vertical is the only root block added, and is the only result.
|
||||
assert block_list[0]['usage_key'] == six.text_type(course_usage_main_vertical)
|
||||
|
||||
# Check that "descendants" is a flat, unordered list of all of main_vertical's descendants:
|
||||
descendants_expected = (
|
||||
@@ -528,9 +536,9 @@ class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
"original_usage_key": six.text_type(lib_key),
|
||||
"original_usage_version": six.text_type(self.store.get_block_original_usage(course_usage_key)[1]),
|
||||
}
|
||||
self.assertEqual(len(block_list[0]["descendants"]), len(descendant_data_expected))
|
||||
assert len(block_list[0]['descendants']) == len(descendant_data_expected)
|
||||
for descendant in block_list[0]["descendants"]:
|
||||
self.assertEqual(descendant, descendant_data_expected.get(descendant["usage_key"]))
|
||||
assert descendant == descendant_data_expected.get(descendant['usage_key'])
|
||||
|
||||
def test_removed_overlimit(self):
|
||||
"""
|
||||
@@ -544,11 +552,11 @@ class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
|
||||
# Check that the event says that one block was removed, leaving no blocks left:
|
||||
children = self.lc_block.get_child_descriptors()
|
||||
self.assertEqual(len(children), 0)
|
||||
assert len(children) == 0
|
||||
event_data = self._assert_event_was_published("removed")
|
||||
self.assertEqual(len(event_data["removed"]), 1)
|
||||
self.assertEqual(event_data["result"], [])
|
||||
self.assertEqual(event_data["reason"], "overlimit")
|
||||
assert len(event_data['removed']) == 1
|
||||
assert event_data['result'] == []
|
||||
assert event_data['reason'] == 'overlimit'
|
||||
|
||||
def test_removed_invalid(self):
|
||||
"""
|
||||
@@ -559,14 +567,14 @@ class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
self.lc_block.get_child_descriptors() # This line is needed in the test environment or the change has no effect
|
||||
self.lc_block.max_count = 2
|
||||
initial_blocks_assigned = self.lc_block.get_child_descriptors()
|
||||
self.assertEqual(len(initial_blocks_assigned), 2)
|
||||
assert len(initial_blocks_assigned) == 2
|
||||
self.publisher.reset_mock() # Clear the "assigned" event that was just published.
|
||||
# Now make sure that one of the assigned blocks will have to be un-assigned.
|
||||
# To cause an "invalid" event, we delete all blocks from the content library
|
||||
# except for one of the two already assigned to the student:
|
||||
keep_block_key = initial_blocks_assigned[0].location
|
||||
keep_block_lib_usage_key, keep_block_lib_version = self.store.get_block_original_usage(keep_block_key)
|
||||
self.assertIsNotNone(keep_block_lib_usage_key)
|
||||
assert keep_block_lib_usage_key is not None
|
||||
deleted_block_key = initial_blocks_assigned[1].location
|
||||
self.library.children = [keep_block_lib_usage_key]
|
||||
self.store.update_item(self.library, self.user_id)
|
||||
@@ -574,19 +582,15 @@ class TestLibraryContentAnalytics(LibraryContentTest):
|
||||
|
||||
# Check that the event says that one block was removed, leaving one block left:
|
||||
children = self.lc_block.get_child_descriptors()
|
||||
self.assertEqual(len(children), 1)
|
||||
assert len(children) == 1
|
||||
event_data = self._assert_event_was_published("removed")
|
||||
self.assertEqual(event_data["removed"], [{
|
||||
"usage_key": six.text_type(deleted_block_key),
|
||||
"original_usage_key": None, # Note: original_usage_key info is sadly unavailable because the block has been
|
||||
# deleted so that info can no longer be retrieved
|
||||
"original_usage_version": None,
|
||||
"descendants": [],
|
||||
}])
|
||||
self.assertEqual(event_data["result"], [{
|
||||
"usage_key": six.text_type(keep_block_key),
|
||||
"original_usage_key": six.text_type(keep_block_lib_usage_key),
|
||||
"original_usage_version": six.text_type(keep_block_lib_version),
|
||||
"descendants": [],
|
||||
}])
|
||||
self.assertEqual(event_data["reason"], "invalid")
|
||||
assert event_data['removed'] ==\
|
||||
[{'usage_key': six.text_type(deleted_block_key),
|
||||
'original_usage_key': None,
|
||||
'original_usage_version': None,
|
||||
'descendants': []}]
|
||||
assert event_data['result'] ==\
|
||||
[{'usage_key': six.text_type(keep_block_key),
|
||||
'original_usage_key': six.text_type(keep_block_lib_usage_key),
|
||||
'original_usage_version': six.text_type(keep_block_lib_version), 'descendants': []}]
|
||||
assert event_data['reason'] == 'invalid'
|
||||
|
||||
@@ -51,7 +51,7 @@ class TestLibraryRoot(MixedSplitTestCase):
|
||||
# Patch the HTML block to always render "Hello world"
|
||||
|
||||
result = library.render(AUTHOR_VIEW, context)
|
||||
self.assertIn(message, result.content)
|
||||
assert message in result.content
|
||||
|
||||
def test_library_author_view_with_paging(self):
|
||||
"""
|
||||
@@ -81,7 +81,7 @@ class TestLibraryRoot(MixedSplitTestCase):
|
||||
result = library.render(AUTHOR_VIEW, context)
|
||||
|
||||
for expected_block in expected_blocks:
|
||||
self.assertIn(expected_block.data, result.content)
|
||||
assert expected_block.data in result.content
|
||||
|
||||
render_and_check_contents(0, 3)
|
||||
render_and_check_contents(1, 3)
|
||||
|
||||
@@ -47,8 +47,8 @@ class LibrarySourcedBlockTestCase(ContentLibrariesRestApiTest):
|
||||
|
||||
# Check if student_view renders the children correctly
|
||||
res = self.get_block_view(self.source_block, STUDENT_VIEW)
|
||||
self.assertIn('Student Preview Test 1', res)
|
||||
self.assertIn('Student Preview Test 2', res)
|
||||
assert 'Student Preview Test 1' in res
|
||||
assert 'Student Preview Test 2' in res
|
||||
|
||||
def test_block_limits(self):
|
||||
# Create a blockstore content library
|
||||
@@ -59,8 +59,8 @@ class LibrarySourcedBlockTestCase(ContentLibrariesRestApiTest):
|
||||
# Import the html blocks from the library to the course
|
||||
post_data = {"values": {"source_block_ids": blocks}, "defaults": ["display_name"]}
|
||||
res = self.client.post(self.submit_url, data=post_data, format='json')
|
||||
self.assertEqual(res.status_code, 400)
|
||||
self.assertEqual(res.json()['error']['messages'][0]['text'], "A maximum of 10 components may be added.")
|
||||
assert res.status_code == 400
|
||||
assert res.json()['error']['messages'][0]['text'] == 'A maximum of 10 components may be added.'
|
||||
|
||||
def get_block_view(self, block, view, context=None):
|
||||
"""
|
||||
|
||||
@@ -28,8 +28,8 @@ class LibraryToolsServiceTest(MixedSplitTestCase):
|
||||
"""
|
||||
_ = LibraryFactory.create(modulestore=self.store)
|
||||
all_libraries = self.tools.list_available_libraries()
|
||||
self.assertTrue(all_libraries)
|
||||
self.assertEqual(len(all_libraries), 1)
|
||||
assert all_libraries
|
||||
assert len(all_libraries) == 1
|
||||
|
||||
@patch('xmodule.modulestore.split_mongo.split.SplitMongoModuleStore.get_library_summaries')
|
||||
def test_list_available_libraries_fetch(self, mock_get_library_summaries):
|
||||
@@ -37,7 +37,7 @@ class LibraryToolsServiceTest(MixedSplitTestCase):
|
||||
Test that library list is compiled using light weight library summary objects.
|
||||
"""
|
||||
_ = self.tools.list_available_libraries()
|
||||
self.assertTrue(mock_get_library_summaries.called)
|
||||
assert mock_get_library_summaries.called
|
||||
|
||||
|
||||
class ContentLibraryToolsTest(MixedSplitTestCase, ContentLibrariesRestApiTest):
|
||||
@@ -69,28 +69,28 @@ class ContentLibraryToolsTest(MixedSplitTestCase, ContentLibrariesRestApiTest):
|
||||
self.tools.import_from_blockstore(sourced_block, [unit_block_id])
|
||||
|
||||
# Verify imported block with its children
|
||||
self.assertEqual(len(sourced_block.children), 1)
|
||||
self.assertEqual(sourced_block.children[0].category, 'unit')
|
||||
assert len(sourced_block.children) == 1
|
||||
assert sourced_block.children[0].category == 'unit'
|
||||
|
||||
imported_unit_block = self.store.get_item(sourced_block.children[0])
|
||||
self.assertEqual(len(imported_unit_block.children), 1)
|
||||
self.assertEqual(imported_unit_block.children[0].category, 'html')
|
||||
assert len(imported_unit_block.children) == 1
|
||||
assert imported_unit_block.children[0].category == 'html'
|
||||
|
||||
imported_html_block = self.store.get_item(imported_unit_block.children[0])
|
||||
self.assertIn('Hello world', imported_html_block.data)
|
||||
assert 'Hello world' in imported_html_block.data
|
||||
|
||||
# Check that assets were imported and static paths were modified after importing
|
||||
assets = library_api.get_library_block_static_asset_files(html_block.scope_ids.usage_id)
|
||||
self.assertEqual(len(assets), 1)
|
||||
self.assertIn(assets[0].url, imported_html_block.data)
|
||||
assert len(assets) == 1
|
||||
assert assets[0].url in imported_html_block.data
|
||||
|
||||
# Check that reimporting updates the target block
|
||||
self._set_library_block_olx(html_block_id, '<html><a href="/static/test.txt">Foo bar</a></html>')
|
||||
self.tools.import_from_blockstore(sourced_block, [unit_block_id])
|
||||
|
||||
self.assertEqual(len(sourced_block.children), 1)
|
||||
assert len(sourced_block.children) == 1
|
||||
imported_unit_block = self.store.get_item(sourced_block.children[0])
|
||||
self.assertEqual(len(imported_unit_block.children), 1)
|
||||
assert len(imported_unit_block.children) == 1
|
||||
imported_html_block = self.store.get_item(imported_unit_block.children[0])
|
||||
self.assertNotIn('Hello world', imported_html_block.data)
|
||||
self.assertIn('Foo bar', imported_html_block.data)
|
||||
assert 'Hello world' not in imported_html_block.data
|
||||
assert 'Foo bar' in imported_html_block.data
|
||||
|
||||
@@ -49,10 +49,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
)
|
||||
for case in test_cases:
|
||||
self.xmodule.score_comment = case[0]
|
||||
self.assertEqual(
|
||||
case[1],
|
||||
self.xmodule.get_context()['comment']
|
||||
)
|
||||
assert case[1] == self.xmodule.get_context()['comment']
|
||||
|
||||
def test_lti20_rest_bad_contenttype(self):
|
||||
"""
|
||||
@@ -81,7 +78,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
request = Mock(headers={u'Content-Type': u'application/vnd.ims.lis.v2.result+json'})
|
||||
self.xmodule.verify_lti_2_0_result_rest_headers(request)
|
||||
# We just want the above call to complete without exceptions, and to have called verify_oauth_body_sign
|
||||
self.assertTrue(self.xmodule.verify_oauth_body_sign.called)
|
||||
assert self.xmodule.verify_oauth_body_sign.called
|
||||
|
||||
BAD_DISPATCH_INPUTS = [
|
||||
None,
|
||||
@@ -115,7 +112,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
fit the form user/<anon_id>
|
||||
"""
|
||||
for ginput, expected in self.GOOD_DISPATCH_INPUTS:
|
||||
self.assertEqual(self.xmodule.parse_lti_2_0_handler_suffix(ginput), expected)
|
||||
assert self.xmodule.parse_lti_2_0_handler_suffix(ginput) == expected
|
||||
|
||||
BAD_JSON_INPUTS = [
|
||||
# (bad inputs, error message expected)
|
||||
@@ -188,8 +185,8 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
"""
|
||||
for json_str, expected_comment in self.GOOD_JSON_INPUTS:
|
||||
score, comment = self.xmodule.parse_lti_2_0_result_json(json_str)
|
||||
self.assertEqual(score, 0.1)
|
||||
self.assertEqual(comment, expected_comment)
|
||||
assert score == 0.1
|
||||
assert comment == expected_comment
|
||||
|
||||
GOOD_JSON_PUT = textwrap.dedent(u"""
|
||||
{"@type": "Result",
|
||||
@@ -253,15 +250,13 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
# Now assert there's no score
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIsNone(self.xmodule.module_score)
|
||||
self.assertEqual(self.xmodule.score_comment, u"")
|
||||
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # lint-amnesty, pylint: disable=unpacking-non-sequence
|
||||
self.assertEqual(
|
||||
called_grade_obj,
|
||||
{'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True},
|
||||
)
|
||||
self.assertEqual(evt_type, 'grade')
|
||||
assert response.status_code == 200
|
||||
assert self.xmodule.module_score is None
|
||||
assert self.xmodule.score_comment == u''
|
||||
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence
|
||||
assert called_grade_obj ==\
|
||||
{'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True}
|
||||
assert evt_type == 'grade'
|
||||
|
||||
def test_lti20_delete_success(self):
|
||||
"""
|
||||
@@ -276,15 +271,13 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
# Now assert there's no score
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIsNone(self.xmodule.module_score)
|
||||
self.assertEqual(self.xmodule.score_comment, u"")
|
||||
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # lint-amnesty, pylint: disable=unpacking-non-sequence
|
||||
self.assertEqual(
|
||||
called_grade_obj,
|
||||
{'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True},
|
||||
)
|
||||
self.assertEqual(evt_type, 'grade')
|
||||
assert response.status_code == 200
|
||||
assert self.xmodule.module_score is None
|
||||
assert self.xmodule.score_comment == u''
|
||||
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence
|
||||
assert called_grade_obj ==\
|
||||
{'user_id': self.USER_STANDIN.id, 'value': None, 'max_value': None, 'score_deleted': True}
|
||||
assert evt_type == 'grade'
|
||||
|
||||
def test_lti20_put_set_score_success(self):
|
||||
"""
|
||||
@@ -295,15 +288,13 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
# Now assert
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(self.xmodule.module_score, 0.1)
|
||||
self.assertEqual(self.xmodule.score_comment, u"ಠ益ಠ")
|
||||
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # lint-amnesty, pylint: disable=unpacking-non-sequence
|
||||
self.assertEqual(evt_type, 'grade')
|
||||
self.assertEqual(
|
||||
called_grade_obj,
|
||||
{'user_id': self.USER_STANDIN.id, 'value': 0.1, 'max_value': 1.0, 'score_deleted': False},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert self.xmodule.module_score == 0.1
|
||||
assert self.xmodule.score_comment == u'ಠ益ಠ'
|
||||
(_, evt_type, called_grade_obj), _ = self.system.publish.call_args # pylint: disable=unpacking-non-sequence
|
||||
assert evt_type == 'grade'
|
||||
assert called_grade_obj ==\
|
||||
{'user_id': self.USER_STANDIN.id, 'value': 0.1, 'max_value': 1.0, 'score_deleted': False}
|
||||
|
||||
def test_lti20_get_no_score_success(self):
|
||||
"""
|
||||
@@ -314,9 +305,8 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
# Now assert
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json, {"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
|
||||
"@type": "Result"})
|
||||
assert response.status_code == 200
|
||||
assert response.json == {'@context': 'http://purl.imsglobal.org/ctx/lis/v2/Result', '@type': 'Result'}
|
||||
|
||||
def test_lti20_get_with_score_success(self):
|
||||
"""
|
||||
@@ -331,11 +321,10 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
# Now call the handler
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
# Now assert
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json, {"@context": "http://purl.imsglobal.org/ctx/lis/v2/Result",
|
||||
"@type": "Result",
|
||||
"resultScore": SCORE,
|
||||
"comment": COMMENT})
|
||||
assert response.status_code == 200
|
||||
assert response.json ==\
|
||||
{'@context': 'http://purl.imsglobal.org/ctx/lis/v2/Result',
|
||||
'@type': 'Result', 'resultScore': SCORE, 'comment': COMMENT}
|
||||
|
||||
UNSUPPORTED_HTTP_METHODS = ["OPTIONS", "HEAD", "POST", "TRACE", "CONNECT"]
|
||||
|
||||
@@ -348,7 +337,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
for bad_method in self.UNSUPPORTED_HTTP_METHODS:
|
||||
mock_request.method = bad_method
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
self.assertEqual(response.status_code, 404)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_lti20_request_handler_bad_headers(self):
|
||||
"""
|
||||
@@ -358,7 +347,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
self.xmodule.verify_lti_2_0_result_rest_headers = Mock(side_effect=LTIError())
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
self.assertEqual(response.status_code, 401)
|
||||
assert response.status_code == 401
|
||||
|
||||
def test_lti20_request_handler_bad_dispatch_user(self):
|
||||
"""
|
||||
@@ -367,7 +356,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
self.setup_system_xmodule_mocks_for_lti20_request_test()
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, None)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_lti20_request_handler_bad_json(self):
|
||||
"""
|
||||
@@ -377,7 +366,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
self.xmodule.parse_lti_2_0_result_json = Mock(side_effect=LTIError())
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
self.assertEqual(response.status_code, 404)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_lti20_request_handler_bad_user(self):
|
||||
"""
|
||||
@@ -387,7 +376,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
self.system.get_real_user = Mock(return_value=None)
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
self.assertEqual(response.status_code, 404)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_lti20_request_handler_grade_past_due(self):
|
||||
"""
|
||||
@@ -398,4 +387,4 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
||||
self.xmodule.accept_grades_past_due = False
|
||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||
response = self.xmodule.lti_2_0_result_rest_handler(mock_request, u"user/abcd")
|
||||
self.assertEqual(response.status_code, 404)
|
||||
assert response.status_code == 404
|
||||
|
||||
@@ -7,6 +7,7 @@ import textwrap
|
||||
import unittest
|
||||
from copy import copy
|
||||
|
||||
import pytest
|
||||
import six
|
||||
from lxml import etree
|
||||
from mock import Mock, PropertyMock, patch
|
||||
@@ -139,7 +140,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
'messageIdentifier': self.defaults['messageIdentifier'],
|
||||
}
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
self.assertDictEqual(expected_response, real_response)
|
||||
|
||||
@patch(
|
||||
@@ -163,7 +164,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
'description': 'OAuth verification error: Malformed authorization header',
|
||||
'messageIdentifier': self.defaults['messageIdentifier'],
|
||||
}
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
self.assertDictEqual(expected_response, real_response)
|
||||
|
||||
def test_real_user_is_none(self):
|
||||
@@ -183,7 +184,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
'description': 'User not found.',
|
||||
'messageIdentifier': self.defaults['messageIdentifier'],
|
||||
}
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
self.assertDictEqual(expected_response, real_response)
|
||||
|
||||
def test_grade_past_due(self):
|
||||
@@ -203,8 +204,8 @@ class LTIBlockTest(unittest.TestCase):
|
||||
'description': 'Grade is past due',
|
||||
'messageIdentifier': 'unknown',
|
||||
}
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(expected_response, real_response)
|
||||
assert response.status_code == 200
|
||||
assert expected_response == real_response
|
||||
|
||||
def test_grade_not_in_range(self):
|
||||
"""
|
||||
@@ -221,7 +222,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
'description': 'Request body XML parsing error: score value outside the permitted range of 0-1.',
|
||||
'messageIdentifier': 'unknown',
|
||||
}
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
self.assertDictEqual(expected_response, real_response)
|
||||
|
||||
def test_bad_grade_decimal(self):
|
||||
@@ -243,7 +244,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
'description': u'Request body XML parsing error: {}'.format(msg),
|
||||
'messageIdentifier': 'unknown',
|
||||
}
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
self.assertDictEqual(expected_response, real_response)
|
||||
|
||||
def test_unsupported_action(self):
|
||||
@@ -262,7 +263,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
'description': 'Target does not support the requested operation.',
|
||||
'messageIdentifier': self.defaults['messageIdentifier'],
|
||||
}
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
self.assertDictEqual(expected_response, real_response)
|
||||
|
||||
def test_good_request(self):
|
||||
@@ -286,14 +287,14 @@ class LTIBlockTest(unittest.TestCase):
|
||||
'messageIdentifier': self.defaults['messageIdentifier'],
|
||||
}
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
assert response.status_code == 200
|
||||
self.assertDictEqual(expected_response, real_response)
|
||||
self.assertEqual(self.xmodule.module_score, float(self.defaults['grade']))
|
||||
assert self.xmodule.module_score == float(self.defaults['grade'])
|
||||
|
||||
def test_user_id(self):
|
||||
expected_user_id = text_type(six.moves.urllib.parse.quote(self.xmodule.runtime.anonymous_student_id))
|
||||
real_user_id = self.xmodule.get_user_id()
|
||||
self.assertEqual(real_user_id, expected_user_id)
|
||||
assert real_user_id == expected_user_id
|
||||
|
||||
def test_outcome_service_url(self):
|
||||
mock_url_prefix = 'https://hostname/'
|
||||
@@ -305,14 +306,14 @@ class LTIBlockTest(unittest.TestCase):
|
||||
|
||||
self.xmodule.runtime.handler_url = Mock(side_effect=mock_handler_url)
|
||||
real_outcome_service_url = self.xmodule.get_outcome_service_url(service_name=test_service_name)
|
||||
self.assertEqual(real_outcome_service_url, mock_url_prefix + test_service_name)
|
||||
assert real_outcome_service_url == (mock_url_prefix + test_service_name)
|
||||
|
||||
def test_resource_link_id(self):
|
||||
with patch('xmodule.lti_module.LTIBlock.location', new_callable=PropertyMock):
|
||||
self.xmodule.location.html_id = lambda: 'i4x-2-3-lti-31de800015cf4afb973356dbe81496df'
|
||||
expected_resource_link_id = text_type(six.moves.urllib.parse.quote(self.unquoted_resource_link_id))
|
||||
real_resource_link_id = self.xmodule.get_resource_link_id()
|
||||
self.assertEqual(real_resource_link_id, expected_resource_link_id)
|
||||
assert real_resource_link_id == expected_resource_link_id
|
||||
|
||||
def test_lis_result_sourcedid(self):
|
||||
expected_sourced_id = u':'.join(six.moves.urllib.parse.quote(i) for i in (
|
||||
@@ -321,7 +322,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
self.user_id
|
||||
))
|
||||
real_lis_result_sourcedid = self.xmodule.get_lis_result_sourcedid()
|
||||
self.assertEqual(real_lis_result_sourcedid, expected_sourced_id)
|
||||
assert real_lis_result_sourcedid == expected_sourced_id
|
||||
|
||||
def test_client_key_secret(self):
|
||||
"""
|
||||
@@ -336,7 +337,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
self.xmodule.lti_id = "lti_id"
|
||||
key, secret = self.xmodule.get_client_key_secret()
|
||||
expected = ('test_client', 'test_secret')
|
||||
self.assertEqual(expected, (key, secret))
|
||||
assert expected == (key, secret)
|
||||
|
||||
def test_client_key_secret_not_provided(self):
|
||||
"""
|
||||
@@ -355,7 +356,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
self.xmodule.lti_id = "another_lti_id"
|
||||
key_secret = self.xmodule.get_client_key_secret()
|
||||
expected = ('', '')
|
||||
self.assertEqual(expected, key_secret)
|
||||
assert expected == key_secret
|
||||
|
||||
def test_bad_client_key_secret(self):
|
||||
"""
|
||||
@@ -370,7 +371,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
runtime = Mock(modulestore=modulestore)
|
||||
self.xmodule.runtime = runtime
|
||||
self.xmodule.lti_id = 'lti_id'
|
||||
with self.assertRaises(LTIError):
|
||||
with pytest.raises(LTIError):
|
||||
self.xmodule.get_client_key_secret()
|
||||
|
||||
@patch('xmodule.lti_module.signature.verify_hmac_sha1', Mock(return_value=True))
|
||||
@@ -438,7 +439,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
|
||||
Tests that tool provider returned grade back with wrong XML Namespace.
|
||||
"""
|
||||
with self.assertRaises(IndexError):
|
||||
with pytest.raises(IndexError):
|
||||
mocked_request = self.get_signed_grade_mock_request(namespace_lti_v1p1=False)
|
||||
self.xmodule.parse_grade_xml_body(mocked_request.body)
|
||||
|
||||
@@ -450,10 +451,10 @@ class LTIBlockTest(unittest.TestCase):
|
||||
"""
|
||||
mocked_request = self.get_signed_grade_mock_request()
|
||||
message_identifier, sourced_id, grade, action = self.xmodule.parse_grade_xml_body(mocked_request.body)
|
||||
self.assertEqual(self.defaults['messageIdentifier'], message_identifier)
|
||||
self.assertEqual(self.defaults['sourcedId'], sourced_id)
|
||||
self.assertEqual(self.defaults['grade'], grade)
|
||||
self.assertEqual(self.defaults['action'], action)
|
||||
assert self.defaults['messageIdentifier'] == message_identifier
|
||||
assert self.defaults['sourcedId'] == sourced_id
|
||||
assert self.defaults['grade'] == grade
|
||||
assert self.defaults['action'] == action
|
||||
|
||||
@patch('xmodule.lti_module.signature.verify_hmac_sha1', Mock(return_value=False))
|
||||
@patch(
|
||||
@@ -464,7 +465,7 @@ class LTIBlockTest(unittest.TestCase):
|
||||
"""
|
||||
Oauth signing verify fail.
|
||||
"""
|
||||
with self.assertRaises(LTIError):
|
||||
with pytest.raises(LTIError):
|
||||
req = self.get_signed_grade_mock_request()
|
||||
self.xmodule.verify_oauth_body_sign(req)
|
||||
|
||||
@@ -519,21 +520,21 @@ class LTIBlockTest(unittest.TestCase):
|
||||
self.xmodule.custom_parameters = bad_custom_params
|
||||
self.xmodule.get_client_key_secret = Mock(return_value=('test_client_key', 'test_client_secret'))
|
||||
self.xmodule.oauth_params = Mock()
|
||||
with self.assertRaises(LTIError):
|
||||
with pytest.raises(LTIError):
|
||||
self.xmodule.get_input_fields()
|
||||
|
||||
def test_max_score(self):
|
||||
self.xmodule.weight = 100.0
|
||||
|
||||
self.assertFalse(self.xmodule.has_score)
|
||||
self.assertEqual(self.xmodule.max_score(), None)
|
||||
assert not self.xmodule.has_score
|
||||
assert self.xmodule.max_score() is None
|
||||
|
||||
self.xmodule.has_score = True
|
||||
|
||||
self.assertEqual(self.xmodule.max_score(), 100.0)
|
||||
assert self.xmodule.max_score() == 100.0
|
||||
|
||||
def test_context_id(self):
|
||||
"""
|
||||
Tests that LTI parameter context_id is equal to course_id.
|
||||
"""
|
||||
self.assertEqual(text_type(self.system.course_id), self.xmodule.context_id)
|
||||
assert text_type(self.system.course_id) == self.xmodule.context_id
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
import pytest
|
||||
from mock import Mock
|
||||
|
||||
from xmodule.mako_module import MakoModuleDescriptor
|
||||
@@ -15,10 +15,10 @@ class MakoModuleTest(TestCase):
|
||||
mock_system = Mock()
|
||||
mock_system.render_template = None
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
with pytest.raises(TypeError):
|
||||
MakoModuleDescriptor(mock_system, {})
|
||||
|
||||
del mock_system.render_template
|
||||
|
||||
with self.assertRaises(TypeError):
|
||||
with pytest.raises(TypeError):
|
||||
MakoModuleDescriptor(mock_system, {})
|
||||
|
||||
@@ -33,7 +33,7 @@ class MongoUtilsTests(TestCase):
|
||||
db = 'test_read_preference_%s' % uuid4().hex
|
||||
# Support for read_preference given in constant name form (ie. PRIMARY, SECONDARY_PREFERRED)
|
||||
connection = connect_to_mongodb(db, host, read_preference=enum_name)
|
||||
self.assertEqual(connection.client.read_preference, expected_read_preference)
|
||||
assert connection.client.read_preference == expected_read_preference
|
||||
# Support for read_preference given as mongos name.
|
||||
connection = connect_to_mongodb(db, host, read_preference=mongos_name)
|
||||
self.assertEqual(connection.client.read_preference, expected_read_preference)
|
||||
assert connection.client.read_preference == expected_read_preference
|
||||
|
||||
@@ -33,9 +33,9 @@ class PollModuleTest(LogicTest):
|
||||
callback = response['callback']
|
||||
|
||||
self.assertDictEqual(poll_answers, {'Yes': 1, 'Dont_know': 0, 'No': 1})
|
||||
self.assertEqual(total, 2)
|
||||
assert total == 2
|
||||
self.assertDictEqual(callback, {'objectName': 'Conditional'})
|
||||
self.assertEqual(self.xmodule.poll_answer, 'No')
|
||||
assert self.xmodule.poll_answer == 'No'
|
||||
|
||||
def test_poll_export_with_unescaped_characters_xml(self):
|
||||
"""
|
||||
@@ -64,4 +64,4 @@ class PollModuleTest(LogicTest):
|
||||
# Extract texts of all children.
|
||||
child_texts = xml.xpath('//text()')
|
||||
# Last index of child_texts contains text of answer tag.
|
||||
self.assertEqual(child_texts[-1], '< 18')
|
||||
assert child_texts[(- 1)] == '< 18'
|
||||
|
||||
@@ -41,50 +41,50 @@ class ProgressTest(unittest.TestCase):
|
||||
self.assertRaises(TypeError, Progress, 2j, 3)
|
||||
|
||||
def test_clamp(self):
|
||||
self.assertEqual((2, 2), Progress(3, 2).frac())
|
||||
self.assertEqual((0, 2), Progress(-2, 2).frac())
|
||||
assert (2, 2) == Progress(3, 2).frac()
|
||||
assert (0, 2) == Progress((- 2), 2).frac()
|
||||
|
||||
def test_frac(self):
|
||||
prg = Progress(1, 2)
|
||||
(a_mem, b_mem) = prg.frac()
|
||||
self.assertEqual(a_mem, 1)
|
||||
self.assertEqual(b_mem, 2)
|
||||
assert a_mem == 1
|
||||
assert b_mem == 2
|
||||
|
||||
def test_percent(self):
|
||||
self.assertEqual(self.not_started.percent(), 0)
|
||||
self.assertAlmostEqual(self.part_done.percent(), 33.33333333333333)
|
||||
self.assertEqual(self.half_done.percent(), 50)
|
||||
self.assertEqual(self.done.percent(), 100)
|
||||
assert self.not_started.percent() == 0
|
||||
assert round(self.part_done.percent() - 33.33333333333333, 7) >= 0
|
||||
assert self.half_done.percent() == 50
|
||||
assert self.done.percent() == 100
|
||||
|
||||
self.assertEqual(self.half_done.percent(), self.also_half_done.percent())
|
||||
assert self.half_done.percent() == self.also_half_done.percent()
|
||||
|
||||
def test_started(self):
|
||||
self.assertFalse(self.not_started.started())
|
||||
assert not self.not_started.started()
|
||||
|
||||
self.assertTrue(self.part_done.started())
|
||||
self.assertTrue(self.half_done.started())
|
||||
self.assertTrue(self.done.started())
|
||||
assert self.part_done.started()
|
||||
assert self.half_done.started()
|
||||
assert self.done.started()
|
||||
|
||||
def test_inprogress(self):
|
||||
# only true if working on it
|
||||
self.assertFalse(self.done.inprogress())
|
||||
self.assertFalse(self.not_started.inprogress())
|
||||
assert not self.done.inprogress()
|
||||
assert not self.not_started.inprogress()
|
||||
|
||||
self.assertTrue(self.part_done.inprogress())
|
||||
self.assertTrue(self.half_done.inprogress())
|
||||
assert self.part_done.inprogress()
|
||||
assert self.half_done.inprogress()
|
||||
|
||||
def test_done(self):
|
||||
self.assertTrue(self.done.done())
|
||||
self.assertFalse(self.half_done.done())
|
||||
self.assertFalse(self.not_started.done())
|
||||
assert self.done.done()
|
||||
assert not self.half_done.done()
|
||||
assert not self.not_started.done()
|
||||
|
||||
def test_str(self):
|
||||
self.assertEqual(str(self.not_started), "0/17")
|
||||
self.assertEqual(str(self.part_done), "2/6")
|
||||
self.assertEqual(str(self.done), "7/7")
|
||||
self.assertEqual(str(Progress(2.1234, 7)), '2.12/7')
|
||||
self.assertEqual(str(Progress(2.0034, 7)), '2/7')
|
||||
self.assertEqual(str(Progress(0.999, 7)), '1/7')
|
||||
assert str(self.not_started) == '0/17'
|
||||
assert str(self.part_done) == '2/6'
|
||||
assert str(self.done) == '7/7'
|
||||
assert str(Progress(2.1234, 7)) == '2.12/7'
|
||||
assert str(Progress(2.0034, 7)) == '2/7'
|
||||
assert str(Progress(0.999, 7)) == '1/7'
|
||||
|
||||
def test_add(self):
|
||||
'''Test the Progress.add_counts() method'''
|
||||
@@ -94,12 +94,12 @@ class ProgressTest(unittest.TestCase):
|
||||
prg_none = None
|
||||
add = lambda a, b: Progress.add_counts(a, b).frac()
|
||||
|
||||
self.assertEqual(add(prg1, prg1), (0, 4))
|
||||
self.assertEqual(add(prg1, prg2), (1, 5))
|
||||
self.assertEqual(add(prg2, prg3), (3, 8))
|
||||
assert add(prg1, prg1) == (0, 4)
|
||||
assert add(prg1, prg2) == (1, 5)
|
||||
assert add(prg2, prg3) == (3, 8)
|
||||
|
||||
self.assertEqual(add(prg2, prg_none), prg2.frac())
|
||||
self.assertEqual(add(prg_none, prg2), prg2.frac())
|
||||
assert add(prg2, prg_none) == prg2.frac()
|
||||
assert add(prg_none, prg2) == prg2.frac()
|
||||
|
||||
def test_equality(self):
|
||||
'''Test that comparing Progress objects for equality
|
||||
@@ -107,12 +107,12 @@ class ProgressTest(unittest.TestCase):
|
||||
prg1 = Progress(1, 2)
|
||||
prg2 = Progress(2, 4)
|
||||
prg3 = Progress(1, 2)
|
||||
self.assertEqual(prg1, prg3)
|
||||
self.assertNotEqual(prg1, prg2)
|
||||
assert prg1 == prg3
|
||||
assert prg1 != prg2
|
||||
|
||||
# Check != while we're at it
|
||||
self.assertNotEqual(prg1, prg2)
|
||||
self.assertEqual(prg1, prg3)
|
||||
assert prg1 != prg2
|
||||
assert prg1 == prg3
|
||||
|
||||
|
||||
class ModuleProgressTest(unittest.TestCase):
|
||||
@@ -123,4 +123,4 @@ class ModuleProgressTest(unittest.TestCase):
|
||||
'''Make sure default get_progress exists, returns None'''
|
||||
xmod = x_module.XModule(Mock(), get_test_system(), DictFieldData({'location': 'a://b/c/d/e'}), Mock())
|
||||
prg = xmod.get_progress() # lint-amnesty, pylint: disable=assignment-from-none
|
||||
self.assertEqual(prg, None)
|
||||
assert prg is None
|
||||
|
||||
@@ -78,7 +78,7 @@ class RandomizeBlockTest(MixedSplitTestCase):
|
||||
exported_olx = f.read()
|
||||
|
||||
# And compare.
|
||||
self.assertEqual(exported_olx, expected_olx)
|
||||
assert exported_olx == expected_olx
|
||||
|
||||
runtime = TestImportSystem(load_error_modules=True, course_id=randomize_block.location.course_key)
|
||||
runtime.resources_fs = export_fs
|
||||
@@ -89,9 +89,9 @@ class RandomizeBlockTest(MixedSplitTestCase):
|
||||
imported_randomize_block = RandomizeBlock.parse_xml(olx_element, runtime, None, id_generator)
|
||||
|
||||
# Check the new XBlock has the same properties as the old one.
|
||||
self.assertEqual(imported_randomize_block.display_name, randomize_block.display_name)
|
||||
self.assertEqual(len(imported_randomize_block.children), 3)
|
||||
self.assertEqual(imported_randomize_block.children, randomize_block.children)
|
||||
assert imported_randomize_block.display_name == randomize_block.display_name
|
||||
assert len(imported_randomize_block.children) == 3
|
||||
assert imported_randomize_block.children == randomize_block.children
|
||||
|
||||
def test_children_seen_by_a_user(self):
|
||||
"""
|
||||
@@ -101,18 +101,18 @@ class RandomizeBlockTest(MixedSplitTestCase):
|
||||
self._bind_module_system(randomize_block, 3)
|
||||
|
||||
# Make sure the runtime knows that the block's children vary per-user:
|
||||
self.assertTrue(randomize_block.has_dynamic_children())
|
||||
assert randomize_block.has_dynamic_children()
|
||||
|
||||
self.assertEqual(len(randomize_block.children), 3)
|
||||
assert len(randomize_block.children) == 3
|
||||
|
||||
# Check how many children each user will see:
|
||||
self.assertEqual(len(randomize_block.get_child_descriptors()), 1)
|
||||
self.assertEqual(randomize_block.get_child_descriptors()[0].display_name, 'Hello HTML 1')
|
||||
assert len(randomize_block.get_child_descriptors()) == 1
|
||||
assert randomize_block.get_child_descriptors()[0].display_name == 'Hello HTML 1'
|
||||
# Check that get_content_titles() doesn't return titles for hidden/unused children
|
||||
# get_content_titles() is not overridden in RandomizeBlock so titles of the 3 children are returned.
|
||||
self.assertEqual(len(randomize_block.get_content_titles()), 3)
|
||||
assert len(randomize_block.get_content_titles()) == 3
|
||||
|
||||
# Bind to another user and check a different child block is displayed to user.
|
||||
randomize_block = self.store.get_item(self.randomize_block.location)
|
||||
self._bind_module_system(randomize_block, 1)
|
||||
self.assertEqual(randomize_block.get_child_descriptors()[0].display_name, 'Hello HTML 2')
|
||||
assert randomize_block.get_child_descriptors()[0].display_name == 'Hello HTML 2'
|
||||
|
||||
@@ -20,15 +20,13 @@ class ResourceTemplatesTests(unittest.TestCase):
|
||||
'announcement.yaml',
|
||||
'anon_user_id.yaml'])
|
||||
got = set((t['template_id'] for t in TestClass.templates()))
|
||||
self.assertEqual(expected, got)
|
||||
assert expected == got
|
||||
|
||||
def test_templates_no_suchdir(self):
|
||||
self.assertEqual(len(TestClass2.templates()), 0)
|
||||
assert len(TestClass2.templates()) == 0
|
||||
|
||||
def test_get_template(self):
|
||||
self.assertEqual(
|
||||
TestClass.get_template('latex_html.yaml')['template_id'],
|
||||
'latex_html.yaml')
|
||||
assert TestClass.get_template('latex_html.yaml')['template_id'] == 'latex_html.yaml'
|
||||
|
||||
|
||||
class TestClass(ResourceTemplates):
|
||||
|
||||
@@ -138,11 +138,12 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
"""
|
||||
Verifies that the rendered view contains the expected position.
|
||||
"""
|
||||
self.assertIn("'position': {}".format(expected_position), rendered_html)
|
||||
assert "'position': {}".format(expected_position) in rendered_html
|
||||
|
||||
def test_student_view_init(self):
|
||||
seq_module = SequenceModule(runtime=Mock(position=2), descriptor=Mock(), scope_ids=Mock())
|
||||
self.assertEqual(seq_module.position, 2) # matches position set in the runtime
|
||||
assert seq_module.position == 2
|
||||
# matches position set in the runtime
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -156,11 +157,11 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
view=view
|
||||
)
|
||||
self._assert_view_at_position(html, expected_position=1)
|
||||
self.assertIn(six.text_type(self.sequence_3_1.location), html)
|
||||
self.assertIn("'gated': False", html)
|
||||
self.assertIn("'next_url': 'NextSequential'", html)
|
||||
self.assertIn("'prev_url': 'PrevSequential'", html)
|
||||
self.assertNotIn("fa fa-check-circle check-circle is-hidden", html)
|
||||
assert six.text_type(self.sequence_3_1.location) in html
|
||||
assert "'gated': False" in html
|
||||
assert "'next_url': 'NextSequential'" in html
|
||||
assert "'prev_url': 'PrevSequential'" in html
|
||||
assert 'fa fa-check-circle check-circle is-hidden' not in html
|
||||
|
||||
# pylint: disable=line-too-long
|
||||
@patch('xmodule.seq_module.SequenceModule.gate_entire_sequence_if_it_is_a_timed_exam_and_contains_content_type_gated_problems')
|
||||
@@ -205,11 +206,11 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
extra_context=dict(next_url='NextSequential', prev_url='PrevSequential'),
|
||||
view=STUDENT_VIEW
|
||||
)
|
||||
self.assertIn('i_am_gated', view)
|
||||
assert 'i_am_gated' in view
|
||||
# check a few elements to ensure the correct page was loaded
|
||||
self.assertIn("seq_module.html", view)
|
||||
self.assertIn('NextSequential', view)
|
||||
self.assertIn('PrevSequential', view)
|
||||
assert 'seq_module.html' in view
|
||||
assert 'NextSequential' in view
|
||||
assert 'PrevSequential' in view
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -234,12 +235,12 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
def test_tooltip(self):
|
||||
html = self._get_rendered_view(self.sequence_3_1, requested_child=None)
|
||||
for child in self.sequence_3_1.children:
|
||||
self.assertIn("'page_title': '{}'".format(child.block_id), html)
|
||||
assert "'page_title': '{}'".format(child.block_id) in html
|
||||
|
||||
def test_hidden_content_before_due(self):
|
||||
html = self._get_rendered_view(self.sequence_4_1)
|
||||
self.assertIn("seq_module.html", html)
|
||||
self.assertIn("'banner_text': None", html)
|
||||
assert 'seq_module.html' in html
|
||||
assert "'banner_text': None" in html
|
||||
|
||||
def test_hidden_content_past_due(self):
|
||||
with freeze_time(COURSE_END_DATE):
|
||||
@@ -248,8 +249,8 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
self.sequence_4_1,
|
||||
extra_context=dict(progress_url=progress_url),
|
||||
)
|
||||
self.assertIn("hidden_content.html", html)
|
||||
self.assertIn(progress_url, html)
|
||||
assert 'hidden_content.html' in html
|
||||
assert progress_url in html
|
||||
|
||||
def test_masquerade_hidden_content_past_due(self):
|
||||
with freeze_time(COURSE_END_DATE):
|
||||
@@ -257,18 +258,15 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
self.sequence_4_1,
|
||||
extra_context=dict(specific_masquerade=True),
|
||||
)
|
||||
self.assertIn("seq_module.html", html)
|
||||
assert 'seq_module.html' in html
|
||||
html = self.get_context_dict_from_string(html)
|
||||
self.assertEqual(
|
||||
'Because the due date has passed, this assignment is hidden from the learner.',
|
||||
html['banner_text']
|
||||
)
|
||||
assert 'Because the due date has passed, this assignment is hidden from the learner.' == html['banner_text']
|
||||
|
||||
def test_hidden_content_self_paced_past_due_before_end(self):
|
||||
with freeze_time(PAST_DUE_BEFORE_END_DATE):
|
||||
html = self._get_rendered_view(self.sequence_4_1, self_paced=True)
|
||||
self.assertIn("seq_module.html", html)
|
||||
self.assertIn("'banner_text': None", html)
|
||||
assert 'seq_module.html' in html
|
||||
assert "'banner_text': None" in html
|
||||
|
||||
def test_hidden_content_self_paced_past_end(self):
|
||||
with freeze_time(COURSE_END_DATE + timedelta(days=7)):
|
||||
@@ -278,56 +276,50 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
extra_context=dict(progress_url=progress_url),
|
||||
self_paced=True,
|
||||
)
|
||||
self.assertIn("hidden_content.html", html)
|
||||
self.assertIn(progress_url, html)
|
||||
assert 'hidden_content.html' in html
|
||||
assert progress_url in html
|
||||
|
||||
def _assert_gated(self, html, sequence):
|
||||
"""
|
||||
Assert sequence content is gated
|
||||
"""
|
||||
self.assertIn("seq_module.html", html)
|
||||
assert 'seq_module.html' in html
|
||||
html = self.get_context_dict_from_string(html)
|
||||
self.assertIsNone(html['banner_text'])
|
||||
self.assertEqual([], html['items'])
|
||||
self.assertTrue(html['gated_content']['gated'])
|
||||
self.assertEqual('PrereqUrl', html['gated_content']['prereq_url'])
|
||||
self.assertEqual('PrereqSectionName', html['gated_content']['prereq_section_name'])
|
||||
self.assertIn(
|
||||
six.text_type(sequence.display_name),
|
||||
html['gated_content']['gated_section_name']
|
||||
)
|
||||
self.assertEqual('NextSequential', html['next_url'])
|
||||
self.assertEqual('PrevSequential', html['prev_url'])
|
||||
assert html['banner_text'] is None
|
||||
assert [] == html['items']
|
||||
assert html['gated_content']['gated']
|
||||
assert 'PrereqUrl' == html['gated_content']['prereq_url']
|
||||
assert 'PrereqSectionName' == html['gated_content']['prereq_section_name']
|
||||
assert six.text_type(sequence.display_name) in html['gated_content']['gated_section_name']
|
||||
assert 'NextSequential' == html['next_url']
|
||||
assert 'PrevSequential' == html['prev_url']
|
||||
|
||||
def _assert_prereq(self, html, sequence):
|
||||
"""
|
||||
Assert sequence is a prerequisite with unfulfilled gates
|
||||
"""
|
||||
self.assertIn("seq_module.html", html)
|
||||
assert 'seq_module.html' in html
|
||||
html = self.get_context_dict_from_string(html)
|
||||
self.assertEqual(
|
||||
"This section is a prerequisite. You must complete this section in order to unlock additional content.",
|
||||
html['banner_text']
|
||||
)
|
||||
self.assertFalse(html['gated_content']['gated'])
|
||||
self.assertEqual(six.text_type(sequence.location), html['item_id'])
|
||||
self.assertIsNone(html['gated_content']['prereq_url'])
|
||||
self.assertIsNone(html['gated_content']['prereq_section_name'])
|
||||
self.assertEqual('NextSequential', html['next_url'])
|
||||
self.assertEqual('PrevSequential', html['prev_url'])
|
||||
assert 'This section is a prerequisite. You must complete this section in order to unlock additional content.' == html['banner_text']
|
||||
assert not html['gated_content']['gated']
|
||||
assert six.text_type(sequence.location) == html['item_id']
|
||||
assert html['gated_content']['prereq_url'] is None
|
||||
assert html['gated_content']['prereq_section_name'] is None
|
||||
assert 'NextSequential' == html['next_url']
|
||||
assert 'PrevSequential' == html['prev_url']
|
||||
|
||||
def _assert_ungated(self, html, sequence):
|
||||
"""
|
||||
Assert sequence is not gated
|
||||
"""
|
||||
self.assertIn("seq_module.html", html)
|
||||
self.assertIn("'banner_text': None", html)
|
||||
self.assertIn("'gated': False", html)
|
||||
self.assertIn(six.text_type(sequence.location), html)
|
||||
self.assertIn("'prereq_url': None", html)
|
||||
self.assertIn("'prereq_section_name': None", html)
|
||||
self.assertIn("'next_url': 'NextSequential'", html)
|
||||
self.assertIn("'prev_url': 'PrevSequential'", html)
|
||||
assert 'seq_module.html' in html
|
||||
assert "'banner_text': None" in html
|
||||
assert "'gated': False" in html
|
||||
assert six.text_type(sequence.location) in html
|
||||
assert "'prereq_url': None" in html
|
||||
assert "'prereq_section_name': None" in html
|
||||
assert "'next_url': 'NextSequential'" in html
|
||||
assert "'prev_url': 'PrevSequential'" in html
|
||||
|
||||
def test_gated_content(self):
|
||||
"""
|
||||
@@ -389,9 +381,9 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
'get_completion',
|
||||
{'usage_key': usage_key}
|
||||
))
|
||||
self.assertIsNot(completion_return, None)
|
||||
self.assertTrue('complete' in completion_return) # lint-amnesty, pylint: disable=wrong-assert-type
|
||||
self.assertEqual(completion_return['complete'], True)
|
||||
assert completion_return is not None
|
||||
assert 'complete' in completion_return
|
||||
assert completion_return['complete'] is True
|
||||
|
||||
def test_handle_ajax_get_completion_return_none(self):
|
||||
"""
|
||||
@@ -403,7 +395,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
'get_completion',
|
||||
{'usage_key': usage_key}
|
||||
)
|
||||
self.assertIs(completion_return, None)
|
||||
assert completion_return is None
|
||||
|
||||
def test_handle_ajax_metadata(self):
|
||||
"""
|
||||
@@ -414,9 +406,9 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
# let's just disable the bookmarks service
|
||||
self.sequence_3_1.xmodule_runtime._services['bookmarks'] = None # lint-amnesty, pylint: disable=protected-access
|
||||
metadata = json.loads(self.sequence_3_1.handle_ajax('metadata', {}))
|
||||
self.assertEqual(len(metadata['items']), 3)
|
||||
self.assertEqual(metadata['tag'], 'sequential')
|
||||
self.assertEqual(metadata['display_name'], self.sequence_3_1.display_name_with_default)
|
||||
assert len(metadata['items']) == 3
|
||||
assert metadata['tag'] == 'sequential'
|
||||
assert metadata['display_name'] == self.sequence_3_1.display_name_with_default
|
||||
|
||||
@override_settings(FIELD_OVERRIDE_PROVIDERS=(
|
||||
'openedx.features.content_type_gating.field_override.ContentTypeGatingFieldOverride',
|
||||
@@ -429,7 +421,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
self.sequence_5_1.xmodule_runtime._services['bookmarks'] = None # pylint: disable=protected-access
|
||||
ContentTypeGatingConfig.objects.create(enabled=True, enabled_as_of=datetime(2018, 1, 1))
|
||||
metadata = json.loads(self.sequence_5_1.handle_ajax('metadata', {}))
|
||||
self.assertEqual(metadata['items'][0]['contains_content_type_gated_content'], False)
|
||||
assert metadata['items'][0]['contains_content_type_gated_content'] is False
|
||||
|
||||
# When a block contains content type gated problems, set the contains_content_type_gated_content field
|
||||
self.sequence_5_1.get_children()[0].get_children()[0].graded = True
|
||||
@@ -438,7 +430,7 @@ class SequenceBlockTestCase(XModuleXmlImportTest):
|
||||
content_type_gate_for_block=Mock(return_value=Fragment('i_am_gated'))
|
||||
))
|
||||
metadata = json.loads(self.sequence_5_1.handle_ajax('metadata', {}))
|
||||
self.assertEqual(metadata['items'][0]['contains_content_type_gated_content'], True)
|
||||
assert metadata['items'][0]['contains_content_type_gated_content'] is True
|
||||
|
||||
def get_context_dict_from_string(self, data):
|
||||
"""
|
||||
|
||||
@@ -4,6 +4,7 @@ Tests for SettingsService
|
||||
|
||||
|
||||
import unittest
|
||||
import pytest
|
||||
from django.test import TestCase
|
||||
|
||||
import ddt
|
||||
@@ -57,46 +58,48 @@ class TestSettingsService(unittest.TestCase):
|
||||
|
||||
def test_get_given_none_throws_value_error(self):
|
||||
""" Test that given None throws value error """
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
self.settings_service.get_settings_bucket(None)
|
||||
|
||||
def test_get_return_default_if_xblock_settings_is_missing(self):
|
||||
""" Test that returns default (or None if default not set) if XBLOCK_SETTINGS is not set """
|
||||
self.assertFalse(hasattr(settings, 'XBLOCK_SETTINGS')) # precondition check
|
||||
self.assertEqual(self.settings_service.get_settings_bucket(self.xblock_mock, 'zzz'), 'zzz')
|
||||
assert not hasattr(settings, 'XBLOCK_SETTINGS')
|
||||
# precondition check
|
||||
assert self.settings_service.get_settings_bucket(self.xblock_mock, 'zzz') == 'zzz'
|
||||
|
||||
def test_get_return_empty_dictionary_if_xblock_settings_and_default_is_missing(self):
|
||||
""" Test that returns default (or None if default not set) if XBLOCK_SETTINGS is not set """
|
||||
self.assertFalse(hasattr(settings, 'XBLOCK_SETTINGS')) # precondition check
|
||||
self.assertEqual(self.settings_service.get_settings_bucket(self.xblock_mock), {})
|
||||
assert not hasattr(settings, 'XBLOCK_SETTINGS')
|
||||
# precondition check
|
||||
assert self.settings_service.get_settings_bucket(self.xblock_mock) == {}
|
||||
|
||||
@override_settings(XBLOCK_SETTINGS={xblock_setting_key2: {'b': 1}})
|
||||
def test_get_returns_none_or_default_if_bucket_not_found(self):
|
||||
""" Test if settings service returns default if setting not found """
|
||||
self.assertEqual(settings.XBLOCK_SETTINGS, {self.xblock_setting_key2: {'b': 1}})
|
||||
self.assertEqual(self.settings_service.get_settings_bucket(self.xblock_mock), {})
|
||||
self.assertEqual(self.settings_service.get_settings_bucket(self.xblock_mock, 123), 123)
|
||||
assert settings.XBLOCK_SETTINGS == {self.xblock_setting_key2: {'b': 1}}
|
||||
assert self.settings_service.get_settings_bucket(self.xblock_mock) == {}
|
||||
assert self.settings_service.get_settings_bucket(self.xblock_mock, 123) == 123
|
||||
|
||||
@override_settings(XBLOCK_SETTINGS={xblock_setting_key1: 42})
|
||||
def test_get_returns_correct_value(self):
|
||||
""" Test if settings service returns correct bucket """
|
||||
self.assertEqual(settings.XBLOCK_SETTINGS, {self.xblock_setting_key1: 42})
|
||||
self.assertEqual(self.settings_service.get_settings_bucket(self.xblock_mock), 42)
|
||||
assert settings.XBLOCK_SETTINGS == {self.xblock_setting_key1: 42}
|
||||
assert self.settings_service.get_settings_bucket(self.xblock_mock) == 42
|
||||
|
||||
@override_settings(XBLOCK_SETTINGS={xblock_setting_key2: "I'm a setting"})
|
||||
def test_get_respects_block_settings_key(self):
|
||||
""" Test if settings service respects block_settings_key value """
|
||||
self.assertEqual(settings.XBLOCK_SETTINGS, {self.xblock_setting_key2: "I'm a setting"})
|
||||
assert settings.XBLOCK_SETTINGS == {self.xblock_setting_key2: "I'm a setting"}
|
||||
self.xblock_mock.block_settings_key = self.xblock_setting_key2
|
||||
self.assertEqual(self.settings_service.get_settings_bucket(self.xblock_mock), "I'm a setting")
|
||||
assert self.settings_service.get_settings_bucket(self.xblock_mock) == "I'm a setting"
|
||||
|
||||
@override_settings(XBLOCK_SETTINGS={_DummyBlock.__name__: [1, 2, 3]})
|
||||
def test_get_uses_class_name_if_block_settings_key_is_not_set(self):
|
||||
""" Test if settings service uses class name if block_settings_key attribute does not exist """
|
||||
mixologist = Mixologist([])
|
||||
block = mixologist.mix(_DummyBlock)
|
||||
self.assertEqual(settings.XBLOCK_SETTINGS, {"_DummyBlock": [1, 2, 3]})
|
||||
self.assertEqual(self.settings_service.get_settings_bucket(block), [1, 2, 3])
|
||||
assert settings.XBLOCK_SETTINGS == {'_DummyBlock': [1, 2, 3]}
|
||||
assert self.settings_service.get_settings_bucket(block) == [1, 2, 3]
|
||||
|
||||
|
||||
class TestConfigurationService(unittest.TestCase):
|
||||
@@ -109,7 +112,7 @@ class TestConfigurationService(unittest.TestCase):
|
||||
Test that instantiating ConfigurationService raises exception on passing
|
||||
a class which is not subclass of ConfigurationModel.
|
||||
"""
|
||||
with self.assertRaises(ValueError):
|
||||
with pytest.raises(ValueError):
|
||||
ConfigurationService(DummyUnexpected)
|
||||
|
||||
def test_configuration_service(self):
|
||||
@@ -117,7 +120,7 @@ class TestConfigurationService(unittest.TestCase):
|
||||
Test the correct configuration on instantiating ConfigurationService.
|
||||
"""
|
||||
config_service = ConfigurationService(DummyConfig)
|
||||
self.assertEqual(config_service.configuration, DummyConfig)
|
||||
assert config_service.configuration == DummyConfig
|
||||
|
||||
|
||||
class MockConfigurationService(TeamsConfigurationService):
|
||||
@@ -157,4 +160,4 @@ class TestTeamsConfigurationService(ConfigurationServiceBaseClass):
|
||||
|
||||
def test_get_teamsconfiguration(self):
|
||||
teams_config = self.configuration_service.get_teams_configuration(self.course.id)
|
||||
self.assertEqual(teams_config, self.teams_config)
|
||||
assert teams_config == self.teams_config
|
||||
|
||||
@@ -60,10 +60,7 @@ class SplitTestUtilitiesTest(PartitionTestCase):
|
||||
),
|
||||
second_random_partition
|
||||
]
|
||||
self.assertEqual(
|
||||
[first_random_partition, second_random_partition],
|
||||
get_split_user_partitions(all_partitions)
|
||||
)
|
||||
assert [first_random_partition, second_random_partition] == get_split_user_partitions(all_partitions)
|
||||
|
||||
|
||||
class SplitTestBlockTest(XModuleXmlImportTest, PartitionTestCase):
|
||||
@@ -150,31 +147,25 @@ class SplitTestBlockLMSTest(SplitTestBlockTest):
|
||||
@ddt.unpack
|
||||
def test_child(self, user_tag, child_url_name):
|
||||
self.user_partition.scheme.current_group = self.user_partition.groups[user_tag]
|
||||
self.assertEqual(self.split_test_module.child_descriptor.url_name, child_url_name)
|
||||
assert self.split_test_module.child_descriptor.url_name == child_url_name
|
||||
|
||||
@ddt.data((0, 'HTML FOR GROUP 0'), (1, 'HTML FOR GROUP 1'))
|
||||
@ddt.unpack
|
||||
def test_get_html(self, user_tag, child_content):
|
||||
self.user_partition.scheme.current_group = self.user_partition.groups[user_tag]
|
||||
self.assertIn(
|
||||
child_content,
|
||||
self.module_system.render(self.split_test_module, STUDENT_VIEW).content
|
||||
)
|
||||
assert child_content in self.module_system.render(self.split_test_module, STUDENT_VIEW).content
|
||||
|
||||
@ddt.data(0, 1)
|
||||
def test_child_missing_tag_value(self, _user_tag):
|
||||
# If user_tag has a missing value, we should still get back a valid child url
|
||||
self.assertIn(self.split_test_module.child_descriptor.url_name, ['split_test_cond0', 'split_test_cond1'])
|
||||
assert self.split_test_module.child_descriptor.url_name in ['split_test_cond0', 'split_test_cond1']
|
||||
|
||||
@ddt.data(100, 200, 300, 400, 500, 600, 700, 800, 900, 1000)
|
||||
def test_child_persist_new_tag_value_when_tag_missing(self, _user_tag):
|
||||
# If a user_tag has a missing value, a group should be saved/persisted for that user.
|
||||
# So, we check that we get the same url_name when we call on the url_name twice.
|
||||
# We run the test ten times so that, if our storage is failing, we'll be most likely to notice it.
|
||||
self.assertEqual(
|
||||
self.split_test_module.child_descriptor.url_name,
|
||||
self.split_test_module.child_descriptor.url_name
|
||||
)
|
||||
assert self.split_test_module.child_descriptor.url_name == self.split_test_module.child_descriptor.url_name
|
||||
|
||||
# Patch the definition_to_xml for the html children.
|
||||
@patch('xmodule.html_module.HtmlBlock.definition_to_xml')
|
||||
@@ -190,14 +181,14 @@ class SplitTestBlockLMSTest(SplitTestBlockTest):
|
||||
# Write out the xml.
|
||||
xml_obj = self.split_test_module.definition_to_xml(MemoryFS())
|
||||
|
||||
self.assertEqual(xml_obj.get('user_partition_id'), '0')
|
||||
self.assertIsNotNone(xml_obj.get('group_id_to_child'))
|
||||
assert xml_obj.get('user_partition_id') == '0'
|
||||
assert xml_obj.get('group_id_to_child') is not None
|
||||
|
||||
# Read the xml back in.
|
||||
fields, children = SplitTestBlock.definition_from_xml(xml_obj, self.module_system)
|
||||
self.assertEqual(fields.get('user_partition_id'), '0')
|
||||
self.assertIsNotNone(fields.get('group_id_to_child'))
|
||||
self.assertEqual(len(children), 2)
|
||||
assert fields.get('user_partition_id') == '0'
|
||||
assert fields.get('group_id_to_child') is not None
|
||||
assert len(children) == 2
|
||||
|
||||
|
||||
class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
@@ -223,14 +214,14 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
# The split_test module should render both its groups when it is the root
|
||||
context = create_studio_context(self.split_test_module)
|
||||
html = self.module_system.render(self.split_test_module, AUTHOR_VIEW, context).content
|
||||
self.assertIn('HTML FOR GROUP 0', html)
|
||||
self.assertIn('HTML FOR GROUP 1', html)
|
||||
assert 'HTML FOR GROUP 0' in html
|
||||
assert 'HTML FOR GROUP 1' in html
|
||||
|
||||
# When rendering as a child, it shouldn't render either of its groups
|
||||
context = create_studio_context(self.course_sequence)
|
||||
html = self.module_system.render(self.split_test_module, AUTHOR_VIEW, context).content
|
||||
self.assertNotIn('HTML FOR GROUP 0', html)
|
||||
self.assertNotIn('HTML FOR GROUP 1', html)
|
||||
assert 'HTML FOR GROUP 0' not in html
|
||||
assert 'HTML FOR GROUP 1' not in html
|
||||
|
||||
# The "Create Missing Groups" button should be rendered when groups are missing
|
||||
context = create_studio_context(self.split_test_module)
|
||||
@@ -239,8 +230,8 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
[Group("0", 'alpha'), Group("1", 'beta'), Group("2", 'gamma')])
|
||||
]
|
||||
html = self.module_system.render(self.split_test_module, AUTHOR_VIEW, context).content
|
||||
self.assertIn('HTML FOR GROUP 0', html)
|
||||
self.assertIn('HTML FOR GROUP 1', html)
|
||||
assert 'HTML FOR GROUP 0' in html
|
||||
assert 'HTML FOR GROUP 1' in html
|
||||
|
||||
def test_group_configuration_url(self):
|
||||
"""
|
||||
@@ -256,29 +247,29 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
]
|
||||
|
||||
expected_url = '/group_configurations/edX/xml_test_course/101#0'
|
||||
self.assertEqual(expected_url, self.split_test_module.group_configuration_url)
|
||||
assert expected_url == self.split_test_module.group_configuration_url
|
||||
|
||||
def test_editable_settings(self):
|
||||
"""
|
||||
Test the setting information passed back from editable_metadata_fields.
|
||||
"""
|
||||
editable_metadata_fields = self.split_test_module.editable_metadata_fields
|
||||
self.assertIn(SplitTestBlock.display_name.name, editable_metadata_fields)
|
||||
self.assertNotIn(SplitTestBlock.due.name, editable_metadata_fields)
|
||||
self.assertNotIn(SplitTestBlock.user_partitions.name, editable_metadata_fields)
|
||||
assert SplitTestBlock.display_name.name in editable_metadata_fields
|
||||
assert SplitTestBlock.due.name not in editable_metadata_fields
|
||||
assert SplitTestBlock.user_partitions.name not in editable_metadata_fields
|
||||
|
||||
# user_partition_id will always appear in editable_metadata_settings, regardless
|
||||
# of the selected value.
|
||||
self.assertIn(SplitTestBlock.user_partition_id.name, editable_metadata_fields)
|
||||
assert SplitTestBlock.user_partition_id.name in editable_metadata_fields
|
||||
|
||||
def test_non_editable_settings(self):
|
||||
"""
|
||||
Test the settings that are marked as "non-editable".
|
||||
"""
|
||||
non_editable_metadata_fields = self.split_test_module.non_editable_metadata_fields
|
||||
self.assertIn(SplitTestBlock.due, non_editable_metadata_fields)
|
||||
self.assertIn(SplitTestBlock.user_partitions, non_editable_metadata_fields)
|
||||
self.assertNotIn(SplitTestBlock.display_name, non_editable_metadata_fields)
|
||||
assert SplitTestBlock.due in non_editable_metadata_fields
|
||||
assert SplitTestBlock.user_partitions in non_editable_metadata_fields
|
||||
assert SplitTestBlock.display_name not in non_editable_metadata_fields
|
||||
|
||||
@patch('xmodule.split_test_module.user_partition_values.values')
|
||||
def test_available_partitions(self, _):
|
||||
@@ -289,8 +280,8 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
self.split_test_module.user_partition_id = SplitTestFields.no_partition_selected['value']
|
||||
self.split_test_module.editable_metadata_fields # pylint: disable=pointless-statement
|
||||
partitions = user_partition_values.values
|
||||
self.assertEqual(1, len(partitions))
|
||||
self.assertEqual(SplitTestFields.no_partition_selected['value'], partitions[0]['value'])
|
||||
assert 1 == len(partitions)
|
||||
assert SplitTestFields.no_partition_selected['value'] == partitions[0]['value']
|
||||
|
||||
# Populate user_partitions and call editable_metadata_fields again
|
||||
self.split_test_module.user_partitions = [
|
||||
@@ -306,27 +297,27 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
]
|
||||
self.split_test_module.editable_metadata_fields # pylint: disable=pointless-statement
|
||||
partitions = user_partition_values.values
|
||||
self.assertEqual(2, len(partitions))
|
||||
self.assertEqual(SplitTestFields.no_partition_selected['value'], partitions[0]['value'])
|
||||
self.assertEqual(0, partitions[1]['value'])
|
||||
self.assertEqual("first_partition", partitions[1]['display_name'])
|
||||
assert 2 == len(partitions)
|
||||
assert SplitTestFields.no_partition_selected['value'] == partitions[0]['value']
|
||||
assert 0 == partitions[1]['value']
|
||||
assert 'first_partition' == partitions[1]['display_name']
|
||||
|
||||
# Try again with a selected partition and verify that there is no option for "No Selection"
|
||||
self.split_test_module.user_partition_id = 0
|
||||
self.split_test_module.editable_metadata_fields # pylint: disable=pointless-statement
|
||||
partitions = user_partition_values.values
|
||||
self.assertEqual(1, len(partitions))
|
||||
self.assertEqual(0, partitions[0]['value'])
|
||||
self.assertEqual("first_partition", partitions[0]['display_name'])
|
||||
assert 1 == len(partitions)
|
||||
assert 0 == partitions[0]['value']
|
||||
assert 'first_partition' == partitions[0]['display_name']
|
||||
|
||||
# Finally try again with an invalid selected partition and verify that "No Selection" is an option
|
||||
self.split_test_module.user_partition_id = 999
|
||||
self.split_test_module.editable_metadata_fields # pylint: disable=pointless-statement
|
||||
partitions = user_partition_values.values
|
||||
self.assertEqual(2, len(partitions))
|
||||
self.assertEqual(SplitTestFields.no_partition_selected['value'], partitions[0]['value'])
|
||||
self.assertEqual(0, partitions[1]['value'])
|
||||
self.assertEqual("first_partition", partitions[1]['display_name'])
|
||||
assert 2 == len(partitions)
|
||||
assert SplitTestFields.no_partition_selected['value'] == partitions[0]['value']
|
||||
assert 0 == partitions[1]['value']
|
||||
assert 'first_partition' == partitions[1]['display_name']
|
||||
|
||||
def test_active_and_inactive_children(self):
|
||||
"""
|
||||
@@ -338,8 +329,8 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
# Verify that a split test has no active children if it has no specified user partition.
|
||||
split_test_module.user_partition_id = -1
|
||||
[active_children, inactive_children] = split_test_module.active_and_inactive_children()
|
||||
self.assertEqual(active_children, [])
|
||||
self.assertEqual(inactive_children, children)
|
||||
assert active_children == []
|
||||
assert inactive_children == children
|
||||
|
||||
# Verify that all the children are returned as active for a correctly configured split_test
|
||||
split_test_module.user_partition_id = 0
|
||||
@@ -347,30 +338,30 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
UserPartition(0, 'first_partition', 'First Partition', [Group("0", 'alpha'), Group("1", 'beta')])
|
||||
]
|
||||
[active_children, inactive_children] = split_test_module.active_and_inactive_children()
|
||||
self.assertEqual(active_children, children)
|
||||
self.assertEqual(inactive_children, [])
|
||||
assert active_children == children
|
||||
assert inactive_children == []
|
||||
|
||||
# Verify that a split_test does not return inactive children in the active children
|
||||
self.split_test_module.user_partitions = [
|
||||
UserPartition(0, 'first_partition', 'First Partition', [Group("0", 'alpha')])
|
||||
]
|
||||
[active_children, inactive_children] = split_test_module.active_and_inactive_children()
|
||||
self.assertEqual(active_children, [children[0]])
|
||||
self.assertEqual(inactive_children, [children[1]])
|
||||
assert active_children == [children[0]]
|
||||
assert inactive_children == [children[1]]
|
||||
|
||||
# Verify that a split_test ignores misconfigured children
|
||||
self.split_test_module.user_partitions = [
|
||||
UserPartition(0, 'first_partition', 'First Partition', [Group("0", 'alpha'), Group("2", 'gamma')])
|
||||
]
|
||||
[active_children, inactive_children] = split_test_module.active_and_inactive_children()
|
||||
self.assertEqual(active_children, [children[0]])
|
||||
self.assertEqual(inactive_children, [children[1]])
|
||||
assert active_children == [children[0]]
|
||||
assert inactive_children == [children[1]]
|
||||
|
||||
# Verify that a split_test referring to a non-existent user partition has no active children
|
||||
self.split_test_module.user_partition_id = 2
|
||||
[active_children, inactive_children] = split_test_module.active_and_inactive_children()
|
||||
self.assertEqual(active_children, [])
|
||||
self.assertEqual(inactive_children, children)
|
||||
assert active_children == []
|
||||
assert inactive_children == children
|
||||
|
||||
def test_validation_messages(self): # lint-amnesty, pylint: disable=too-many-statements
|
||||
"""
|
||||
@@ -384,32 +375,32 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
"""
|
||||
Verify that the validation message has the expected validation message and type.
|
||||
"""
|
||||
self.assertEqual(message.text, expected_message)
|
||||
self.assertEqual(message.type, expected_message_type)
|
||||
assert message.text == expected_message
|
||||
assert message.type == expected_message_type
|
||||
if expected_action_class:
|
||||
self.assertEqual(message.action_class, expected_action_class)
|
||||
assert message.action_class == expected_action_class
|
||||
else:
|
||||
self.assertFalse(hasattr(message, "action_class"))
|
||||
assert not hasattr(message, 'action_class')
|
||||
if expected_action_label:
|
||||
self.assertEqual(message.action_label, expected_action_label)
|
||||
assert message.action_label == expected_action_label
|
||||
else:
|
||||
self.assertFalse(hasattr(message, "action_label"))
|
||||
assert not hasattr(message, 'action_label')
|
||||
if expected_action_runtime_event:
|
||||
self.assertEqual(message.action_runtime_event, expected_action_runtime_event)
|
||||
assert message.action_runtime_event == expected_action_runtime_event
|
||||
else:
|
||||
self.assertFalse(hasattr(message, "action_runtime_event"))
|
||||
assert not hasattr(message, 'action_runtime_event')
|
||||
|
||||
def verify_summary_message(general_validation, expected_message, expected_message_type):
|
||||
"""
|
||||
Verify that the general validation message has the expected validation message and type.
|
||||
"""
|
||||
self.assertEqual(general_validation.text, expected_message)
|
||||
self.assertEqual(general_validation.type, expected_message_type)
|
||||
assert general_validation.text == expected_message
|
||||
assert general_validation.type == expected_message_type
|
||||
|
||||
# Verify the messages for an unconfigured user partition
|
||||
split_test_module.user_partition_id = -1
|
||||
validation = split_test_module.validate()
|
||||
self.assertEqual(len(validation.messages), 0)
|
||||
assert len(validation.messages) == 0
|
||||
verify_validation_message(
|
||||
validation.summary,
|
||||
u"The experiment is not associated with a group configuration.",
|
||||
@@ -424,8 +415,8 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
UserPartition(0, 'first_partition', 'First Partition', [Group("0", 'alpha'), Group("1", 'beta')])
|
||||
]
|
||||
validation = split_test_module.validate_split_test()
|
||||
self.assertTrue(validation)
|
||||
self.assertIsNone(split_test_module.general_validation_message(), None)
|
||||
assert validation
|
||||
assert split_test_module.general_validation_message() is None, None
|
||||
|
||||
# Verify the messages for a split test with too few groups
|
||||
split_test_module.user_partitions = [
|
||||
@@ -433,7 +424,7 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
[Group("0", 'alpha'), Group("1", 'beta'), Group("2", 'gamma')])
|
||||
]
|
||||
validation = split_test_module.validate()
|
||||
self.assertEqual(len(validation.messages), 1)
|
||||
assert len(validation.messages) == 1
|
||||
verify_validation_message(
|
||||
validation.messages[0],
|
||||
u"The experiment does not contain all of the groups in the configuration.",
|
||||
@@ -452,7 +443,7 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
[Group("0", 'alpha')])
|
||||
]
|
||||
validation = split_test_module.validate()
|
||||
self.assertEqual(len(validation.messages), 1)
|
||||
assert len(validation.messages) == 1
|
||||
verify_validation_message(
|
||||
validation.messages[0],
|
||||
u"The experiment has an inactive group. Move content into active groups, then delete the inactive group.",
|
||||
@@ -469,7 +460,7 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
[Group("0", 'alpha'), Group("2", 'gamma')])
|
||||
]
|
||||
validation = split_test_module.validate()
|
||||
self.assertEqual(len(validation.messages), 2)
|
||||
assert len(validation.messages) == 2
|
||||
verify_validation_message(
|
||||
validation.messages[0],
|
||||
u"The experiment does not contain all of the groups in the configuration.",
|
||||
@@ -492,7 +483,7 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
# Verify the messages for a split test referring to a non-existent user partition
|
||||
split_test_module.user_partition_id = 2
|
||||
validation = split_test_module.validate()
|
||||
self.assertEqual(len(validation.messages), 1)
|
||||
assert len(validation.messages) == 1
|
||||
verify_validation_message(
|
||||
validation.messages[0],
|
||||
u"The experiment uses a deleted group configuration. "
|
||||
@@ -514,7 +505,7 @@ class SplitTestBlockStudioTest(SplitTestBlockTest):
|
||||
]
|
||||
split_test_module.user_partition_id = 10
|
||||
validation = split_test_module.validate()
|
||||
self.assertEqual(len(validation.messages), 1)
|
||||
assert len(validation.messages) == 1
|
||||
verify_validation_message(
|
||||
validation.messages[0],
|
||||
u"The experiment uses a group configuration that is not supported for experiments. "
|
||||
@@ -593,7 +584,7 @@ class SplitTestBlockExportImportTest(MixedSplitTestCase):
|
||||
exported_olx = f.read()
|
||||
|
||||
# And compare.
|
||||
self.assertEqual(exported_olx, expected_olx)
|
||||
assert exported_olx == expected_olx
|
||||
|
||||
runtime = TestImportSystem(load_error_modules=True, course_id=split_test_block.location.course_key)
|
||||
runtime.resources_fs = export_fs
|
||||
@@ -604,9 +595,9 @@ class SplitTestBlockExportImportTest(MixedSplitTestCase):
|
||||
imported_split_test_block = SplitTestBlock.parse_xml(olx_element, runtime, None, id_generator)
|
||||
|
||||
# Check the new XBlock has the same properties as the old one.
|
||||
self.assertEqual(imported_split_test_block.display_name, split_test_block.display_name)
|
||||
self.assertEqual(len(imported_split_test_block.children), len(split_test_block.children))
|
||||
self.assertEqual(imported_split_test_block.children, split_test_block.children)
|
||||
self.assertEqual(imported_split_test_block.user_partition_id, split_test_block.user_partition_id)
|
||||
self.assertEqual(imported_split_test_block.group_id_to_child['0'], str(split_test_block.group_id_to_child['0']))
|
||||
self.assertEqual(imported_split_test_block.group_id_to_child['1'], str(split_test_block.group_id_to_child['1']))
|
||||
assert imported_split_test_block.display_name == split_test_block.display_name
|
||||
assert len(imported_split_test_block.children) == len(split_test_block.children)
|
||||
assert imported_split_test_block.children == split_test_block.children
|
||||
assert imported_split_test_block.user_partition_id == split_test_block.user_partition_id
|
||||
assert imported_split_test_block.group_id_to_child['0'] == str(split_test_block.group_id_to_child['0'])
|
||||
assert imported_split_test_block.group_id_to_child['1'] == str(split_test_block.group_id_to_child['1'])
|
||||
|
||||
@@ -25,5 +25,5 @@ class StudioEditableModuleTestCase(BaseVerticalBlockTest):
|
||||
|
||||
# Both children of the vertical should be rendered as reorderable
|
||||
self.module_system.render(self.vertical, AUTHOR_VIEW, context).content # pylint: disable=expression-not-assigned
|
||||
self.assertIn(self.vertical.get_children()[0].location, reorderable_items)
|
||||
self.assertIn(self.vertical.get_children()[1].location, reorderable_items)
|
||||
assert self.vertical.get_children()[0].location in reorderable_items
|
||||
assert self.vertical.get_children()[1].location in reorderable_items
|
||||
|
||||
@@ -72,7 +72,7 @@ class UnitBlockTests(XmlTest, unittest.TestCase):
|
||||
The unit XBlock is designed to hold other XBlocks, so check that its
|
||||
completion status is defined as the aggregation of its child blocks.
|
||||
"""
|
||||
self.assertEqual(XBlockCompletionMode.get_mode(UnitBlock), XBlockCompletionMode.AGGREGATOR)
|
||||
assert XBlockCompletionMode.get_mode(UnitBlock) == XBlockCompletionMode.AGGREGATOR
|
||||
|
||||
def assertXmlEqual(self, xml_str_a, xml_str_b):
|
||||
"""
|
||||
@@ -84,4 +84,4 @@ class UnitBlockTests(XmlTest, unittest.TestCase):
|
||||
xml_str = re.sub(r'(\s)\s+', r'\1', xml_str)
|
||||
xml_bytes = xml_str.encode('utf8')
|
||||
return minidom.parseString(xml_bytes).toprettyxml()
|
||||
self.assertEqual(clean(xml_str_a), clean(xml_str_b))
|
||||
assert clean(xml_str_a) == clean(xml_str_b)
|
||||
|
||||
@@ -27,39 +27,39 @@ class TestGetExtendedDueDate(unittest.TestCase):
|
||||
Test no due date.
|
||||
"""
|
||||
node = object()
|
||||
self.assertEqual(self.call_fut(node), None)
|
||||
assert self.call_fut(node) is None
|
||||
|
||||
def test_due_date_no_extension(self):
|
||||
"""
|
||||
Test due date without extension.
|
||||
"""
|
||||
node = mock.Mock(due=1, extended_due=None)
|
||||
self.assertEqual(self.call_fut(node), 1)
|
||||
assert self.call_fut(node) == 1
|
||||
|
||||
def test_due_date_with_extension(self):
|
||||
"""
|
||||
Test due date with extension.
|
||||
"""
|
||||
node = mock.Mock(due=1, extended_due=2)
|
||||
self.assertEqual(self.call_fut(node), 2)
|
||||
assert self.call_fut(node) == 2
|
||||
|
||||
def test_due_date_extension_is_earlier(self):
|
||||
"""
|
||||
Test due date with extension, but due date is later than extension.
|
||||
"""
|
||||
node = mock.Mock(due=2, extended_due=1)
|
||||
self.assertEqual(self.call_fut(node), 2)
|
||||
assert self.call_fut(node) == 2
|
||||
|
||||
def test_extension_without_due_date(self):
|
||||
"""
|
||||
Test non-sensical extension without due date.
|
||||
"""
|
||||
node = mock.Mock(due=None, extended_due=1)
|
||||
self.assertEqual(self.call_fut(node), None)
|
||||
assert self.call_fut(node) is None
|
||||
|
||||
def test_due_date_with_extension_dict(self):
|
||||
"""
|
||||
Test due date with extension when node is a dict.
|
||||
"""
|
||||
node = {'due': 1, 'extended_due': 2}
|
||||
self.assertEqual(self.call_fut(node), 2)
|
||||
assert self.call_fut(node) == 2
|
||||
|
||||
@@ -19,7 +19,7 @@ class UtilHtmlEscapeTests(TestCase):
|
||||
|
||||
This is a paragraph.
|
||||
"""
|
||||
self.assertEqual(escape_html_characters(html_content), self.final_content)
|
||||
assert escape_html_characters(html_content) == self.final_content
|
||||
|
||||
def test_escape_cdata_comments(self):
|
||||
html_content = """
|
||||
@@ -39,7 +39,7 @@ class UtilHtmlEscapeTests(TestCase):
|
||||
|
||||
This is a paragraph.
|
||||
"""
|
||||
self.assertEqual(escape_html_characters(html_content), self.final_content)
|
||||
assert escape_html_characters(html_content) == self.final_content
|
||||
|
||||
def test_escape_non_breaking_space(self):
|
||||
html_content = """
|
||||
@@ -60,4 +60,4 @@ class UtilHtmlEscapeTests(TestCase):
|
||||
]]>
|
||||
This is a paragraph.
|
||||
"""
|
||||
self.assertEqual(escape_html_characters(html_content), self.final_content)
|
||||
assert escape_html_characters(html_content) == self.final_content
|
||||
|
||||
@@ -36,38 +36,24 @@ class StudioValidationMessageTest(unittest.TestCase):
|
||||
"""
|
||||
Test the `to_json` method.
|
||||
"""
|
||||
self.assertEqual(
|
||||
{
|
||||
"type": StudioValidationMessage.NOT_CONFIGURED,
|
||||
"text": u"Not Configured message",
|
||||
"action_label": u"Action label"
|
||||
},
|
||||
StudioValidationMessage(
|
||||
StudioValidationMessage.NOT_CONFIGURED, u"Not Configured message", action_label=u"Action label"
|
||||
).to_json()
|
||||
)
|
||||
assert \
|
||||
{'type': StudioValidationMessage.NOT_CONFIGURED,
|
||||
'text': u'Not Configured message', 'action_label': u'Action label'} == \
|
||||
StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED,
|
||||
u'Not Configured message', action_label=u'Action label').to_json()
|
||||
|
||||
self.assertEqual(
|
||||
{
|
||||
"type": StudioValidationMessage.WARNING,
|
||||
"text": u"Warning message",
|
||||
"action_class": "class-for-action"
|
||||
},
|
||||
StudioValidationMessage(
|
||||
StudioValidationMessage.WARNING, u"Warning message", action_class="class-for-action"
|
||||
).to_json()
|
||||
)
|
||||
assert \
|
||||
{'type': StudioValidationMessage.WARNING,
|
||||
'text': u'Warning message',
|
||||
'action_class': 'class-for-action'} ==\
|
||||
StudioValidationMessage(StudioValidationMessage.WARNING, u'Warning message',
|
||||
action_class='class-for-action').to_json()
|
||||
|
||||
self.assertEqual(
|
||||
{
|
||||
"type": StudioValidationMessage.ERROR,
|
||||
"text": u"Error message",
|
||||
"action_runtime_event": "do-fix-up"
|
||||
},
|
||||
StudioValidationMessage(
|
||||
StudioValidationMessage.ERROR, u"Error message", action_runtime_event="do-fix-up"
|
||||
).to_json()
|
||||
)
|
||||
assert \
|
||||
{'type': StudioValidationMessage.ERROR,
|
||||
'text': u'Error message', 'action_runtime_event': 'do-fix-up'} ==\
|
||||
StudioValidationMessage(StudioValidationMessage.ERROR,
|
||||
u'Error message', action_runtime_event='do-fix-up').to_json()
|
||||
|
||||
|
||||
class StudioValidationTest(unittest.TestCase):
|
||||
@@ -80,15 +66,15 @@ class StudioValidationTest(unittest.TestCase):
|
||||
validation.add(ValidationMessage(ValidationMessage.ERROR, u"Error message"))
|
||||
|
||||
studio_validation = StudioValidation.copy(validation)
|
||||
self.assertIsInstance(studio_validation, StudioValidation)
|
||||
self.assertFalse(studio_validation)
|
||||
self.assertEqual(1, len(studio_validation.messages))
|
||||
assert isinstance(studio_validation, StudioValidation)
|
||||
assert not studio_validation
|
||||
assert 1 == len(studio_validation.messages)
|
||||
expected = {
|
||||
"type": StudioValidationMessage.ERROR,
|
||||
"text": u"Error message"
|
||||
}
|
||||
self.assertEqual(expected, studio_validation.messages[0].to_json())
|
||||
self.assertIsNone(studio_validation.summary)
|
||||
assert expected == studio_validation.messages[0].to_json()
|
||||
assert studio_validation.summary is None
|
||||
|
||||
def test_copy_studio_validation(self):
|
||||
validation = StudioValidation("id")
|
||||
@@ -97,14 +83,14 @@ class StudioValidationTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
validation_copy = StudioValidation.copy(validation)
|
||||
self.assertFalse(validation_copy)
|
||||
self.assertEqual(1, len(validation_copy.messages))
|
||||
assert not validation_copy
|
||||
assert 1 == len(validation_copy.messages)
|
||||
expected = {
|
||||
"type": StudioValidationMessage.WARNING,
|
||||
"text": u"Warning message",
|
||||
"action_label": u"Action Label"
|
||||
}
|
||||
self.assertEqual(expected, validation_copy.messages[0].to_json())
|
||||
assert expected == validation_copy.messages[0].to_json()
|
||||
|
||||
def test_copy_errors(self):
|
||||
with pytest.raises(TypeError):
|
||||
@@ -116,19 +102,19 @@ class StudioValidationTest(unittest.TestCase):
|
||||
Also test the "bool" property of `Validation`.
|
||||
"""
|
||||
validation = StudioValidation("id")
|
||||
self.assertTrue(validation.empty)
|
||||
self.assertTrue(validation)
|
||||
assert validation.empty
|
||||
assert validation
|
||||
|
||||
validation.add(StudioValidationMessage(StudioValidationMessage.ERROR, u"Error message"))
|
||||
self.assertFalse(validation.empty)
|
||||
self.assertFalse(validation)
|
||||
assert not validation.empty
|
||||
assert not validation
|
||||
|
||||
validation_with_summary = StudioValidation("id")
|
||||
validation_with_summary.set_summary(
|
||||
StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, u"Summary message")
|
||||
)
|
||||
self.assertFalse(validation.empty)
|
||||
self.assertFalse(validation)
|
||||
assert not validation.empty
|
||||
assert not validation
|
||||
|
||||
def test_add_messages(self):
|
||||
"""
|
||||
@@ -143,16 +129,16 @@ class StudioValidationTest(unittest.TestCase):
|
||||
validation_2.add(StudioValidationMessage(StudioValidationMessage.NOT_CONFIGURED, u"Not configured"))
|
||||
|
||||
validation_1.add_messages(validation_2)
|
||||
self.assertEqual(2, len(validation_1.messages))
|
||||
assert 2 == len(validation_1.messages)
|
||||
|
||||
self.assertEqual(StudioValidationMessage.ERROR, validation_1.messages[0].type)
|
||||
self.assertEqual(u"Error message", validation_1.messages[0].text)
|
||||
assert StudioValidationMessage.ERROR == validation_1.messages[0].type
|
||||
assert u'Error message' == validation_1.messages[0].text
|
||||
|
||||
self.assertEqual(StudioValidationMessage.NOT_CONFIGURED, validation_1.messages[1].type)
|
||||
self.assertEqual(u"Not configured", validation_1.messages[1].text)
|
||||
assert StudioValidationMessage.NOT_CONFIGURED == validation_1.messages[1].type
|
||||
assert u'Not configured' == validation_1.messages[1].text
|
||||
|
||||
self.assertEqual(StudioValidationMessage.WARNING, validation_1.summary.type)
|
||||
self.assertEqual(u"Summary message", validation_1.summary.text)
|
||||
assert StudioValidationMessage.WARNING == validation_1.summary.type
|
||||
assert u'Summary message' == validation_1.summary.text
|
||||
|
||||
def test_set_summary_accepts_validation_message(self):
|
||||
"""
|
||||
@@ -160,8 +146,8 @@ class StudioValidationTest(unittest.TestCase):
|
||||
"""
|
||||
validation = StudioValidation("id")
|
||||
validation.set_summary(ValidationMessage(ValidationMessage.WARNING, u"Summary message"))
|
||||
self.assertEqual(ValidationMessage.WARNING, validation.summary.type)
|
||||
self.assertEqual(u"Summary message", validation.summary.text)
|
||||
assert ValidationMessage.WARNING == validation.summary.type
|
||||
assert u'Summary message' == validation.summary.text
|
||||
|
||||
def test_set_summary_errors(self):
|
||||
"""
|
||||
@@ -180,7 +166,7 @@ class StudioValidationTest(unittest.TestCase):
|
||||
"messages": [],
|
||||
"empty": True
|
||||
}
|
||||
self.assertEqual(expected, validation.to_json())
|
||||
assert expected == validation.to_json()
|
||||
|
||||
validation.add(
|
||||
StudioValidationMessage(
|
||||
@@ -233,4 +219,4 @@ class StudioValidationTest(unittest.TestCase):
|
||||
},
|
||||
"empty": False
|
||||
}
|
||||
self.assertEqual(expected, validation.to_json())
|
||||
assert expected == validation.to_json()
|
||||
|
||||
@@ -156,22 +156,22 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
html = self.module_system.render(
|
||||
self.vertical, view, self.default_context if context is None else context
|
||||
).content
|
||||
self.assertIn(self.test_html, html)
|
||||
assert self.test_html in html
|
||||
if view == STUDENT_VIEW:
|
||||
self.assertIn(self.test_problem, html)
|
||||
assert self.test_problem in html
|
||||
else:
|
||||
self.assertNotIn(self.test_problem, html)
|
||||
self.assertIn("'due': datetime.datetime({year}, {month}, {day}".format(
|
||||
year=self.vertical.due.year, month=self.vertical.due.month, day=self.vertical.due.day), html)
|
||||
assert self.test_problem not in html
|
||||
assert f"'due': datetime.datetime({self.vertical.due.year}, {self.vertical.due.month}, {self.vertical.due.day}"\
|
||||
in html
|
||||
if view == STUDENT_VIEW:
|
||||
self.assert_bookmark_info(self.assertIn, html)
|
||||
else:
|
||||
self.assert_bookmark_info(self.assertNotIn, html)
|
||||
if context:
|
||||
self.assertIn("'has_assignments': True", html)
|
||||
self.assertIn("'subsection_format': '{}'".format(context['format']), html)
|
||||
self.assertIn("'completed': {}".format(completion_value == 1), html)
|
||||
self.assertIn("'past_due': {}".format(self.vertical.due < now), html)
|
||||
assert "'has_assignments': True" in html
|
||||
assert "'subsection_format': '{}'".format(context['format']) in html
|
||||
assert "'completed': {}".format((completion_value == 1)) in html
|
||||
assert "'past_due': {}".format((self.vertical.due < now)) in html
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_render_problem_without_score(self, has_score):
|
||||
@@ -188,13 +188,13 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
|
||||
html = self.module_system.render(self.vertical, STUDENT_VIEW, self.default_context).content
|
||||
if has_score:
|
||||
self.assertIn("'has_assignments': True", html)
|
||||
self.assertIn("'completed': False", html)
|
||||
self.assertIn("'past_due': True", html)
|
||||
assert "'has_assignments': True" in html
|
||||
assert "'completed': False" in html
|
||||
assert "'past_due': True" in html
|
||||
else:
|
||||
self.assertIn("'has_assignments': False", html)
|
||||
self.assertIn("'completed': None", html)
|
||||
self.assertIn("'past_due': False", html)
|
||||
assert "'has_assignments': False" in html
|
||||
assert "'completed': None" in html
|
||||
assert "'past_due': False" in html
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_render_access_denied_blocks(self, has_access_error):
|
||||
@@ -208,9 +208,9 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
html = self.module_system.render(self.vertical, STUDENT_VIEW, context).content
|
||||
|
||||
if has_access_error:
|
||||
self.assertNotIn(self.test_problem, html)
|
||||
assert self.test_problem not in html
|
||||
else:
|
||||
self.assertIn(self.test_problem, html)
|
||||
assert self.test_problem in html
|
||||
|
||||
@ddt.unpack
|
||||
@ddt.data(
|
||||
@@ -231,11 +231,10 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
)
|
||||
self.module_system.render(self.vertical, STUDENT_VIEW, self.default_context)
|
||||
if mark_completed_enabled:
|
||||
self.assertEqual(
|
||||
mock_student_view.call_args[0][1]['wrap_xblock_data']['mark-completed-on-view-after-delay'], 9876
|
||||
)
|
||||
assert mock_student_view.call_args[0][1]['wrap_xblock_data']['mark-completed-on-view-after-delay'] ==\
|
||||
9876
|
||||
else:
|
||||
self.assertNotIn('wrap_xblock_data', mock_student_view.call_args[0][1])
|
||||
assert 'wrap_xblock_data' not in mock_student_view.call_args[0][1]
|
||||
|
||||
def test_render_studio_view(self):
|
||||
"""
|
||||
@@ -246,8 +245,8 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
'is_unit_page': True
|
||||
}
|
||||
html = self.module_system.render(self.vertical, AUTHOR_VIEW, context).content
|
||||
self.assertNotIn(self.test_html, html)
|
||||
self.assertNotIn(self.test_problem, html)
|
||||
assert self.test_html not in html
|
||||
assert self.test_problem not in html
|
||||
|
||||
# Vertical should render reorderable children on the container page
|
||||
reorderable_items = set()
|
||||
@@ -256,5 +255,5 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
||||
'reorderable_items': reorderable_items,
|
||||
}
|
||||
html = self.module_system.render(self.vertical, AUTHOR_VIEW, context).content
|
||||
self.assertIn(self.test_html, html)
|
||||
self.assertIn(self.test_problem, html)
|
||||
assert self.test_html in html
|
||||
assert self.test_problem in html
|
||||
|
||||
@@ -21,7 +21,7 @@ import shutil
|
||||
import unittest
|
||||
from tempfile import mkdtemp
|
||||
from uuid import uuid4
|
||||
|
||||
import pytest
|
||||
import ddt
|
||||
import httpretty
|
||||
import six
|
||||
@@ -125,10 +125,7 @@ class VideoBlockTest(unittest.TestCase):
|
||||
"""Test parsing old-style Youtube ID strings into a dict."""
|
||||
youtube_str = '0.75:jNCf2gIqpeE,1.00:ZwkTiUPN0mg,1.25:rsq9auxASqI,1.50:kMyNdzVHHgg'
|
||||
output = VideoBlock._parse_youtube(youtube_str)
|
||||
self.assertEqual(output, {'0.75': 'jNCf2gIqpeE',
|
||||
'1.00': 'ZwkTiUPN0mg',
|
||||
'1.25': 'rsq9auxASqI',
|
||||
'1.50': 'kMyNdzVHHgg'})
|
||||
assert output == {'0.75': 'jNCf2gIqpeE', '1.00': 'ZwkTiUPN0mg', '1.25': 'rsq9auxASqI', '1.50': 'kMyNdzVHHgg'}
|
||||
|
||||
def test_parse_youtube_one_video(self):
|
||||
"""
|
||||
@@ -137,35 +134,23 @@ class VideoBlockTest(unittest.TestCase):
|
||||
"""
|
||||
youtube_str = '0.75:jNCf2gIqpeE'
|
||||
output = VideoBlock._parse_youtube(youtube_str)
|
||||
self.assertEqual(output, {'0.75': 'jNCf2gIqpeE',
|
||||
'1.00': '',
|
||||
'1.25': '',
|
||||
'1.50': ''})
|
||||
assert output == {'0.75': 'jNCf2gIqpeE', '1.00': '', '1.25': '', '1.50': ''}
|
||||
|
||||
def test_parse_youtube_invalid(self):
|
||||
"""Ensure that ids that are invalid return an empty dict"""
|
||||
# invalid id
|
||||
youtube_str = 'thisisaninvalidid'
|
||||
output = VideoBlock._parse_youtube(youtube_str)
|
||||
self.assertEqual(output, {'0.75': '',
|
||||
'1.00': '',
|
||||
'1.25': '',
|
||||
'1.50': ''})
|
||||
assert output == {'0.75': '', '1.00': '', '1.25': '', '1.50': ''}
|
||||
# another invalid id
|
||||
youtube_str = ',::,:,,'
|
||||
output = VideoBlock._parse_youtube(youtube_str)
|
||||
self.assertEqual(output, {'0.75': '',
|
||||
'1.00': '',
|
||||
'1.25': '',
|
||||
'1.50': ''})
|
||||
assert output == {'0.75': '', '1.00': '', '1.25': '', '1.50': ''}
|
||||
|
||||
# and another one, partially invalid
|
||||
youtube_str = '0.75_BAD!!!,1.0:AXdE34_U,1.25:KLHF9K_Y,1.5:VO3SxfeD,'
|
||||
output = VideoBlock._parse_youtube(youtube_str)
|
||||
self.assertEqual(output, {'0.75': '',
|
||||
'1.00': 'AXdE34_U',
|
||||
'1.25': 'KLHF9K_Y',
|
||||
'1.50': 'VO3SxfeD'})
|
||||
assert output == {'0.75': '', '1.00': 'AXdE34_U', '1.25': 'KLHF9K_Y', '1.50': 'VO3SxfeD'}
|
||||
|
||||
def test_parse_youtube_key_format(self):
|
||||
"""
|
||||
@@ -173,23 +158,14 @@ class VideoBlockTest(unittest.TestCase):
|
||||
"""
|
||||
youtube_str = '1.00:p2Q6BrNhdh8'
|
||||
youtube_str_hack = '1.0:p2Q6BrNhdh8'
|
||||
self.assertEqual(
|
||||
VideoBlock._parse_youtube(youtube_str),
|
||||
VideoBlock._parse_youtube(youtube_str_hack)
|
||||
)
|
||||
assert VideoBlock._parse_youtube(youtube_str) == VideoBlock._parse_youtube(youtube_str_hack)
|
||||
|
||||
def test_parse_youtube_empty(self):
|
||||
"""
|
||||
Some courses have empty youtube attributes, so we should handle
|
||||
that well.
|
||||
"""
|
||||
self.assertEqual(
|
||||
VideoBlock._parse_youtube(''),
|
||||
{'0.75': '',
|
||||
'1.00': '',
|
||||
'1.25': '',
|
||||
'1.50': ''}
|
||||
)
|
||||
assert VideoBlock._parse_youtube('') == {'0.75': '', '1.00': '', '1.25': '', '1.50': ''}
|
||||
|
||||
|
||||
class VideoBlockTestBase(unittest.TestCase):
|
||||
@@ -213,9 +189,9 @@ class VideoBlockTestBase(unittest.TestCase):
|
||||
for attr in ['tag', 'attrib', 'text', 'tail']:
|
||||
expected_attr = getattr(expected, attr)
|
||||
actual_attr = getattr(xml, attr)
|
||||
self.assertEqual(expected_attr, actual_attr)
|
||||
assert expected_attr == actual_attr
|
||||
|
||||
self.assertEqual(get_child_tags(expected), get_child_tags(xml))
|
||||
assert get_child_tags(expected) == get_child_tags(xml)
|
||||
for left, right in zip(expected, xml):
|
||||
self.assertXmlEqual(left, right)
|
||||
|
||||
@@ -234,7 +210,7 @@ class TestCreateYoutubeString(VideoBlockTestBase):
|
||||
self.descriptor.youtube_id_1_25 = '1EeWXzPdhSA'
|
||||
self.descriptor.youtube_id_1_5 = 'rABDYkeK0x8'
|
||||
expected = "0.75:izygArpw-Qo,1.00:p2Q6BrNhdh8,1.25:1EeWXzPdhSA,1.50:rABDYkeK0x8"
|
||||
self.assertEqual(create_youtube_string(self.descriptor), expected)
|
||||
assert create_youtube_string(self.descriptor) == expected
|
||||
|
||||
def test_create_youtube_string_missing(self):
|
||||
"""
|
||||
@@ -244,7 +220,7 @@ class TestCreateYoutubeString(VideoBlockTestBase):
|
||||
self.descriptor.youtube_id_1_0 = 'p2Q6BrNhdh8'
|
||||
self.descriptor.youtube_id_1_25 = '1EeWXzPdhSA'
|
||||
expected = "0.75:izygArpw-Qo,1.00:p2Q6BrNhdh8,1.25:1EeWXzPdhSA"
|
||||
self.assertEqual(create_youtube_string(self.descriptor), expected)
|
||||
assert create_youtube_string(self.descriptor) == expected
|
||||
|
||||
|
||||
class TestCreateYouTubeUrl(VideoBlockTestBase):
|
||||
@@ -271,7 +247,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
Assert that `video` has the correct attributes. `attrs` is a map of {metadata_field: value}.
|
||||
"""
|
||||
for key, value in attrs.items():
|
||||
self.assertEqual(getattr(video, key), value)
|
||||
assert getattr(video, key) == value
|
||||
|
||||
def test_constructor(self):
|
||||
sample_xml = '''
|
||||
@@ -636,13 +612,13 @@ class VideoBlockImportTestCase(TestCase):
|
||||
"""
|
||||
def mock_val_import(xml, edx_video_id, resource_fs, static_dir, external_transcripts, course_id):
|
||||
"""Mock edxval.api.import_from_xml"""
|
||||
self.assertEqual(xml.tag, 'video_asset')
|
||||
self.assertEqual(dict(list(xml.items())), {'mock_attr': ''})
|
||||
self.assertEqual(edx_video_id, 'test_edx_video_id')
|
||||
self.assertEqual(static_dir, EXPORT_IMPORT_STATIC_DIR)
|
||||
self.assertIsNotNone(resource_fs)
|
||||
self.assertEqual(external_transcripts, {u'en': [u'subs_3_yD_cEKoCk.srt.sjson']})
|
||||
self.assertEqual(course_id, 'test_course_id')
|
||||
assert xml.tag == 'video_asset'
|
||||
assert dict(list(xml.items())) == {'mock_attr': ''}
|
||||
assert edx_video_id == 'test_edx_video_id'
|
||||
assert static_dir == EXPORT_IMPORT_STATIC_DIR
|
||||
assert resource_fs is not None
|
||||
assert external_transcripts == {u'en': [u'subs_3_yD_cEKoCk.srt.sjson']}
|
||||
assert course_id == 'test_course_id'
|
||||
return edx_video_id
|
||||
|
||||
edx_video_id = 'test_edx_video_id'
|
||||
@@ -686,7 +662,7 @@ class VideoBlockImportTestCase(TestCase):
|
||||
<video_asset client_video_id="test_client_video_id" duration="-1"/>
|
||||
</video>
|
||||
"""
|
||||
with self.assertRaises(mock_val_api.ValCannotCreateError):
|
||||
with pytest.raises(mock_val_api.ValCannotCreateError):
|
||||
VideoBlock.from_xml(xml_data, module_system, id_generator=Mock())
|
||||
|
||||
|
||||
@@ -811,7 +787,7 @@ class VideoExportTestCase(VideoBlockTestBase):
|
||||
xml = self.descriptor.definition_to_xml(self.file_system)
|
||||
# Check that download_video field is also set to default (False) in xml for backward compatibility
|
||||
expected = '<video url_name="SampleProblem"/>\n'
|
||||
self.assertEqual(expected, etree.tostring(xml, pretty_print=True).decode('utf-8'))
|
||||
assert expected == etree.tostring(xml, pretty_print=True).decode('utf-8')
|
||||
|
||||
@patch('xmodule.video_module.video_module.edxval_api', None)
|
||||
def test_export_to_xml_with_transcripts_as_none(self):
|
||||
@@ -821,7 +797,7 @@ class VideoExportTestCase(VideoBlockTestBase):
|
||||
self.descriptor.transcripts = None
|
||||
xml = self.descriptor.definition_to_xml(self.file_system)
|
||||
expected = b'<video url_name="SampleProblem"/>\n'
|
||||
self.assertEqual(expected, etree.tostring(xml, pretty_print=True))
|
||||
assert expected == etree.tostring(xml, pretty_print=True)
|
||||
|
||||
@patch('xmodule.video_module.video_module.edxval_api', None)
|
||||
def test_export_to_xml_invalid_characters_in_attributes(self):
|
||||
@@ -831,7 +807,7 @@ class VideoExportTestCase(VideoBlockTestBase):
|
||||
"""
|
||||
self.descriptor.display_name = 'Display\x1eName'
|
||||
xml = self.descriptor.definition_to_xml(self.file_system)
|
||||
self.assertEqual(xml.get('display_name'), 'DisplayName')
|
||||
assert xml.get('display_name') == 'DisplayName'
|
||||
|
||||
@patch('xmodule.video_module.video_module.edxval_api', None)
|
||||
def test_export_to_xml_unicode_characters(self):
|
||||
@@ -840,7 +816,7 @@ class VideoExportTestCase(VideoBlockTestBase):
|
||||
"""
|
||||
self.descriptor.display_name = u'这是文'
|
||||
xml = self.descriptor.definition_to_xml(self.file_system)
|
||||
self.assertEqual(xml.get('display_name'), u'\u8fd9\u662f\u6587')
|
||||
assert xml.get('display_name') == u'这是文'
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -889,7 +865,7 @@ class VideoBlockStudentViewDataTestCase(unittest.TestCase):
|
||||
descriptor = instantiate_descriptor(**field_data)
|
||||
descriptor.runtime.course_id = MagicMock()
|
||||
student_view_data = descriptor.student_view_data()
|
||||
self.assertEqual(student_view_data, expected_student_view_data)
|
||||
assert student_view_data == expected_student_view_data
|
||||
|
||||
@patch('xmodule.video_module.video_module.HLSPlaybackEnabledFlag.feature_enabled', Mock(return_value=True))
|
||||
@patch('xmodule.video_module.transcripts_utils.get_available_transcript_languages', Mock(return_value=['es']))
|
||||
@@ -987,10 +963,7 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
</video>
|
||||
'''
|
||||
descriptor = instantiate_descriptor(data=xml_data)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {"display_name": "Test Video"},
|
||||
"content_type": "Video"
|
||||
})
|
||||
assert descriptor.index_dictionary() == {'content': {'display_name': 'Test Video'}, 'content_type': 'Video'}
|
||||
|
||||
@httpretty.activate
|
||||
def test_video_with_youtube_subs_index_dictionary(self):
|
||||
@@ -1022,13 +995,8 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
descriptor = instantiate_descriptor(data=xml_data_sub)
|
||||
subs = download_youtube_subs(yt_subs_id, descriptor, settings)
|
||||
save_subs_to_store(json.loads(subs), yt_subs_id, descriptor)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {
|
||||
"display_name": "Test Video",
|
||||
"transcript_en": YOUTUBE_SUBTITLES
|
||||
},
|
||||
"content_type": "Video"
|
||||
})
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content': {'display_name': 'Test Video', 'transcript_en': YOUTUBE_SUBTITLES}, 'content_type': 'Video'}
|
||||
|
||||
@httpretty.activate
|
||||
def test_video_with_subs_and_transcript_index_dictionary(self):
|
||||
@@ -1063,14 +1031,10 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
subs = download_youtube_subs(yt_subs_id, descriptor, settings)
|
||||
save_subs_to_store(json.loads(subs), yt_subs_id, descriptor)
|
||||
save_to_store(SRT_FILEDATA, "subs_grmtran1.srt", 'text/srt', descriptor.location)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {
|
||||
"display_name": "Test Video",
|
||||
"transcript_en": YOUTUBE_SUBTITLES,
|
||||
"transcript_ge": "sprechen sie deutsch? Ja, ich spreche Deutsch",
|
||||
},
|
||||
"content_type": "Video"
|
||||
})
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content': {'display_name': 'Test Video', 'transcript_en': YOUTUBE_SUBTITLES,
|
||||
'transcript_ge': 'sprechen sie deutsch? Ja, ich spreche Deutsch'},
|
||||
'content_type': 'Video'}
|
||||
|
||||
def test_video_with_multiple_transcripts_index_dictionary(self):
|
||||
"""
|
||||
@@ -1096,14 +1060,10 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
descriptor = instantiate_descriptor(data=xml_data_transcripts)
|
||||
save_to_store(SRT_FILEDATA, "subs_grmtran1.srt", 'text/srt', descriptor.location)
|
||||
save_to_store(CRO_SRT_FILEDATA, "subs_croatian1.srt", 'text/srt', descriptor.location)
|
||||
self.assertEqual(descriptor.index_dictionary(), {
|
||||
"content": {
|
||||
"display_name": "Test Video",
|
||||
"transcript_ge": "sprechen sie deutsch? Ja, ich spreche Deutsch",
|
||||
"transcript_hr": "Dobar dan! Kako ste danas?"
|
||||
},
|
||||
"content_type": "Video"
|
||||
})
|
||||
assert descriptor.index_dictionary() ==\
|
||||
{'content': {'display_name': 'Test Video',
|
||||
'transcript_ge': 'sprechen sie deutsch? Ja, ich spreche Deutsch',
|
||||
'transcript_hr': 'Dobar dan! Kako ste danas?'}, 'content_type': 'Video'}
|
||||
|
||||
def test_video_with_multiple_transcripts_translation_retrieval(self):
|
||||
"""
|
||||
@@ -1128,7 +1088,7 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
|
||||
descriptor = instantiate_descriptor(data=xml_data_transcripts)
|
||||
translations = descriptor.available_translations(descriptor.get_transcripts_info())
|
||||
self.assertEqual(sorted(translations), sorted(['hr', 'ge']))
|
||||
assert sorted(translations) == sorted(['hr', 'ge'])
|
||||
|
||||
def test_video_with_no_transcripts_translation_retrieval(self):
|
||||
"""
|
||||
@@ -1138,13 +1098,13 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
"""
|
||||
descriptor = instantiate_descriptor(data=None)
|
||||
translations_with_fallback = descriptor.available_translations(descriptor.get_transcripts_info())
|
||||
self.assertEqual(translations_with_fallback, ['en'])
|
||||
assert translations_with_fallback == ['en']
|
||||
|
||||
with patch.dict(settings.FEATURES, FALLBACK_TO_ENGLISH_TRANSCRIPTS=False):
|
||||
# Some organizations don't have English transcripts for all videos
|
||||
# This feature makes it configurable
|
||||
translations_no_fallback = descriptor.available_translations(descriptor.get_transcripts_info())
|
||||
self.assertEqual(translations_no_fallback, [])
|
||||
assert translations_no_fallback == []
|
||||
|
||||
@override_settings(ALL_LANGUAGES=ALL_LANGUAGES)
|
||||
def test_video_with_language_do_not_have_transcripts_translation(self):
|
||||
@@ -1168,7 +1128,7 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
'''
|
||||
descriptor = instantiate_descriptor(data=xml_data_transcripts)
|
||||
translations = descriptor.available_translations(descriptor.get_transcripts_info(), verify_assets=False)
|
||||
self.assertNotEqual(translations, ['ur'])
|
||||
assert translations != ['ur']
|
||||
|
||||
def assert_validation_message(self, validation, expected_msg):
|
||||
"""
|
||||
@@ -1178,12 +1138,11 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
validation (StudioValidation): A validation object.
|
||||
expected_msg (string): An expected validation message.
|
||||
"""
|
||||
self.assertFalse(validation.empty) # Validation contains some warning/message
|
||||
self.assertTrue(validation.summary)
|
||||
self.assertEqual(StudioValidationMessage.WARNING, validation.summary.type)
|
||||
self.assertIn(
|
||||
expected_msg, validation.summary.text.replace('Urdu, Esperanto', 'Esperanto, Urdu')
|
||||
)
|
||||
assert not validation.empty
|
||||
# Validation contains some warning/message
|
||||
assert validation.summary
|
||||
assert StudioValidationMessage.WARNING == validation.summary.type
|
||||
assert expected_msg in validation.summary.text.replace('Urdu, Esperanto', 'Esperanto, Urdu')
|
||||
|
||||
@ddt.data(
|
||||
(
|
||||
@@ -1227,4 +1186,4 @@ class VideoBlockIndexingTestCase(unittest.TestCase):
|
||||
descriptor.transcripts = None
|
||||
response = descriptor.get_transcripts_info()
|
||||
expected = {'transcripts': {}, 'sub': ''}
|
||||
self.assertEqual(expected, response)
|
||||
assert expected == response
|
||||
|
||||
@@ -48,11 +48,11 @@ class WordCloudBlockTest(TestCase):
|
||||
CourseLocator('org', 'course', 'run', branch='revision'), 'word_cloud', 'block_id'
|
||||
)
|
||||
|
||||
self.assertEqual(block.display_name, 'Favorite Fruits')
|
||||
self.assertFalse(block.display_student_percents)
|
||||
self.assertEqual(block.instructions, 'What are your favorite fruits?')
|
||||
self.assertEqual(block.num_inputs, 3)
|
||||
self.assertEqual(block.num_top_words, 100)
|
||||
assert block.display_name == 'Favorite Fruits'
|
||||
assert not block.display_student_percents
|
||||
assert block.instructions == 'What are your favorite fruits?'
|
||||
assert block.num_inputs == 3
|
||||
assert block.num_top_words == 100
|
||||
|
||||
node = etree.Element("unknown_root")
|
||||
# This will export the olx to a separate file.
|
||||
@@ -60,7 +60,7 @@ class WordCloudBlockTest(TestCase):
|
||||
with runtime.export_fs.open(u'word_cloud/block_id.xml') as f:
|
||||
exported_xml = f.read()
|
||||
|
||||
self.assertEqual(exported_xml, original_xml)
|
||||
assert exported_xml == original_xml
|
||||
|
||||
def test_bad_ajax_request(self):
|
||||
"""
|
||||
@@ -86,9 +86,9 @@ class WordCloudBlockTest(TestCase):
|
||||
|
||||
post_data = MultiDict(('student_words[]', word) for word in ['cat', 'cat', 'dog', 'sun'])
|
||||
response = json.loads(block.handle_ajax('submit', post_data))
|
||||
self.assertEqual(response['status'], 'success')
|
||||
self.assertEqual(response['submitted'], True)
|
||||
self.assertEqual(response['total_count'], 22)
|
||||
assert response['status'] == 'success'
|
||||
assert response['submitted'] is True
|
||||
assert response['total_count'] == 22
|
||||
self.assertDictEqual(
|
||||
response['student_words'],
|
||||
{'sun': 1, 'dog': 6, 'cat': 12}
|
||||
@@ -103,7 +103,7 @@ class WordCloudBlockTest(TestCase):
|
||||
{'text': 'sun', 'size': 1, 'percent': 4.0}]
|
||||
)
|
||||
|
||||
self.assertEqual(100.0, sum(i['percent'] for i in response['top_words']))
|
||||
assert 100.0 == sum((i['percent'] for i in response['top_words']))
|
||||
|
||||
def test_indexibility(self):
|
||||
"""
|
||||
@@ -112,13 +112,7 @@ class WordCloudBlockTest(TestCase):
|
||||
|
||||
module_system = get_test_system()
|
||||
block = WordCloudBlock(module_system, DictFieldData(self.raw_field_data), Mock())
|
||||
self.assertEqual(
|
||||
block.index_dictionary(),
|
||||
{
|
||||
'content_type': 'Word Cloud',
|
||||
'content': {
|
||||
'display_name': 'Word Cloud Block',
|
||||
'instructions': 'Enter some random words that comes to your mind'
|
||||
}
|
||||
}
|
||||
)
|
||||
assert block.index_dictionary() ==\
|
||||
{'content_type': 'Word Cloud',
|
||||
'content': {'display_name': 'Word Cloud Block',
|
||||
'instructions': 'Enter some random words that comes to your mind'}}
|
||||
|
||||
@@ -340,10 +340,7 @@ class TestStudentView(XBlockWrapperTestMixin, TestCase):
|
||||
"""
|
||||
Assert that both student_view and get_html render the same.
|
||||
"""
|
||||
self.assertEqual(
|
||||
descriptor._xmodule.get_html(),
|
||||
descriptor.render(STUDENT_VIEW).content
|
||||
)
|
||||
assert descriptor._xmodule.get_html() == descriptor.render(STUDENT_VIEW).content
|
||||
|
||||
|
||||
class TestStudioView(XBlockWrapperTestMixin, TestCase):
|
||||
@@ -367,7 +364,7 @@ class TestStudioView(XBlockWrapperTestMixin, TestCase):
|
||||
"""
|
||||
html = descriptor.get_html()
|
||||
rendered_content = descriptor.render(STUDIO_VIEW).content
|
||||
self.assertEqual(html, rendered_content)
|
||||
assert html == rendered_content
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@@ -392,8 +389,8 @@ class TestXModuleHandler(TestCase):
|
||||
|
||||
def test_xmodule_handler_return_value(self):
|
||||
response = self.module.xmodule_handler(self.request)
|
||||
self.assertIsInstance(response, webob.Response)
|
||||
self.assertEqual(response.body.decode('utf-8'), '{}')
|
||||
assert isinstance(response, webob.Response)
|
||||
assert response.body.decode('utf-8') == '{}'
|
||||
|
||||
@ddt.data(
|
||||
u'{"test_key": "test_value"}',
|
||||
@@ -407,8 +404,8 @@ class TestXModuleHandler(TestCase):
|
||||
|
||||
self.module.handle_ajax = Mock(return_value=response_data)
|
||||
response = self.module.xmodule_handler(self.request)
|
||||
self.assertIsInstance(response, webob.Response)
|
||||
self.assertEqual(response.body.decode('utf-8'), '{"test_key": "test_value"}')
|
||||
assert isinstance(response, webob.Response)
|
||||
assert response.body.decode('utf-8') == '{"test_key": "test_value"}'
|
||||
|
||||
|
||||
class TestXmlExport(XBlockWrapperTestMixin, TestCase):
|
||||
@@ -430,8 +427,8 @@ class TestXmlExport(XBlockWrapperTestMixin, TestCase):
|
||||
|
||||
xmodule_node = etree.fromstring(descriptor.export_to_xml(xmodule_api_fs))
|
||||
|
||||
self.assertEqual(list(xmodule_api_fs.walk()), list(xblock_api_fs.walk()))
|
||||
self.assertEqual(etree.tostring(xmodule_node), etree.tostring(xblock_node))
|
||||
assert list(xmodule_api_fs.walk()) == list(xblock_api_fs.walk())
|
||||
assert etree.tostring(xmodule_node) == etree.tostring(xblock_node)
|
||||
|
||||
|
||||
class TestPublicView(XBlockWrapperTestMixin, TestCase):
|
||||
@@ -453,12 +450,6 @@ class TestPublicView(XBlockWrapperTestMixin, TestCase):
|
||||
Assert that public_view contains correct message.
|
||||
"""
|
||||
if descriptor.display_name:
|
||||
self.assertIn(
|
||||
descriptor.display_name,
|
||||
descriptor.render(PUBLIC_VIEW).content
|
||||
)
|
||||
assert descriptor.display_name in descriptor.render(PUBLIC_VIEW).content
|
||||
else:
|
||||
self.assertIn(
|
||||
"This content is only accessible",
|
||||
descriptor.render(PUBLIC_VIEW).content
|
||||
)
|
||||
assert 'This content is only accessible' in descriptor.render(PUBLIC_VIEW).content
|
||||
|
||||
@@ -131,8 +131,8 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
Test that the Blocks with nothing set with return the fields' defaults.
|
||||
"""
|
||||
block = self.get_a_block()
|
||||
self.assertEqual(block.inherited, "the default")
|
||||
self.assertEqual(block.not_inherited, "nothing")
|
||||
assert block.inherited == 'the default'
|
||||
assert block.not_inherited == 'nothing'
|
||||
|
||||
def test_set_value(self):
|
||||
"""
|
||||
@@ -141,8 +141,8 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
block = self.get_a_block()
|
||||
block.inherited = "Changed!"
|
||||
block.not_inherited = "New Value!"
|
||||
self.assertEqual(block.inherited, "Changed!")
|
||||
self.assertEqual(block.not_inherited, "New Value!")
|
||||
assert block.inherited == 'Changed!'
|
||||
assert block.not_inherited == 'New Value!'
|
||||
|
||||
def test_inherited(self):
|
||||
"""
|
||||
@@ -150,11 +150,11 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
"""
|
||||
parent_block = self.get_a_block(usage_id=self.get_usage_id("course", "parent"))
|
||||
parent_block.inherited = "Changed!"
|
||||
self.assertEqual(parent_block.inherited, "Changed!")
|
||||
assert parent_block.inherited == 'Changed!'
|
||||
|
||||
child = self.get_a_block(usage_id=self.get_usage_id("vertical", "child"))
|
||||
child.parent = parent_block.location
|
||||
self.assertEqual(child.inherited, "Changed!")
|
||||
assert child.inherited == 'Changed!'
|
||||
|
||||
def test_inherited_across_generations(self):
|
||||
"""
|
||||
@@ -162,12 +162,12 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
"""
|
||||
parent = self.get_a_block(usage_id=self.get_usage_id("course", "parent"))
|
||||
parent.inherited = "Changed!"
|
||||
self.assertEqual(parent.inherited, "Changed!")
|
||||
assert parent.inherited == 'Changed!'
|
||||
for child_num in range(10):
|
||||
usage_id = self.get_usage_id("vertical", "child_{}".format(child_num))
|
||||
child = self.get_a_block(usage_id=usage_id)
|
||||
child.parent = parent.location
|
||||
self.assertEqual(child.inherited, "Changed!")
|
||||
assert child.inherited == 'Changed!'
|
||||
|
||||
def test_not_inherited(self):
|
||||
"""
|
||||
@@ -175,11 +175,11 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
"""
|
||||
parent = self.get_a_block(usage_id=self.get_usage_id("course", "parent"))
|
||||
parent.not_inherited = "Changed!"
|
||||
self.assertEqual(parent.not_inherited, "Changed!")
|
||||
assert parent.not_inherited == 'Changed!'
|
||||
|
||||
child = self.get_a_block(usage_id=self.get_usage_id("vertical", "child"))
|
||||
child.parent = parent.location
|
||||
self.assertEqual(child.not_inherited, "nothing")
|
||||
assert child.not_inherited == 'nothing'
|
||||
|
||||
def test_non_defaults_inherited_across_lib(self):
|
||||
"""
|
||||
@@ -192,7 +192,7 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
fields=dict(inherited="changed!"),
|
||||
defaults=dict(inherited="parent's default"),
|
||||
)
|
||||
self.assertEqual(parent_block.inherited, "changed!")
|
||||
assert parent_block.inherited == 'changed!'
|
||||
|
||||
child = self.get_block_using_split_kvs(
|
||||
block_type="problem",
|
||||
@@ -201,7 +201,7 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
defaults={},
|
||||
)
|
||||
child.parent = parent_block.location
|
||||
self.assertEqual(child.inherited, "changed!")
|
||||
assert child.inherited == 'changed!'
|
||||
|
||||
def test_defaults_not_inherited_across_lib(self):
|
||||
"""
|
||||
@@ -214,7 +214,7 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
fields=dict(inherited="changed!"),
|
||||
defaults=dict(inherited="parent's default"),
|
||||
)
|
||||
self.assertEqual(parent_block.inherited, "changed!")
|
||||
assert parent_block.inherited == 'changed!'
|
||||
|
||||
child = self.get_block_using_split_kvs(
|
||||
block_type="library_content",
|
||||
@@ -223,7 +223,7 @@ class InheritingFieldDataTest(unittest.TestCase):
|
||||
defaults=dict(inherited="child's default"),
|
||||
)
|
||||
child.parent = parent_block.location
|
||||
self.assertEqual(child.inherited, "child's default")
|
||||
assert child.inherited == "child's default"
|
||||
|
||||
|
||||
class EditableMetadataFieldsTest(unittest.TestCase):
|
||||
@@ -232,7 +232,7 @@ class EditableMetadataFieldsTest(unittest.TestCase):
|
||||
editable_fields = self.get_xml_editable_fields(DictFieldData({}))
|
||||
# Tests that the xblock fields (currently tags and name) get filtered out.
|
||||
# Also tests that xml_attributes is filtered out of XmlDescriptor.
|
||||
self.assertEqual(1, len(editable_fields), editable_fields)
|
||||
assert 1 == len(editable_fields), editable_fields
|
||||
self.assert_field_values(
|
||||
editable_fields, 'display_name', XModuleMixin.display_name,
|
||||
explicitly_set=False, value=None, default_value=None
|
||||
@@ -249,7 +249,7 @@ class EditableMetadataFieldsTest(unittest.TestCase):
|
||||
def test_integer_field(self):
|
||||
descriptor = self.get_descriptor(DictFieldData({'max_attempts': '7'}))
|
||||
editable_fields = descriptor.editable_metadata_fields
|
||||
self.assertEqual(8, len(editable_fields))
|
||||
assert 8 == len(editable_fields)
|
||||
self.assert_field_values(
|
||||
editable_fields, 'max_attempts', TestFields.max_attempts,
|
||||
explicitly_set=True, value=7, default_value=1000, type='Integer',
|
||||
@@ -355,17 +355,17 @@ class EditableMetadataFieldsTest(unittest.TestCase):
|
||||
type='Generic', options=[]): # lint-amnesty, pylint: disable=redefined-builtin
|
||||
test_field = editable_fields[name]
|
||||
|
||||
self.assertEqual(field.name, test_field['field_name'])
|
||||
self.assertEqual(field.display_name, test_field['display_name'])
|
||||
self.assertEqual(field.help, test_field['help'])
|
||||
assert field.name == test_field['field_name']
|
||||
assert field.display_name == test_field['display_name']
|
||||
assert field.help == test_field['help']
|
||||
|
||||
self.assertEqual(field.to_json(value), test_field['value'])
|
||||
self.assertEqual(field.to_json(default_value), test_field['default_value'])
|
||||
assert field.to_json(value) == test_field['value']
|
||||
assert field.to_json(default_value) == test_field['default_value']
|
||||
|
||||
self.assertEqual(options, test_field['options'])
|
||||
self.assertEqual(type, test_field['type'])
|
||||
assert options == test_field['options']
|
||||
assert type == test_field['type']
|
||||
|
||||
self.assertEqual(explicitly_set, test_field['explicitly_set'])
|
||||
assert explicitly_set == test_field['explicitly_set']
|
||||
|
||||
|
||||
class TestSerialize(unittest.TestCase):
|
||||
|
||||
Reference in New Issue
Block a user