Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: The XBlock should work even when max_attempts is null #155

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion freetextresponse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
present in order for the student to receive credit.
"""

__version__ = "4.1.0"
__version__ = "4.1.1"
7 changes: 6 additions & 1 deletion freetextresponse/tests/submitdisplay_class.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
{
"empty_null_max": {
"max_attempts": null,
"count_attempts": 1,
"result": ""
},
"empty_zero_max": {
"max_attempts": 0,
"count_attempts": 1,
"count_attempts": 1,
"result": ""
},
"empty_under_max": {
Expand Down
77 changes: 69 additions & 8 deletions freetextresponse/tests/test_all.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Module To Test FreeTextResponse XBlock
"""
from datetime import datetime, timedelta
from os import path
import json
import unittest
Expand Down Expand Up @@ -88,7 +89,7 @@ def test_generate_validation_message(self):
def test_validate_field_data(self, **test_dict):
"""
Checks classmethod validate_field_data
tests the instuctor values set in edit
tests the instructor values set in edit
"""
test_data = TestData()
test_data.weight = test_dict['weight']
Expand Down Expand Up @@ -324,6 +325,7 @@ def test_word_count_valid(self, **test_data):
# Messages
@ddt.data(
# max_attempts, count_attempts, result
(None, 4, ''),
(0, 4, ''),
(1, 0, 'You have used 0 of 1 submission'),
(3, 2, 'You have used 2 of 3 submissions'),
Expand Down Expand Up @@ -412,7 +414,7 @@ def test_get_submitted_message(
Tests _get_submitted_message
Returns a message to display to
the user after they submit a
resopnse
response
"""
self.xblock._word_count_valid = MagicMock(
return_value=word_count_valid
Expand Down Expand Up @@ -497,12 +499,53 @@ def test_get_submitdisplay_class(self, **test_data):
self.xblock._get_nodisplay_class()
)

def test_submit(self):
@ddt.data(
({'max_attempts': None, 'count_attempts': 1}, True),
({'max_attempts': None, 'count_attempts': 3}, True),
({'max_attempts': 0, 'count_attempts': 3}, True),
({'max_attempts': 3, 'count_attempts': 2}, True),
({'max_attempts': 3, 'count_attempts': 3}, False),
({'due': None, 'graceperiod': None}, True),
({'due': None, 'graceperiod': timedelta(hours=1)}, True),
(
{
'due': datetime.utcnow() + timedelta(hours=1),
'graceperiod': None,
},
True,
),
(
{
'due': datetime.utcnow() - timedelta(hours=1),
'graceperiod': None,
},
False,
),
(
{
'due': datetime.utcnow() - timedelta(hours=1),
'graceperiod': timedelta(hours=2),
},
True,
),
(
{
'due': datetime.utcnow() - timedelta(hours=5),
'graceperiod': timedelta(hours=2),
},
False,
),
)
@ddt.unpack
def test_submit(self, xblock_config, can_submit):
# pylint: disable=protected-access
"""
Tests save_reponse results
Tests save_response results
"""
data = json.dumps({'student_answer': 'asdf'})
student_answer = 'asdf'
for key, value in xblock_config.items():
setattr(self.xblock, key, value)
data = json.dumps({'student_answer': student_answer})
request = TestRequest()
request.method = 'POST'
request.body = data.encode('utf-8')
Expand Down Expand Up @@ -543,13 +586,27 @@ def test_submit(self):
response.json_body['visibility_class'],
self.xblock._get_indicator_visibility_class()
)
self.assertEqual(
self.xblock.student_answer,
student_answer if can_submit else ''
)

def test_save_reponse(self):
@ddt.data(
({'max_attempts': None, 'count_attempts': 1}, True),
({'max_attempts': None, 'count_attempts': 3}, True),
({'max_attempts': 0, 'count_attempts': 3}, True),
({'max_attempts': 3, 'count_attempts': 3}, False)
)
@ddt.unpack
def test_save_response(self, xblock_config, can_save):
# pylint: disable=protected-access
"""
Tests save_reponse results
Tests save_response results
"""
data = json.dumps({'student_answer': 'asdf'})
student_answer = 'asdf'
for key, value in xblock_config.items():
setattr(self.xblock, key, value)
data = json.dumps({'student_answer': student_answer})
request = TestRequest()
request.method = 'POST'
request.body = data.encode('utf-8')
Expand Down Expand Up @@ -587,3 +644,7 @@ def test_save_reponse(self):
response.json_body['visibility_class'],
self.xblock._get_indicator_visibility_class()
)
self.assertEqual(
self.xblock.student_answer,
student_answer if can_save else ''
)
12 changes: 10 additions & 2 deletions freetextresponse/tests/validate_field_data.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"weight_attemps_negative": {
"weight_attempts_negative": {
"weight": -1,
"max_attempts": 1,
"max_word_count": 1,
"min_word_count": 1,
"submitted_message": "s",
"result": "Weight Attempts cannot be negative"
},
"max_attemps_negative": {
"max_attempts_negative": {
"weight": 0,
"max_attempts": -1,
"max_word_count": 1,
Expand Down Expand Up @@ -38,6 +38,14 @@
"min_word_count": 2,
"submitted_message": "",
"result": "Submission Received Message cannot be blank"
},
"submission_message_blank_null_max_attempts": {
"weight": 0,
"max_attempts": null,
"max_word_count": 3,
"min_word_count": 2,
"submitted_message": "",
"result": "Submission Received Message cannot be blank"
}
}

16 changes: 8 additions & 8 deletions freetextresponse/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
try:
from xblock.utils.resources import ResourceLoader
from xblock.utils.studio_editable import StudioEditableXBlockMixin
except ModuleNotFoundError:
except ModuleNotFoundError: # pragma: no cover
# For backward compatibility with releases older than Quince.
from xblockutils.resources import ResourceLoader
from xblockutils.studio_editable import StudioEditableXBlockMixin
Expand Down Expand Up @@ -74,7 +74,7 @@ def _get_nodisplay_class(self):
Returns the css class for the submit button
"""
result = ''
if self.max_attempts > 0 and self.count_attempts >= self.max_attempts:
if self.max_attempts and 0 < self.max_attempts <= self.count_attempts:
result = 'nodisplay'
return result

Expand Down Expand Up @@ -142,7 +142,7 @@ def _get_used_attempts_feedback(self):
they have used if applicable
"""
result = ''
if self.max_attempts > 0:
if self.max_attempts and self.max_attempts > 0:
result = self.ngettext(
'You have used {count_attempts} of {max_attempts} submission',
'You have used {count_attempts} of {max_attempts} submissions',
Expand Down Expand Up @@ -206,7 +206,7 @@ def submit(self, data, suffix=''):
Processes the user's submission
"""
# Fails if the UI submit/save buttons were shut
# down on the previous sumbisson
# down on the previous submission
if self._can_submit():
self.student_answer = data['student_answer']
# Counting the attempts and publishing a score
Expand Down Expand Up @@ -239,8 +239,8 @@ def save_reponse(self, data, suffix=''):
Processes the user's save
"""
# Fails if the UI submit/save buttons were shut
# down on the previous sumbisson
if self.max_attempts == 0 or self.count_attempts < self.max_attempts:
# down on the previous submission
if not self.max_attempts or self.count_attempts < self.max_attempts:
self.student_answer = data['student_answer']
result = {
'status': 'success',
Expand Down Expand Up @@ -295,7 +295,7 @@ def _can_submit(self):
"""
if self.is_past_due():
return False
if self.max_attempts == 0:
if not self.max_attempts:
return True
if self.count_attempts < self.max_attempts:
return True
Expand All @@ -321,7 +321,7 @@ def validate_field_data(self, validation, data):
'Weight Attempts cannot be negative'
)
validation.add(msg)
if data.max_attempts < 0:
if data.max_attempts and data.max_attempts < 0:
msg = self._generate_validation_message(
'Maximum Attempts cannot be negative'
)
Expand Down
Loading