@@ -369,7 +369,7 @@ public function test_xml_import(): void {
369369 <text></text>
370370 </questionvariables>
371371 <specificfeedback format="html">
372- <text>[[feedback:firsttree]]</text>
372+ <text>[[feedback:firsttree]][[feedback:secondtree]] </text>
373373 </specificfeedback>
374374 <questionnote format="html">
375375 <text></text>
@@ -413,6 +413,24 @@ public function test_xml_import(): void {
413413 <showvalidation>1</showvalidation>
414414 <options></options>
415415 </input>
416+ <input>
417+ <name>ans2</name>
418+ <type>algebraic</type>
419+ <tans>2</tans>
420+ <boxsize>5</boxsize>
421+ <strictsyntax>1</strictsyntax>
422+ <insertstars>0</insertstars>
423+ <syntaxhint></syntaxhint>
424+ <syntaxattribute>0</syntaxattribute>
425+ <forbidwords></forbidwords>
426+ <allowwords></allowwords>
427+ <forbidfloat>1</forbidfloat>
428+ <requirelowestterms>0</requirelowestterms>
429+ <checkanswertype>0</checkanswertype>
430+ <mustverify>1</mustverify>
431+ <showvalidation>1</showvalidation>
432+ <options></options>
433+ </input>
416434 <prt>
417435 <name>firsttree</name>
418436 <value>1</value>
@@ -445,6 +463,62 @@ public function test_xml_import(): void {
445463 </falsefeedback>
446464 </node>
447465 </prt>
466+ <prt>
467+ <name>secondtree</name>
468+ <value>1</value>
469+ <autosimplify>1</autosimplify>
470+ <feedbackvariables>
471+ <text></text>
472+ </feedbackvariables>
473+ <node>
474+ <name>0</name>
475+ <answertest>EqualComAss</answertest>
476+ <sans>ans2</sans>
477+ <tans>2</tans>
478+ <testoptions></testoptions>
479+ <quiet>0</quiet>
480+ <truescoremode>=</truescoremode>
481+ <truescore>1</truescore>
482+ <truepenalty>0</truepenalty>
483+ <truenextnode>-1</truenextnode>
484+ <trueanswernote>secondtree-1-T</trueanswernote>
485+ <truefeedback format="html">
486+ <text></text>
487+ </truefeedback>
488+ <falsescoremode>=</falsescoremode>
489+ <falsescore>0</falsescore>
490+ <falsepenalty>0</falsepenalty>
491+ <falsenextnode>1</falsenextnode>
492+ <falseanswernote>secondtree-1-F</falseanswernote>
493+ <falsefeedback format="html">
494+ <text></text>
495+ </falsefeedback>
496+ </node>
497+ <node>
498+ <name>1</name>
499+ <answertest>EqualComAss</answertest>
500+ <sans>ans2</sans>
501+ <tans>2</tans>
502+ <testoptions></testoptions>
503+ <quiet>0</quiet>
504+ <truescoremode>=</truescoremode>
505+ <truescore>1</truescore>
506+ <truepenalty>0</truepenalty>
507+ <truenextnode>-1</truenextnode>
508+ <trueanswernote>secondtree-2-T</trueanswernote>
509+ <truefeedback format="html">
510+ <text></text>
511+ </truefeedback>
512+ <falsescoremode>=</falsescoremode>
513+ <falsescore>0</falsescore>
514+ <falsepenalty>0</falsepenalty>
515+ <falsenextnode>-1</falsenextnode>
516+ <falseanswernote>secondtree-2-F</falseanswernote>
517+ <falsefeedback format="html">
518+ <text></text>
519+ </falsefeedback>
520+ </node>
521+ </prt>
448522 <deployedseed>12345</deployedseed>
449523 <qtest>
450524 <testcase>1</testcase>
@@ -479,7 +553,8 @@ public function test_xml_import(): void {
479553 $ expectedq = new stdClass ();
480554 $ expectedq ->qtype = 'stack ' ;
481555 $ expectedq ->name = 'test-0 ' ;
482- $ expectedq ->questiontext = 'What is $1+1$? [[input:ans1]] [[validation:ans1]] ' ;
556+ $ expectedq ->questiontext
557+ = 'What is $1+1$? [[input:ans1]] [[validation:ans1]] ' ;
483558 $ expectedq ->questiontextformat = FORMAT_HTML ;
484559 $ expectedq ->generalfeedback = '' ;
485560 $ expectedq ->generalfeedbackformat = FORMAT_HTML ;
@@ -488,7 +563,10 @@ public function test_xml_import(): void {
488563 $ expectedq ->penalty = 0.3333333 ;
489564
490565 $ expectedq ->questionvariables = '' ;
491- $ expectedq ->specificfeedback = ['text ' => '[[feedback:firsttree]] ' , 'format ' => FORMAT_HTML , 'files ' => []];
566+ $ expectedq ->specificfeedback = ['text ' => '[[feedback:firsttree]][[feedback:secondtree]] ' ,
567+ 'format ' => FORMAT_HTML ,
568+ 'files ' => [],
569+ ];
492570 $ expectedq ->questionnote = ['text ' => '' , 'format ' => FORMAT_HTML , 'files ' => []];
493571 $ expectedq ->questionsimplify = 1 ;
494572 $ expectedq ->assumepositive = 0 ;
@@ -531,6 +609,22 @@ public function test_xml_import(): void {
531609 $ expectedq ->ans1showvalidation = 1 ;
532610 $ expectedq ->ans1options = '' ;
533611
612+ $ expectedq ->ans2type = 'algebraic ' ;
613+ $ expectedq ->ans2modelans = 2 ;
614+ $ expectedq ->ans2boxsize = 5 ;
615+ $ expectedq ->ans2strictsyntax = 1 ;
616+ $ expectedq ->ans2insertstars = 0 ;
617+ $ expectedq ->ans2syntaxhint = '' ;
618+ $ expectedq ->ans2syntaxattribute = 0 ;
619+ $ expectedq ->ans2forbidwords = '' ;
620+ $ expectedq ->ans2allowwords = '' ;
621+ $ expectedq ->ans2forbidfloat = 1 ;
622+ $ expectedq ->ans2requirelowestterms = 0 ;
623+ $ expectedq ->ans2checkanswertype = 0 ;
624+ $ expectedq ->ans2mustverify = 1 ;
625+ $ expectedq ->ans2showvalidation = 1 ;
626+ $ expectedq ->ans2options = '' ;
627+
534628 $ expectedq ->firsttreevalue = 1 ;
535629 $ expectedq ->firsttreeautosimplify = 1 ;
536630 $ expectedq ->firsttreefeedbackstyle = 1 ;
@@ -553,6 +647,46 @@ public function test_xml_import(): void {
553647 $ expectedq ->firsttreefalseanswernote [0 ] = 'firsttree-1-F ' ;
554648 $ expectedq ->firsttreefalsefeedback [0 ] = ['text ' => '' , 'format ' => FORMAT_HTML , 'files ' => []];
555649
650+ $ expectedq ->secondtreevalue = 1 ;
651+ $ expectedq ->secondtreeautosimplify = 1 ;
652+ $ expectedq ->secondtreefeedbackstyle = 1 ;
653+ $ expectedq ->secondtreefeedbackvariables = '' ;
654+ $ expectedq ->secondtreeanswertest [0 ] = 'EqualComAss ' ;
655+ $ expectedq ->secondtreesans [0 ] = 'ans2 ' ;
656+ $ expectedq ->secondtreetans [0 ] = '2 ' ;
657+ $ expectedq ->secondtreetestoptions [0 ] = '' ;
658+ $ expectedq ->secondtreequiet [0 ] = 0 ;
659+ $ expectedq ->secondtreetruescoremode [0 ] = '= ' ;
660+ $ expectedq ->secondtreetruescore [0 ] = 1 ;
661+ $ expectedq ->secondtreetruepenalty [0 ] = 0 ;
662+ $ expectedq ->secondtreetruenextnode [0 ] = -1 ;
663+ $ expectedq ->secondtreetrueanswernote [0 ] = 'secondtree-1-T ' ;
664+ $ expectedq ->secondtreetruefeedback [0 ] = ['text ' => '' , 'format ' => FORMAT_HTML , 'files ' => []];
665+ $ expectedq ->secondtreefalsescoremode [0 ] = '= ' ;
666+ $ expectedq ->secondtreefalsescore [0 ] = 0 ;
667+ $ expectedq ->secondtreefalsepenalty [0 ] = 0 ;
668+ $ expectedq ->secondtreefalsenextnode [0 ] = 1 ;
669+ $ expectedq ->secondtreefalseanswernote [0 ] = 'secondtree-1-F ' ;
670+ $ expectedq ->secondtreefalsefeedback [0 ] = ['text ' => '' , 'format ' => FORMAT_HTML , 'files ' => []];
671+
672+ $ expectedq ->secondtreeanswertest [1 ] = 'EqualComAss ' ;
673+ $ expectedq ->secondtreesans [1 ] = 'ans2 ' ;
674+ $ expectedq ->secondtreetans [1 ] = '2 ' ;
675+ $ expectedq ->secondtreetestoptions [1 ] = '' ;
676+ $ expectedq ->secondtreequiet [1 ] = 0 ;
677+ $ expectedq ->secondtreetruescoremode [1 ] = '= ' ;
678+ $ expectedq ->secondtreetruescore [1 ] = 1 ;
679+ $ expectedq ->secondtreetruepenalty [1 ] = 0 ;
680+ $ expectedq ->secondtreetruenextnode [1 ] = -1 ;
681+ $ expectedq ->secondtreetrueanswernote [1 ] = 'secondtree-2-T ' ;
682+ $ expectedq ->secondtreetruefeedback [1 ] = ['text ' => '' , 'format ' => FORMAT_HTML , 'files ' => []];
683+ $ expectedq ->secondtreefalsescoremode [1 ] = '= ' ;
684+ $ expectedq ->secondtreefalsescore [1 ] = 0 ;
685+ $ expectedq ->secondtreefalsepenalty [1 ] = 0 ;
686+ $ expectedq ->secondtreefalsenextnode [1 ] = -1 ;
687+ $ expectedq ->secondtreefalseanswernote [1 ] = 'secondtree-2-F ' ;
688+ $ expectedq ->secondtreefalsefeedback [1 ] = ['text ' => '' , 'format ' => FORMAT_HTML , 'files ' => []];
689+
556690 $ expectedq ->deployedseeds = ['12345 ' ];
557691
558692 $ qtest = new stack_question_test ('' , ['ans1 ' => '2 ' ], 1 );
@@ -569,6 +703,57 @@ public function test_xml_import(): void {
569703 $ this ->assertEquals ($ expectedq ->deployedseeds , $ q ->deployedseeds ); // Redundant, but gives better fail messages.
570704 $ this ->assertEquals ($ expectedq ->testcases , $ q ->testcases ); // Redundant, but gives better fail messages.
571705 $ this ->assert (new question_check_specified_fields_expectation ($ expectedq ), $ q );
706+
707+ $ this ->assertEquals (null , $ q ->structuralerror ?? null );
708+ $ this ->assertEquals (null , $ q ->validationerrors ?? null );
709+
710+ $ xmldata ['question ' ]['# ' ]['input ' ][1 ]['# ' ]['name ' ][0 ]['# ' ] = 'ans1 ' ;
711+ $ q = $ importer ->try_importing_using_qtypes (
712+ $ xmldata ['question ' ],
713+ null ,
714+ null ,
715+ 'stack '
716+ );
717+
718+ $ this ->assertEquals (true , $ q ->structuralerror );
719+ $ this ->assertEquals (
720+ 'ans1input: Multiple inputs have the same name: ans1. ' .
721+ ' <br />This question cannot be saved or imported in its current state. ' ,
722+ $ q ->validationerrors
723+ );
724+
725+ $ xmldata ['question ' ]['# ' ]['input ' ][1 ]['# ' ]['name ' ][0 ]['# ' ] = 'ans2 ' ;
726+ $ xmldata ['question ' ]['# ' ]['prt ' ][1 ]['# ' ]['name ' ][0 ]['# ' ] = 'firsttree ' ;
727+ $ q = $ importer ->try_importing_using_qtypes (
728+ $ xmldata ['question ' ],
729+ null ,
730+ null ,
731+ 'stack '
732+ );
733+
734+ $ this ->assertEquals (true , $ q ->structuralerror );
735+ $ this ->assertEquals (
736+ 'firsttreeprt: Multiple prts have the same name: firsttree. <br /> ' .
737+ 'secondtreevalue: This PRT must be set up before the question can be saved. ' .
738+ '<br />This question cannot be saved or imported in its current state. ' ,
739+ $ q ->validationerrors
740+ );
741+
742+ $ xmldata ['question ' ]['# ' ]['prt ' ][1 ]['# ' ]['name ' ][0 ]['# ' ] = 'secondtree ' ;
743+ $ xmldata ['question ' ]['# ' ]['prt ' ][1 ]['# ' ]['node ' ][1 ]['# ' ]['name ' ][0 ]['# ' ] = '0 ' ;
744+ $ q = $ importer ->try_importing_using_qtypes (
745+ $ xmldata ['question ' ],
746+ null ,
747+ null ,
748+ 'stack '
749+ );
750+
751+ $ this ->assertEquals (true , $ q ->structuralerror );
752+ $ this ->assertEquals (
753+ '0node: Multiple nodes have the name: 0 in PRT: secondtree. <br /> ' .
754+ 'This question cannot be saved or imported in its current state. ' ,
755+ $ q ->validationerrors
756+ );
572757 }
573758
574759 public function test_get_input_names_from_question_text_input_only (): void {
0 commit comments