qti 2.28.0 → 2.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e41a3a5f23ea40d864c780f298babfa504ff43ec2db3b45b2601ab52233745b0
4
- data.tar.gz: 4258a94f2294a5d54a4e5fbe91b52b53d2942baaea5496d6cf989e3f5c87cffe
3
+ metadata.gz: 5faafa20e505881d4e305e9346f24060883b8cf86b1861f08021f6def9329ea9
4
+ data.tar.gz: 69bbc14fecc3909cfc905102433e2ae1631261cf56fcda2c13035a35583a9682
5
5
  SHA512:
6
- metadata.gz: 9430cbbbec8edd4361403e47f35dfea883431a9edd3519bc56b361f211af0ae3c0a8e51bc32bba4ee40360b725d354c7faa3517d50ffecb51b33970691ee065e
7
- data.tar.gz: 8ba772bb5cbbc3d492c37bd015052dd70e5c0ddbd01923a51959067a67ea407db8e91b14b3bd9c83452678e05ff80626a53f3750384d37d77ae680b7dbc60635
6
+ metadata.gz: 43f8a769c16f2a2671219c7f2f3b4e25a3c8321dfed55d17035d1b3eab2238dcbae93f8b669e4393971a31c9607cfb3f2ca78ba454538bcfd279673f2f271eae
7
+ data.tar.gz: d51c5c66f01164d227c38ebb3098787096ce1b1257737ffe42ae70db5af39c8e09157b87c6469e7b66599803547c3bf92b6c0c9cacb667ef490e15bec86e27df
@@ -105,6 +105,27 @@ module Qti
105
105
  end
106
106
  end
107
107
 
108
+ def case_sensitive
109
+ @case_sensitive ||= begin
110
+ if case_sensitive_metadata?
111
+ case_sensitive_metadata_label = qti_metadata_children.children.find do |node|
112
+ node.text == 'case_sensitive'
113
+ end
114
+ case_sensitive_metadata_label.next.text
115
+ end
116
+ end
117
+ end
118
+
119
+ def case_sensitive_metadata?
120
+ if @doc.at_xpath('.//xmlns:qtimetadata').present?
121
+ qti_metadata_children.children.find do |node|
122
+ node.text == 'case_sensitive'
123
+ end.present?
124
+ else
125
+ false
126
+ end
127
+ end
128
+
108
129
  def decvar_maxvalue
109
130
  @doc.at_xpath('.//xmlns:decvar/@maxvalue')&.value&.to_i ||
110
131
  @doc.at_xpath('.//xmlns:decvar/@defaultval')&.value&.to_i || 0
@@ -29,8 +29,35 @@ module Qti
29
29
  end
30
30
  end
31
31
 
32
+ # Numeric answers cannot be paired with their comment through a
33
+ # `varequal`, the way the base implementation does it: exact and
34
+ # precision answers nest it inside an `or`, and range answers have no
35
+ # single value to emit one for. Canvas instead puts each answer's
36
+ # `displayfeedback` in the same `respcondition` that carries its
37
+ # `setvar SCORE`, so pair them by that node and key the result on the
38
+ # position within `answer_nodes` -- the same list, in the same order,
39
+ # that `scoring_data_structs` is built from.
40
+ def answer_feedback
41
+ answers = answer_nodes.filter_map.with_index do |answer_node, index|
42
+ numeric_answer_feedback_entry(answer_node, index)
43
+ end
44
+ answers unless answers.empty?
45
+ end
46
+
32
47
  private
33
48
 
49
+ def numeric_answer_feedback_entry(answer_node, index)
50
+ refid = answer_node.xpath('./xmlns:displayfeedback[not (@linkrefid="correct_fb" or ' \
51
+ '@linkrefid="general_incorrect_fb" or @linkrefid="general_fb")]').first&.[](:linkrefid)
52
+ feedback = get_feedback(refid)
53
+ return nil unless feedback
54
+ {
55
+ response_index: index,
56
+ texttype: feedback[:texttype],
57
+ feedback: feedback.text
58
+ }
59
+ end
60
+
34
61
  def answer_nodes
35
62
  @node.xpath('.//xmlns:respcondition/xmlns:setvar[@varname="SCORE"]/..')
36
63
  end
data/lib/qti/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '2.28.0'.freeze
2
+ VERSION = '2.30.0'.freeze
3
3
  end
@@ -0,0 +1,134 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <questestinterop xmlns="http://www.imsglobal.org/xsd/ims_qtiasiv1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd">
3
+ <item ident="97b0baae152f137d14503e2a2125c4d0" title="NQ Fill in Multiple Blanks Case Sensitive">
4
+ <itemmetadata>
5
+ <qtimetadata>
6
+ <qtimetadatafield>
7
+ <fieldlabel>question_type</fieldlabel>
8
+ <fieldentry>fill_in_multiple_blanks_question</fieldentry>
9
+ </qtimetadatafield>
10
+ <qtimetadatafield>
11
+ <fieldlabel>points_possible</fieldlabel>
12
+ <fieldentry>1.0</fieldentry>
13
+ </qtimetadatafield>
14
+ <qtimetadatafield>
15
+ <fieldlabel>original_answer_ids</fieldlabel>
16
+ <fieldentry>["bafd8242-ecdb-4158-a6d3-4ff15e016cb8-0", "d719aee0-6ce0-462c-9c0d-be63ba8d3408-0", "ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90-0", "41dfd716-8fd9-466a-97fa-33d353e44b42-0", "41dfd716-8fd9-466a-97fa-33d353e44b42-1", "a053119f-6a61-4372-ac79-4b2a7de0232f-0"]</fieldentry>
17
+ </qtimetadatafield>
18
+ <qtimetadatafield>
19
+ <fieldlabel>assessment_question_identifierref</fieldlabel>
20
+ <fieldentry>eaeec2d07f83998ee7b317ffde86dbc0</fieldentry>
21
+ </qtimetadatafield>
22
+ <qtimetadatafield>
23
+ <fieldlabel>case_sensitive</fieldlabel>
24
+ <fieldentry>true</fieldentry>
25
+ </qtimetadatafield>
26
+ </qtimetadata>
27
+ </itemmetadata>
28
+ <presentation>
29
+ <material>
30
+ <mattext texttype="text/html">&lt;p&gt;Roses are [bafd8242-ecdb-4158-a6d3-4ff15e016cb8], [d719aee0-6ce0-462c-9c0d-be63ba8d3408], [ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90], [41dfd716-8fd9-466a-97fa-33d353e44b42], and [a053119f-6a61-4372-ac79-4b2a7de0232f].&lt;/p&gt;</mattext>
31
+ </material>
32
+ <response_lid ident="response_bafd8242-ecdb-4158-a6d3-4ff15e016cb8">
33
+ <material>
34
+ <mattext>red</mattext>
35
+ </material>
36
+ <render_choice>
37
+ <response_label ident="bafd8242-ecdb-4158-a6d3-4ff15e016cb8-0" scoring_algorithm='TextContainsAnswer' answer_type='openEntry'>
38
+ <material>
39
+ <mattext texttype="text/plain">red</mattext>
40
+ </material>
41
+ </response_label>
42
+ </render_choice>
43
+ </response_lid>
44
+ <response_lid ident="response_d719aee0-6ce0-462c-9c0d-be63ba8d3408">
45
+ <material>
46
+ <mattext>blue</mattext>
47
+ </material>
48
+ <render_choice>
49
+ <response_label ident="d719aee0-6ce0-462c-9c0d-be63ba8d3408-0" scoring_algorithm='TextCloseEnough' answer_type='openEntry' levenshtein_distance='1' ignore_case='true'>
50
+ <material>
51
+ <mattext texttype="text/plain">blue</mattext>
52
+ </material>
53
+ </response_label>
54
+ </render_choice>
55
+ </response_lid>
56
+ <response_lid ident="response_ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90">
57
+ <material>
58
+ <mattext>green</mattext>
59
+ </material>
60
+ <render_choice>
61
+ <response_label ident="ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90-0" scoring_algorithm='TextEquivalence' answer_type='openEntry'>
62
+ <material>
63
+ <mattext texttype="text/plain">green</mattext>
64
+ </material>
65
+ </response_label>
66
+ </render_choice>
67
+ </response_lid>
68
+ <response_lid ident="response_41dfd716-8fd9-466a-97fa-33d353e44b42">
69
+ <material>
70
+ <mattext>yellow</mattext>
71
+ </material>
72
+ <render_choice>
73
+ <response_label ident="41dfd716-8fd9-466a-97fa-33d353e44b42-0" scoring_algorithm='TextInChoices' answer_type='openEntry'>
74
+ <material>
75
+ <mattext texttype="text/plain">yellow</mattext>
76
+ </material>
77
+ </response_label>
78
+ <response_label ident="41dfd716-8fd9-466a-97fa-33d353e44b42-1" scoring_algorithm='TextInChoices' answer_type='openEntry'>
79
+ <material>
80
+ <mattext texttype="text/plain">teal</mattext>
81
+ </material>
82
+ </response_label>
83
+ </render_choice>
84
+ </response_lid>
85
+ <response_lid ident="response_a053119f-6a61-4372-ac79-4b2a7de0232f">
86
+ <material>
87
+ <mattext>^orange&lt;s&gt;$</mattext>
88
+ </material>
89
+ <render_choice>
90
+ <response_label ident="a053119f-6a61-4372-ac79-4b2a7de0232f-0" scoring_algorithm='TextRegex' answer_type='openEntry'>
91
+ <material>
92
+ <mattext texttype="text/plain">^orange&lt;s&gt;$</mattext>
93
+ </material>
94
+ </response_label>
95
+ </render_choice>
96
+ </response_lid>
97
+ </presentation>
98
+ <resprocessing>
99
+ <outcomes>
100
+ <decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
101
+ </outcomes>
102
+ <respcondition>
103
+ <conditionvar>
104
+ <varequal respident="response_bafd8242-ecdb-4158-a6d3-4ff15e016cb8">bafd8242-ecdb-4158-a6d3-4ff15e016cb8-0</varequal>
105
+ </conditionvar>
106
+ <setvar action="Add" varname="SCORE">20.00</setvar>
107
+ </respcondition>
108
+ <respcondition>
109
+ <conditionvar>
110
+ <varequal respident="response_d719aee0-6ce0-462c-9c0d-be63ba8d3408">d719aee0-6ce0-462c-9c0d-be63ba8d3408-0</varequal>
111
+ </conditionvar>
112
+ <setvar action="Add" varname="SCORE">20.00</setvar>
113
+ </respcondition>
114
+ <respcondition>
115
+ <conditionvar>
116
+ <varequal respident="response_ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90">ce47aaf6-c1dd-4db8-9a9f-7f5c131d8a90-0</varequal>
117
+ </conditionvar>
118
+ <setvar action="Add" varname="SCORE">20.00</setvar>
119
+ </respcondition>
120
+ <respcondition>
121
+ <conditionvar>
122
+ <varequal respident="response_41dfd716-8fd9-466a-97fa-33d353e44b42">41dfd716-8fd9-466a-97fa-33d353e44b42-0</varequal>
123
+ </conditionvar>
124
+ <setvar action="Add" varname="SCORE">20.00</setvar>
125
+ </respcondition>
126
+ <respcondition>
127
+ <conditionvar>
128
+ <varequal respident="response_a053119f-6a61-4372-ac79-4b2a7de0232f">a053119f-6a61-4372-ac79-4b2a7de0232f-0</varequal>
129
+ </conditionvar>
130
+ <setvar action="Add" varname="SCORE">20.00</setvar>
131
+ </respcondition>
132
+ </resprocessing>
133
+ </item>
134
+ </questestinterop>
@@ -0,0 +1,189 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ Numeric per-answer feedback fixture. Question1 covers all four numeric answer
4
+ types (exact, precision, margin of error, range) plus item level feedback that
5
+ must be ignored; Question2 has comments on only the first and third of three
6
+ answers, covering index alignment with scoring_data_structs.
7
+ -->
8
+ <questestinterop xmlns="http://www.imsglobal.org/xsd/ims_qtiasiv1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.imsglobal.org/xsd/ims_qtiasiv1p2 http://www.imsglobal.org/xsd/ims_qtiasiv1p2p1.xsd">
9
+ <assessment ident="i98661073a66c6b2567c8f9b1a22c2989" title="Numeric feedback">
10
+ <section ident="root_section">
11
+ <item ident="ia63b6a115fa68a555398a58626a62f82" title="Question1">
12
+ <presentation>
13
+ <material>
14
+ <mattext texttype="text/html">&lt;div&gt;&lt;p&gt;question 1&lt;/p&gt;&lt;/div&gt;</mattext>
15
+ </material>
16
+ <response_str ident="response1" rcardinality="Single">
17
+ <render_fib fibtype="Decimal">
18
+ <response_label ident="answer1"/>
19
+ </render_fib>
20
+ </response_str>
21
+ </presentation>
22
+ <resprocessing>
23
+ <outcomes>
24
+ <decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
25
+ </outcomes>
26
+ <respcondition continue="No">
27
+ <conditionvar>
28
+ <or>
29
+ <varequal respident="response1">42.0</varequal>
30
+ <and>
31
+ <vargte respident="response1">42.0</vargte>
32
+ <varlte respident="response1">42.0</varlte>
33
+ </and>
34
+ </or>
35
+ </conditionvar>
36
+ <setvar action="Set" varname="SCORE">100</setvar>
37
+ <displayfeedback feedbacktype="Response" linkrefid="1001_fb"/>
38
+ <displayfeedback feedbacktype="Response" linkrefid="correct_fb"/>
39
+ </respcondition>
40
+ <respcondition continue="No">
41
+ <conditionvar>
42
+ <or>
43
+ <varequal respident="response1">1000.00</varequal>
44
+ <and>
45
+ <vargt respident="response1">999.995</vargt>
46
+ <varlte respident="response1">1000.005</varlte>
47
+ </and>
48
+ </or>
49
+ </conditionvar>
50
+ <setvar action="Set" varname="SCORE">100</setvar>
51
+ <displayfeedback feedbacktype="Response" linkrefid="1002_fb"/>
52
+ </respcondition>
53
+ <respcondition continue="No">
54
+ <conditionvar>
55
+ <or>
56
+ <varequal respident="response1">77.0</varequal>
57
+ <and>
58
+ <vargte respident="response1">70.0</vargte>
59
+ <varlte respident="response1">84.0</varlte>
60
+ </and>
61
+ </or>
62
+ </conditionvar>
63
+ <setvar action="Set" varname="SCORE">100</setvar>
64
+ <displayfeedback feedbacktype="Response" linkrefid="1003_fb"/>
65
+ </respcondition>
66
+ <respcondition continue="No">
67
+ <conditionvar>
68
+ <vargte respident="response1">3.9</vargte>
69
+ <varlte respident="response1">4.1</varlte>
70
+ </conditionvar>
71
+ <setvar action="Set" varname="SCORE">100</setvar>
72
+ <displayfeedback feedbacktype="Response" linkrefid="1004_fb"/>
73
+ </respcondition>
74
+ </resprocessing>
75
+ <itemfeedback ident="1001_fb">
76
+ <flow_mat>
77
+ <material>
78
+ <mattext texttype="text/html">&lt;p&gt;Exact answer comment&lt;/p&gt;</mattext>
79
+ </material>
80
+ </flow_mat>
81
+ </itemfeedback>
82
+ <itemfeedback ident="1002_fb">
83
+ <flow_mat>
84
+ <material>
85
+ <mattext texttype="text/html">&lt;p&gt;Precision answer comment&lt;/p&gt;</mattext>
86
+ </material>
87
+ </flow_mat>
88
+ </itemfeedback>
89
+ <itemfeedback ident="1003_fb">
90
+ <flow_mat>
91
+ <material>
92
+ <mattext texttype="text/html">&lt;p&gt;Margin of error answer comment&lt;/p&gt;</mattext>
93
+ </material>
94
+ </flow_mat>
95
+ </itemfeedback>
96
+ <itemfeedback ident="1004_fb">
97
+ <flow_mat>
98
+ <material>
99
+ <mattext texttype="text/html">&lt;p&gt;Range answer comment&lt;/p&gt;</mattext>
100
+ </material>
101
+ </flow_mat>
102
+ </itemfeedback>
103
+ <itemfeedback ident="correct_fb">
104
+ <flow_mat>
105
+ <material>
106
+ <mattext texttype="text/html">&lt;p&gt;General Correct Feedback&lt;/p&gt;</mattext>
107
+ </material>
108
+ </flow_mat>
109
+ </itemfeedback>
110
+ <itemfeedback ident="general_fb">
111
+ <flow_mat>
112
+ <material>
113
+ <mattext texttype="text/html">&lt;p&gt;General Feedback&lt;/p&gt;</mattext>
114
+ </material>
115
+ </flow_mat>
116
+ </itemfeedback>
117
+ </item>
118
+ <item ident="ia63b6a115fa68a555398a58626a62f83" title="Question2">
119
+ <presentation>
120
+ <material>
121
+ <mattext texttype="text/html">&lt;div&gt;&lt;p&gt;question 2&lt;/p&gt;&lt;/div&gt;</mattext>
122
+ </material>
123
+ <response_str ident="response1" rcardinality="Single">
124
+ <render_fib fibtype="Decimal">
125
+ <response_label ident="answer1"/>
126
+ </render_fib>
127
+ </response_str>
128
+ </presentation>
129
+ <resprocessing>
130
+ <outcomes>
131
+ <decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
132
+ </outcomes>
133
+ <respcondition continue="No">
134
+ <conditionvar>
135
+ <or>
136
+ <varequal respident="response1">10.0</varequal>
137
+ <and>
138
+ <vargte respident="response1">10.0</vargte>
139
+ <varlte respident="response1">10.0</varlte>
140
+ </and>
141
+ </or>
142
+ </conditionvar>
143
+ <setvar action="Set" varname="SCORE">100</setvar>
144
+ <displayfeedback feedbacktype="Response" linkrefid="2001_fb"/>
145
+ </respcondition>
146
+ <respcondition continue="No">
147
+ <conditionvar>
148
+ <or>
149
+ <varequal respident="response1">20.0</varequal>
150
+ <and>
151
+ <vargte respident="response1">20.0</vargte>
152
+ <varlte respident="response1">20.0</varlte>
153
+ </and>
154
+ </or>
155
+ </conditionvar>
156
+ <setvar action="Set" varname="SCORE">100</setvar>
157
+ </respcondition>
158
+ <respcondition continue="No">
159
+ <conditionvar>
160
+ <or>
161
+ <varequal respident="response1">30.0</varequal>
162
+ <and>
163
+ <vargte respident="response1">30.0</vargte>
164
+ <varlte respident="response1">30.0</varlte>
165
+ </and>
166
+ </or>
167
+ </conditionvar>
168
+ <setvar action="Set" varname="SCORE">100</setvar>
169
+ <displayfeedback feedbacktype="Response" linkrefid="2003_fb"/>
170
+ </respcondition>
171
+ </resprocessing>
172
+ <itemfeedback ident="2001_fb">
173
+ <flow_mat>
174
+ <material>
175
+ <mattext texttype="text/html">&lt;p&gt;First answer comment&lt;/p&gt;</mattext>
176
+ </material>
177
+ </flow_mat>
178
+ </itemfeedback>
179
+ <itemfeedback ident="2003_fb">
180
+ <flow_mat>
181
+ <material>
182
+ <mattext texttype="text/html">&lt;p&gt;Third answer comment&lt;/p&gt;</mattext>
183
+ </material>
184
+ </flow_mat>
185
+ </itemfeedback>
186
+ </item>
187
+ </section>
188
+ </assessment>
189
+ </questestinterop>
@@ -135,6 +135,26 @@ describe Qti::V1::Models::AssessmentItem do
135
135
  end
136
136
  end
137
137
 
138
+ describe '#case_sensitive' do
139
+ let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
140
+ let(:assessment_item_refs) { test_object.assessment_items }
141
+ let(:loaded_class) { described_class.new(assessment_item_refs) }
142
+
143
+ context 'when it does not contain case_sensitive metadata' do
144
+ let(:file_path) { File.join('spec', 'fixtures', 'items_1.2', 'nq_multiple_fib_scoring_algorithms.xml') }
145
+ it 'returns nil' do
146
+ expect(loaded_class.case_sensitive).to be_nil
147
+ end
148
+ end
149
+
150
+ context 'when it contains case_sensitive metadata' do
151
+ let(:file_path) { File.join('spec', 'fixtures', 'items_1.2', 'nq_multiple_fib_case_sensitive.xml') }
152
+ it 'returns the case_sensitive value' do
153
+ expect(loaded_class.case_sensitive).to eq 'true'
154
+ end
155
+ end
156
+ end
157
+
138
158
  describe '#scoring_data_structs' do
139
159
  it 'grabs the rcardinality and scoring data value' do
140
160
  struct = loaded_class.send(:scoring_data_structs)
@@ -140,4 +140,62 @@ describe Qti::V1::Models::Interactions::NumericInteraction do
140
140
  end
141
141
  end
142
142
  end
143
+
144
+ context 'answer feedback' do
145
+ let(:xml_file_name) { 'numeric_answer_feedback.xml' }
146
+
147
+ context 'a question with a comment on every answer type' do
148
+ let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
149
+
150
+ it 'returns a comment for the exact, precision, margin of error and range answers' do
151
+ expect(loaded_class.answer_feedback).to eq(
152
+ [
153
+ { response_index: 0, texttype: 'text/html', feedback: '<p>Exact answer comment</p>' },
154
+ { response_index: 1, texttype: 'text/html', feedback: '<p>Precision answer comment</p>' },
155
+ { response_index: 2, texttype: 'text/html', feedback: '<p>Margin of error answer comment</p>' },
156
+ { response_index: 3, texttype: 'text/html', feedback: '<p>Range answer comment</p>' }
157
+ ]
158
+ )
159
+ end
160
+
161
+ it 'aligns every response_index with the matching scoring_data_struct' do
162
+ structs = loaded_class.scoring_data_structs
163
+ expect(structs.map(&:type)).to eq(
164
+ %w[exactResponse preciseResponse marginOfError withinARange]
165
+ )
166
+ expect(loaded_class.answer_feedback.map { |fb| structs[fb[:response_index]].type }).to eq(
167
+ %w[exactResponse preciseResponse marginOfError withinARange]
168
+ )
169
+ end
170
+
171
+ it 'ignores the item level feedback' do
172
+ expect(loaded_class.answer_feedback.map { |fb| fb[:feedback] }).not_to include(
173
+ '<p>General Correct Feedback</p>', '<p>General Feedback</p>'
174
+ )
175
+ end
176
+ end
177
+
178
+ context 'a question where only some answers have a comment' do
179
+ let(:loaded_class) { described_class.new(assessment_item_refs[1], test_object) }
180
+
181
+ it 'keeps the index of the commented answers aligned with scoring_data_structs' do
182
+ expect(loaded_class.answer_feedback).to eq(
183
+ [
184
+ { response_index: 0, texttype: 'text/html', feedback: '<p>First answer comment</p>' },
185
+ { response_index: 2, texttype: 'text/html', feedback: '<p>Third answer comment</p>' }
186
+ ]
187
+ )
188
+ expect(loaded_class.scoring_data_structs.map(&:value)).to eq(%w[10.0 20.0 30.0])
189
+ end
190
+ end
191
+ end
192
+
193
+ context 'without answer feedback' do
194
+ let(:xml_file_name) { 'numeric_exact_match.xml' }
195
+ let(:loaded_class) { described_class.new(assessment_item_refs[1], test_object) }
196
+
197
+ it 'returns nil' do
198
+ expect(loaded_class.answer_feedback).to be_nil
199
+ end
200
+ end
143
201
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qti
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.28.0
4
+ version: 2.30.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adrian Diaz
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2025-05-12 00:00:00.000000000 Z
15
+ date: 2026-09-07 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: actionview
@@ -410,7 +410,9 @@ files:
410
410
  - spec/fixtures/items_1.2/multiple_answer_canvas.xml
411
411
  - spec/fixtures/items_1.2/multiple_choice.xml
412
412
  - spec/fixtures/items_1.2/nq_multiple_fib_answer_types.xml
413
+ - spec/fixtures/items_1.2/nq_multiple_fib_case_sensitive.xml
413
414
  - spec/fixtures/items_1.2/nq_multiple_fib_scoring_algorithms.xml
415
+ - spec/fixtures/items_1.2/numeric_answer_feedback.xml
414
416
  - spec/fixtures/items_1.2/numeric_exact_match.xml
415
417
  - spec/fixtures/items_1.2/numeric_margin_error.xml
416
418
  - spec/fixtures/items_1.2/numeric_margin_error_percent.xml
@@ -743,7 +745,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
743
745
  - !ruby/object:Gem::Version
744
746
  version: '0'
745
747
  requirements: []
746
- rubygems_version: 3.4.10
748
+ rubygems_version: 3.5.22
747
749
  signing_key:
748
750
  specification_version: 4
749
751
  summary: QTI 1.2 and 2.1 import and export models
@@ -794,7 +796,9 @@ test_files:
794
796
  - spec/fixtures/items_1.2/multiple_answer_canvas.xml
795
797
  - spec/fixtures/items_1.2/multiple_choice.xml
796
798
  - spec/fixtures/items_1.2/nq_multiple_fib_answer_types.xml
799
+ - spec/fixtures/items_1.2/nq_multiple_fib_case_sensitive.xml
797
800
  - spec/fixtures/items_1.2/nq_multiple_fib_scoring_algorithms.xml
801
+ - spec/fixtures/items_1.2/numeric_answer_feedback.xml
798
802
  - spec/fixtures/items_1.2/numeric_exact_match.xml
799
803
  - spec/fixtures/items_1.2/numeric_margin_error.xml
800
804
  - spec/fixtures/items_1.2/numeric_margin_error_percent.xml