diff --git a/tests/helper.php b/tests/helper.php
index 34c780e9f07957220b4e68128fb54a4724661bc0..d28a605af4ba7233624f5aa91b902f09697dfd48 100644
--- a/tests/helper.php
+++ b/tests/helper.php
@@ -73,6 +73,7 @@ class qtype_stack_test_helper extends question_test_helper {
             'validator',          // Test teacher-defined input validators and language.
             'feedback',           // Test teacher-defined input feedback and complex numbers.
             'ordergreat',         // Test the ordergreat function at the question level, e.g. keyvals.
+            'exdowncase',         // Test the ordergreat function with exdowncase.
             // Test questions for all the various input types.
             'algebraic_input',
             'algebraic_input_right',
@@ -4096,6 +4097,94 @@ class qtype_stack_test_helper extends question_test_helper {
         return $q;
     }
 
+    /**
+     * @return qtype_stack_question.
+     */
+    public static function make_stack_question_exdowncase() {
+        $q = self::make_a_stack_question();
+
+        $q->name = 'exdowncase';
+        $q->questionvariables = "ordergreat(x);\nveq: 5*y^2-8*x*y+13*x^2 = 49;";
+        $q->questiontext = "What is {@veq@}? [[input:ansq]][[validation:ansq]]";
+        $q->generalfeedback = '';
+        $q->questionnote = '';
+
+        $q->specificfeedback = '[[feedback:firsttree]]';
+        $q->penalty = 0.25; // Non-zero and not the default.
+
+        $q->inputs['ansq'] = stack_input_factory::make(
+            'algebraic', 'ansq', 'veq', null,
+            [
+                'boxWidth' => 20, 'forbidWords' => ''
+            ]);
+
+        // By setting simp:true (the default) we check the re-ordering really happens.
+        $q->options->set_option('simplify', true);
+
+        $prt = new stdClass;
+        $prt->name              = 'firsttree';
+        $prt->id                = 0;
+        $prt->value             = 1;
+        $prt->feedbackstyle     = 1;
+        $prt->feedbackvariables = 'loweranseq:exdowncase(ansq);';
+        $prt->firstnodename     = '0';
+        $prt->nodes             = [];
+        $prt->autosimplify      = true;
+
+        $newnode = new stdClass;
+        $newnode->id                  = '0';
+        $newnode->nodename            = '0';
+        $newnode->description         = 'Use CasEqual as the test';
+        $newnode->sans                = 'loweranseq';
+        $newnode->tans                = 'veq';
+        $newnode->answertest          = 'CasEqual';
+        $newnode->testoptions         = '';
+        $newnode->quiet               = false;
+        $newnode->falsescore          = '0';
+        $newnode->falsescoremode      = '=';
+        $newnode->falsepenalty        = $q->penalty;
+        $newnode->falsefeedback       = "";
+        $newnode->falsefeedbackformat = '1';
+        $newnode->falseanswernote     = 'firsttree-0-0';
+        $newnode->falsenextnode       = '1';
+        $newnode->truescore           = '1';
+        $newnode->truescoremode       = '=';
+        $newnode->truepenalty         = $q->penalty;
+        $newnode->truefeedback        = "";
+        $newnode->truefeedbackformat  = '1';
+        $newnode->trueanswernote      = 'firsttree-0-1';
+        $newnode->truenextnode        = '1';
+        $prt->nodes[] = $newnode;
+        $newnode = new stdClass;
+        $newnode->id                  = '1';
+        $newnode->nodename            = '1';
+        $newnode->description         = 'Use AlgEquiv as the test';
+        $newnode->sans                = 'loweranseq';
+        $newnode->tans                = 'veq';
+        $newnode->answertest          = 'AlgEquiv';
+        $newnode->testoptions         = '';
+        $newnode->quiet               = false;
+        $newnode->falsescore          = '0';
+        $newnode->falsescoremode      = '=';
+        $newnode->falsepenalty        = $q->penalty;
+        $newnode->falsefeedback       = "";
+        $newnode->falsefeedbackformat = '1';
+        $newnode->falseanswernote     = 'firsttree-1-0';
+        $newnode->falsenextnode       = '-1';
+        $newnode->truescore           = '1';
+        $newnode->truescoremode       = '=';
+        $newnode->truepenalty         = $q->penalty;
+        $newnode->truefeedback        = "";
+        $newnode->truefeedbackformat  = '1';
+        $newnode->trueanswernote      = 'firsttree-1-1';
+        $newnode->truenextnode        = '-1';
+        $prt->nodes[] = $newnode;
+
+        $q->prts[$prt->name] = new stack_potentialresponse_tree_lite($prt, $prt->value, $q);
+
+        return $q;
+    }
+
     /**
      * Make the data what would be received from the editing form for an algebraic input question.
      *
diff --git a/tests/walkthrough_adaptive_test.php b/tests/walkthrough_adaptive_test.php
index b99dfb128fc4589f6176315ded43bb4000baf39a..7bef19bec6345763593b3c27c974c374d00fbccb 100644
--- a/tests/walkthrough_adaptive_test.php
+++ b/tests/walkthrough_adaptive_test.php
@@ -4818,4 +4818,73 @@ class walkthrough_adaptive_test extends qtype_stack_walkthrough_test_base {
         $expected = 'Seed: 1; ansq: 3*x+5*y=1 [score]; firsttree: # = 1 | ATCASEqual_true. | firsttree-0-1';
         $this->check_response_summary($expected);
     }
+
+    public function test_input_validator_exdowncase() {
+        $q = test_question_maker::make_question('stack', 'exdowncase');
+        $this->start_attempt_at_question($q, 'adaptive', 1);
+
+        // Check the initial state.
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->check_prt_score('firsttree', null, null);
+        $this->render();
+        $this->check_output_contains_text_input('ansq');
+        $this->check_output_does_not_contain_input_validation();
+        $this->check_output_does_not_contain_prt_feedback();
+        $this->check_output_does_not_contain_stray_placeholders();
+        $this->check_current_output(
+            new question_pattern_expectation('/What is/'),
+            $this->get_does_not_contain_feedback_expectation(),
+            $this->get_does_not_contain_num_parts_correct(),
+            $this->get_no_hint_visible_expectation()
+            );
+        $this->assert_content_with_maths_contains('\({13\cdot x^2-8\cdot y\cdot x+5\cdot y^2=49}\)',
+            $this->currentoutput);
+
+        // Process a validate request.
+        $ia = '13*x^2-8*y*x+5*y^2 = 49';
+        $this->process_submission(['ansq' => $ia, '-submit' => 1]);
+
+        $this->check_current_mark(null);
+        $this->check_prt_score('firsttree', null, null);
+        $this->render();
+
+        // Check order of variables in validation of answer matches what students type.
+        $expected = 'Seed: 1; ansq: 13*x^2-8*y*x+5*y^2 = 49 [valid]; firsttree: !';
+        $this->check_response_summary($expected);
+        $this->check_output_contains_text_input('ansq', $ia);
+        $this->check_output_contains_input_validation('ansq');
+        $this->check_output_does_not_contain_prt_feedback();
+        $this->check_output_does_not_contain_stray_placeholders();
+        $this->assert_content_with_maths_contains('\[ 13\cdot x^2-8\cdot y\cdot x+5\cdot y^2=49',
+            $this->currentoutput);
+        $ia = '13*x^2-8*y*x+5*y^2 = 49';
+        $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]);
+        $this->render();
+        $this->assert_content_with_maths_contains('\[ 13\cdot x^2-8\cdot y\cdot x+5\cdot y^2=49',
+            $this->currentoutput);
+        $expected = 'Seed: 1; ansq: 13*x^2-8*y*x+5*y^2 = 49 [score]; firsttree: # = 1 | ' .
+            'ATCASEqual_true. | firsttree-0-1 | ATEquation_sides | firsttree-1-1';
+        $this->check_response_summary($expected);
+
+        // New answer with upper case.
+        $ia = '13*X^2-8*y*x+5*y^2 = 49';
+        $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]);
+        $this->render();
+        $this->assert_content_with_maths_contains('\[ 13\cdot X^2-8\cdot y\cdot x+5\cdot y^2=49',
+            $this->currentoutput);
+        $expected = 'Seed: 1; ansq: 13*X^2-8*y*x+5*y^2 = 49 [score]; firsttree: # = 1 | ' .
+            'ATCASEqual_true. | firsttree-0-1 | ATEquation_sides | firsttree-1-1';
+        $this->check_response_summary($expected);
+
+        // New answer which is wrong.
+        $ia = '13*X^2-8*y*x+5*y^2 = 48';
+        $this->process_submission(['ansq' => $ia, 'ansq_val' => $ia, '-submit' => 1]);
+        $this->render();
+        $this->assert_content_with_maths_contains('\[ 13\cdot X^2-8\cdot y\cdot x+5\cdot y^2=48',
+            $this->currentoutput);
+        $expected = 'Seed: 1; ansq: 13*X^2-8*y*x+5*y^2 = 48 [score]; firsttree: # = 0 | ' .
+            'ATCASEqual_false. | firsttree-0-0 | ATEquation_lhs_notrhs | firsttree-1-0';
+        $this->check_response_summary($expected);
+    }
 }