Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions cms/djangoapps/contentstore/views/tests/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
ALWAYS,
VisibilityState,
get_block_info,
_get_metadata_with_problem_defaults,
_get_source_index,
_xblock_type_and_display_name,
add_container_page_publishing_info,
Expand Down Expand Up @@ -3514,6 +3515,83 @@ def validate_xblock_info_consistency(
self.assertIsNone(xblock_info.get("child_info", None))


class TestGetMetadataWithProblemDefaults(ModuleStoreTestCase):
"""
Unit tests for _get_metadata_with_problem_defaults.

The helper must inject a ``weight`` value (derived from ``max_score()``) for
problem xblocks that have never had ``weight`` explicitly saved, while leaving
every other combination untouched.
"""

def _make_problem(self, **kwargs):
"""Create and return a problem xblock from the modulestore."""
course = CourseFactory.create()
block = BlockFactory.create(
parent_location=course.location,
category='problem',
display_name='A Problem',
**kwargs,
)
return modulestore().get_item(block.location)

# ------------------------------------------------------------------
# Problem blocks – weight absent from stored metadata
# ------------------------------------------------------------------

def test_problem_without_weight_adds_weight_from_max_score(self):
"""
When weight is absent and max_score() > 0, it is injected into metadata.
"""
xblock = self._make_problem()
with patch.object(xblock, 'max_score', return_value=3.0):
metadata = _get_metadata_with_problem_defaults(xblock)
self.assertEqual(metadata.get('weight'), 3.0)

def test_problem_without_weight_max_score_zero_does_not_inject(self):
"""
A zero max_score will not inject a weight.
"""
xblock = self._make_problem()
with patch.object(xblock, 'max_score', return_value=0):
metadata = _get_metadata_with_problem_defaults(xblock)
self.assertNotIn('weight', metadata)

# ------------------------------------------------------------------
# Problem blocks – weight already present in stored metadata
# ------------------------------------------------------------------

def test_problem_with_explicit_weight_is_preserved(self):
"""
When weight is already explicitly set, it will not be overwritten.
"""
xblock = self._make_problem(weight=5.0)
with patch.object(xblock, 'max_score', return_value=2.0):
metadata = _get_metadata_with_problem_defaults(xblock)
self.assertEqual(metadata.get('weight'), 5.0)

# ------------------------------------------------------------------
# Non-problem blocks
# ------------------------------------------------------------------

def test_non_problem_block_is_unmodified(self):
"""
Non-problem blocks must pass through untouched even if a max_score
method is available on them.
"""
course = CourseFactory.create()
video = BlockFactory.create(
parent_location=course.location,
category='video',
display_name='A Video',
)
xblock = modulestore().get_item(video.location)
metadata_before = dict(get_block_info(xblock).get('metadata', {}))
metadata_result = _get_metadata_with_problem_defaults(xblock)
self.assertEqual(metadata_result, metadata_before)
self.assertNotIn('weight', metadata_result)


@patch.dict("django.conf.settings.FEATURES", {"ENABLE_SPECIAL_EXAMS": True})
@ddt.ddt
class TestSpecialExamXBlockInfo(ItemTest):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,26 @@ def modify_xblock(usage_key, request):
)


def _get_metadata_with_problem_defaults(xblock):
"""
Returns own_metadata for the xblock, injecting a ``weight`` default for
problem blocks whose weight has never been explicitly saved.

Without this, the frontend falls back to displaying 1 (its own default)
even when the problem's actual point value differs. If ``max_score()``
returns a positive number, we inject it so the correct value is shown.
"""
metadata = own_metadata(xblock)
if xblock.scope_ids.block_type == 'problem' and 'weight' not in metadata:
try:
max_score_value = xblock.max_score()
if max_score_value and max_score_value > 0:
metadata['weight'] = float(max_score_value)
except Exception: # pylint: disable=broad-except
pass
return metadata


def save_xblock_with_callback(xblock, user, old_metadata=None, old_content=None):
"""
Updates the xblock in the modulestore.
Expand Down Expand Up @@ -1079,7 +1099,7 @@ def get_block_info(
xblock_info = create_xblock_info(
xblock,
data=data,
metadata=own_metadata(xblock),
metadata=_get_metadata_with_problem_defaults(xblock),
include_ancestor_info=include_ancestor_info,
include_children_predicate=include_children_predicate
)
Expand Down
Loading