From 1ab581366e56f9e8c9e9f2ae2a78371a79ffc23a Mon Sep 17 00:00:00 2001 From: Glenn Rice Date: Mon, 19 Feb 2024 20:06:27 -0600 Subject: [PATCH] Fix Value::Error calls in a checker for a RadioMultiAnswer object. This fixes the issue observed in https://webwork.maa.org/moodle/mod/forum/discuss.php?d=8489. See the problem posted there for a problem to test this with. There were two problems really that caused the issue. First `$self->{ans}` is a doubly nested array. So `$self->{ans}[0]` won't be an answer evaluator, but rather an array of answer evaluators. That should have been `$self->{ans}[0][0]`. However, that still won't work in this case, because for the problem in that forum post there are no answers in the first part. Thus the `$self->{ans}[0]` is the emtpy array, and so `$self->{ans}[0][0]` is undefined, and still not an answer evaluator. So another approach was taken, and the context error is just added via the RadioMultiAnswer `appendMessage` instead. This also adds the context swapping added for MultiAnswer objects in pull request #632. The same issues that led to that pull request can occur for a RadioMultiAnswer. Furthermore, this fixes an issue in the changes from #632. That is that the `$ans` used on line 307 of parserMultiAnswer.pl is a variable that is not declared. There is no error for this because `strict` is not (yet) in effect for this macro. --- macros/parsers/parserMultiAnswer.pl | 10 +++++----- macros/parsers/parserRadioMultiAnswer.pl | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/macros/parsers/parserMultiAnswer.pl b/macros/parsers/parserMultiAnswer.pl index c4c2821871..d7eaaee99f 100644 --- a/macros/parsers/parserMultiAnswer.pl +++ b/macros/parsers/parserMultiAnswer.pl @@ -303,12 +303,12 @@ sub perform_check { $rh_ans->{isPreview} = $inputs->{previewAnswers} || ($inputs_{action} && $inputs->{action} =~ m/^Preview/); - Parser::Context->current(undef, $context); # change to multi-answer's context - my $flags = Value::contextSet($context, $self->cmp_contextFlags($ans)); # save old context flags - $context->{answerHash} = $rh_ans; # attach the answerHash + Parser::Context->current(undef, $context); # change to multi-answer's context + my $flags = Value::contextSet($context, $self->cmp_contextFlags($rh_ans)); # save old context flags + $context->{answerHash} = $rh_ans; # attach the answerHash my @result = Value::cmp_compare([@correct], [@student], $self, $rh_ans); - Value::contextSet($context, %{$flags}); # restore context values - $context->{answerHash} = undef; # remove answerHash + Value::contextSet($context, %{$flags}); # restore context values + $context->{answerHash} = undef; # remove answerHash if (!@result && $context->{error}{flag}) { $self->cmp_error($self->{ans}[0]); return 1 } my $result = (scalar(@result) > 1 ? [@result] : $result[0] || 0); diff --git a/macros/parsers/parserRadioMultiAnswer.pl b/macros/parsers/parserRadioMultiAnswer.pl index 001f890f11..d456e12bcc 100644 --- a/macros/parsers/parserRadioMultiAnswer.pl +++ b/macros/parsers/parserRadioMultiAnswer.pl @@ -533,7 +533,8 @@ sub check_string { # supplied checker. sub perform_check { my ($self, $rh_ans) = @_; - $self->context->clearError; + my $context = $self->context; + $context->clearError; my @correct; my @student; # The answers for all parts are sent to the grader. The answers in the incorrect parts from @@ -565,8 +566,17 @@ sub perform_check { $rh_ans->{isPreview} = $main::inputs_ref->{previewAnswers} || ($main::inputs_ref->{action} && $main::inputs_ref->{action} =~ m/^Preview/); $self->{errorMessages} = []; + + Parser::Context->current(undef, $context); # change to the radio multi answers's context + my $flags = Value::contextSet($context, $self->cmp_contextFlags($rh_ans)); # save old context flags my $result = Value::cmp_compare([@correct], [@student], $self, $rh_ans); - if (!defined $result && $self->context->{error}{flag}) { $self->cmp_error($self->{ans}[0]); return 1; } + Value::contextSet($context, %{$flags}); # restore context values + $context->{answerHash} = undef; # remove answerHash + + if (!defined $result && $self->context->{error}{flag}) { + $self->appendMessage($self->context->{error}{message}); + return 1; + } if (Value::matchNumber($result)) { $rh_ans->score($result); } else {