Skip to content

Commit

Permalink
Fix some parsons tests
Browse files Browse the repository at this point in the history
  • Loading branch information
smmercuri committed Feb 7, 2025
1 parent 131c031 commit 615fdc5
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 25 deletions.
9 changes: 8 additions & 1 deletion stack/input/parsons/parsons.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ protected function extra_validation($contents) {
if ($validation === 'EMPTYANSWER') {
$validation = '';
}
if (!self::validate_parsons_contents($contents)) {

if (!self::validate_parsons_string($validation)) {
return stack_string('parsons_got_unrecognised_value');
}
return '';
Expand Down Expand Up @@ -361,6 +362,12 @@ public static function validate_parsons_state($state) {
*/
public static function validate_parsons_string($input) {
$data = json_decode($input, true);
// When used in the input class $input is a string of a string, so we need to decode twice
// But in later usage (e.g., for filters) $input is just a string
if (is_string($data)) {
$data = json_decode($data, true);
}
//print_r($data);
// Check if the JSON decoding was successful and the resulting structure is an array.
if (json_last_error() !== JSON_ERROR_NONE || !is_array($data)) {
return false;
Expand Down
47 changes: 23 additions & 24 deletions tests/input_parsons_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,9 @@ public function test_validate_parsons_string_input(): void {
$el->set_parameter('sameType', true);
$state = $el->validate_student_response(['sans1' => 'Hello world'], $options, $ta,
new stack_cas_security());
// TODO: make sure we invalidate inputs which are not correct JSON.
$this->assertEquals(stack_input::INVALID, $state->status);
$this->assertEquals('"Hello world"', $state->contentsmodified);
$this->assertEquals('\[ \text{Hello world} \]', $state->contentsdisplayed);
$this->assertEquals('<span class="stacksyntaxexample">&quot;Hello world&quot;</span>', $state->contentsdisplayed);
$this->assertEquals('',
$el->get_teacher_answer_display($state->contentsmodified, $state->contentsdisplayed));
}
Expand All @@ -92,6 +91,7 @@ public function test_validate_parsons_state_input(): void {
$state = $el->validate_student_response(['sans1' => '[[{"used":[[[]]],"available":["aGVsbG8=","d29ybGQ="]},0]]'],
$options, $ta,
new stack_cas_security());
print_r($state);
$this->assertEquals(stack_input::VALID, $state->status);
$this->assertEquals('', $state->note);
$this->assertEquals('', $state->errors);
Expand All @@ -111,21 +111,21 @@ public function test_validate_parsons_state_input_malformed(): void {
$ta = "\"[[{\"used\":[[[\"UzE=\",\"UzI=\",\"UzQ=\",\"UzU=\",\"UzM=\",\"QzY=\"]]],\"available\":[]},1738672937]]\"";
$el = stack_input_factory::make('parsons', 'sans1', $ta);
$el->set_parameter('sameType', true);
$state = $el->validate_student_response(['sans1' => '{\"used\":[[]]],\"available\":[\"aGVsbG8=\",\"d29ybGQ=\"]},0]]'],
$state = $el->validate_student_response(['sans1' => '{"used":[[]]],"available":["aGVsbG8=","d29ybGQ="]},0]]'],
$options, $ta, new stack_cas_security());
$this->assertEquals(stack_input::INVALID, $state->status);
$this->assertEquals('', $state->note);
$this->assertEquals('', $state->errors);
$this->assertEquals('Invalid state for Parson\'s input.', $state->errors);
// The input does not modify the string contents.
$this->assertEquals('"{\\\\\"used\\\\\":[[]]],\\\\\"available\\\\\":[\\\\\"aGVsbG8=\\\\\",\\\\\"d29ybGQ=\\\\\"]},0]]"',
$this->assertEquals('"{\"used\":[[]]],\"available\":[\"aGVsbG8=\",\"d29ybGQ=\"]},0]]"',
$state->contentsmodified);
$this->assertEquals(
'<span class="stacksyntaxexample">&quot;{\\\\\&quot;used\\\\\&quot;:[[]]],\\\\\&quot;available\\\\\&quot;:' .
'[\\\\\&quot;aGVsbG8=\\\\\&quot;,\\\\\&quot;d29ybGQ=\\\\\&quot;]},0]]&quot;</span>', $state->contentsdisplayed);
'<span class="stacksyntaxexample">&quot;{\&quot;used\&quot;:[[]]],\&quot;available\&quot;:' .
'[\&quot;aGVsbG8=\&quot;,\&quot;d29ybGQ=\&quot;]},0]]&quot;</span>', $state->contentsdisplayed);
$this->assertEquals('',
$el->get_teacher_answer_display($state->contentsmodified, $state->contentsdisplayed));
$expected = 'sana1: "{\\\\\"used\\\\\":[[]]],\\\\\"available\\\\\":' .
'[\\\\\"aGVsbG8=\\\\\",\\\\\"d29ybGQ=\\\\\"]},0]]" [invalid]';
$expected = 'sana1: "{\"used\":[[]]],\"available\":' .
'[\"aGVsbG8=\",\"d29ybGQ=\"]},0]]" [invalid]';
$this->assertEquals($expected,
$el->summarise_response('sana1', $state, null));
}
Expand All @@ -139,12 +139,11 @@ public function test_validate_string_singlequotes_input(): void {
// Note here the student has used string quotes which are no longer respected.
$state = $el->validate_student_response(['sans1' => '\'[[{"used":[[[]]],"available":["aGVsbG8=","d29ybGQ="]},0]]\''],
$options, $ta, new stack_cas_security());
$this->assertEquals(stack_input::VALID, $state->status);
$this->assertEquals(stack_input::INVALID, $state->status);
$this->assertEquals('"\'[[{\"used\":[[[]]],\"available\":[\"aGVsbG8=\",\"d29ybGQ=\"]},0]]\'"', $state->contentsmodified);
// This will fail internal evaluation in the Parson's decode filter due to the extra quotes, so will remain unhashed.
$this->assertEquals(
'\[ \text{&apos;[[{&quot;used&quot;:[[[]]],&quot;available&quot;' .
':[&quot;aGVsbG8=&quot;,&quot;d29ybGQ=&quot;]},0]]&apos;} \]',
'<span class="stacksyntaxexample">&quot;\'[[{\&quot;used\&quot;:[[[]]],\&quot;available\&quot;:[\&quot;aGVsbG8=\&quot;,\&quot;d29ybGQ=\&quot;]},0]]\'&quot;</span>',
$state->contentsdisplayed
);
}
Expand Down Expand Up @@ -176,7 +175,7 @@ public function test_validate_remains_hashed_if_invalid_timestamp(): void {
$this->assertEquals(stack_input::INVALID, $state->status);
$this->assertEquals('"[[{\"used\":[[[]]],\"available\":[\"aGVsbG8=\",\"d29ybGQ=\"]},\"I am invalid timestamp\"]]"',
$state->contentsmodified);
// TODO: do we get a specific error message here?
$this->assertEquals('Invalid state for Parson\'s input.', $state->errors);
// This will fail internal evaluation in the Parson's decode filter due to invalid state, so will remain unhashed.
$this->assertEquals(
'<span class="stacksyntaxexample">&quot;[[{\&quot;used\&quot;:[[[]]],\&quot;available\&quot;:' .
Expand Down Expand Up @@ -218,10 +217,9 @@ public function test_validate_parsons_explicitempty(): void {
$el = stack_input_factory::make('parsons', 'sans1', $ta);
$el->set_parameter('options', 'allowempty');
$state = $el->validate_student_response(['sans1' => '""'], $options, $ta, new stack_cas_security());
$this->assertEquals(stack_input::VALID, $state->status);
// Note here the student has used string quotes which are respected.
$this->assertEquals(stack_input::INVALID, $state->status);
$this->assertEquals('"\"\""', $state->contentsmodified);
$this->assertEquals('\[ \text{&quot;&quot;} \]', $state->contentsdisplayed);
$this->assertEquals('<span class="stacksyntaxexample">&quot;\&quot;\&quot;&quot;</span>', $state->contentsdisplayed);
}

public function test_validate_parsons_allowempty(): void {
Expand All @@ -231,9 +229,10 @@ public function test_validate_parsons_allowempty(): void {
$el = stack_input_factory::make('parsons', 'sans1', $ta);
$el->set_parameter('options', 'allowempty');
$state = $el->validate_student_response(['sans1' => ''], $options, $ta, new stack_cas_security());
$this->assertEquals(stack_input::VALID, $state->status);
// We do not allow empty in Parson's block
$this->assertEquals(stack_input::INVALID, $state->status);
$this->assertEquals('""', $state->contentsmodified);
$this->assertEquals('\[ \text{ } \]', $state->contentsdisplayed);
$this->assertEquals('<span class="stacksyntaxexample">&quot;&quot;</span>', $state->contentsdisplayed);
}

public function test_validate_student_response_xss_4(): void {
Expand All @@ -244,23 +243,23 @@ public function test_validate_student_response_xss_4(): void {

$sa = '"<div onclick=\'dosuchandsuch\'></div>"';
$cm = '"\"&lt;&#8203;div on&#0;click&#0;&#61;\'dosuchandsuch\'>&lt;&#8203;/div&gt;\""';
$cd = '\[ \text{&quot;&lt;div on&#0;click&#0;&#61;&apos;dosuchandsuch&apos;&gt;&lt;/div&gt;&quot;} \]';
$cd = '<span class="stacksyntaxexample">&quot;\&quot;&lt;div on&#0;click&#0;&#61;\'dosuchandsuch\'&gt;&lt;/div&gt;\&quot;&quot;</span>';
$state = $el->validate_student_response(['sans1' => $sa], $options, $ta,
new stack_cas_security(false, '', '', ['ta']));
$this->assertEquals($state->status, stack_input::VALID);
$this->assertEquals($state->status, stack_input::INVALID);
$this->assertEquals('', $state->note);
$this->assertEquals('', $state->errors);
$this->assertEquals('Invalid state for Parson\'s input.', $state->errors);
$this->assertEquals($cm, $state->contentsmodified);
$this->assertEquals($cd, $state->contentsdisplayed);

$sa = '"<div onmousemove =\'dosuchandsuch\'></div>"';
$cm = '"\"&lt;&#8203;div on&#0;mousemove &#0;&#61;\'dosuchandsuch\'>&lt;&#8203;/div&gt;\""';
$cd = '\[ \text{&quot;&lt;div on&#0;mousemove &#0;&#61;&apos;dosuchandsuch&apos;&gt;&lt;/div&gt;&quot;} \]';
$cd = '<span class="stacksyntaxexample">&quot;\&quot;&lt;div on&#0;mousemove &#0;&#61;\'dosuchandsuch\'&gt;&lt;/div&gt;\&quot;&quot;</span>';
$state = $el->validate_student_response(['sans1' => $sa], $options, $ta,
new stack_cas_security(false, '', '', ['ta']));
$this->assertEquals($state->status, stack_input::VALID);
$this->assertEquals($state->status, stack_input::INVALID);
$this->assertEquals('', $state->note);
$this->assertEquals('', $state->errors);
$this->assertEquals('Invalid state for Parson\'s input.', $state->errors);
$this->assertEquals($cm, $state->contentsmodified);
$this->assertEquals($cd, $state->contentsdisplayed);
}
Expand Down

0 comments on commit 615fdc5

Please sign in to comment.