qti 2.16.0 → 2.18.1
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 +4 -4
- data/lib/qti/v1/models/assessment_item.rb +21 -0
- data/lib/qti/v1/models/interactions/base_interaction.rb +10 -0
- data/lib/qti/v1/models/interactions/categorization_interaction.rb +81 -0
- data/lib/qti/v1/models/interactions.rb +2 -1
- data/lib/qti/version.rb +1 -1
- data/lib/qti.rb +1 -0
- data/spec/fixtures/items_1.2/categorization.xml +133 -0
- data/spec/fixtures/items_1.2/true_false.xml +1 -1
- data/spec/fixtures/items_1.2/true_false_with_calculator.xml +90 -0
- data/spec/lib/qti/v1/models/assessment_item_spec.rb +20 -0
- data/spec/lib/qti/v1/models/interactions/categorization_interaction_spec.rb +62 -0
- data/spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb +14 -0
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 336700103b4d3c146a3a14e388d0cc03b568aa7561401ffabede5cab0881559d
|
|
4
|
+
data.tar.gz: 29a3213732a5377ba14d133c06a5e545c3f16c25e1e19200d9f4dd98e1b98792
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e31d581b78da6e468e3a8c5d188310585981b42c2a581f66d9938861c2fcdc701f86d8cbc99c13f3eaf6977e191237deb9904d50bd83159e6b780ffd89005846
|
|
7
|
+
data.tar.gz: 3ad4b4496777d9df2ef092ae2a9c9cbd7d19808c4939bbfdd63fdc1710faa85aeee2296c2209c8642fd15d9bf9ae417f5618f4858e13e4296075aaac65631c35
|
|
@@ -84,6 +84,27 @@ module Qti
|
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
def calculator_type
|
|
88
|
+
@calculator_type ||= begin
|
|
89
|
+
if calculator_type_metadata?
|
|
90
|
+
calculator_type_metadata_label = qti_metadata_children.children.find do |node|
|
|
91
|
+
node.text == 'calculator_type'
|
|
92
|
+
end
|
|
93
|
+
calculator_type_metadata_label.next.text
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def calculator_type_metadata?
|
|
99
|
+
if @doc.at_xpath('.//xmlns:qtimetadata').present?
|
|
100
|
+
qti_metadata_children.children.find do |node|
|
|
101
|
+
node.text == 'calculator_type'
|
|
102
|
+
end.present?
|
|
103
|
+
else
|
|
104
|
+
false
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
87
108
|
def decvar_maxvalue
|
|
88
109
|
@doc.at_xpath('.//xmlns:decvar/@maxvalue')&.value&.to_i ||
|
|
89
110
|
@doc.at_xpath('.//xmlns:decvar/@defaultval')&.value&.to_i || 0
|
|
@@ -40,6 +40,16 @@ module Qti
|
|
|
40
40
|
@node.at_xpath('.//xmlns:render_choice/@shuffle')&.value.try(:downcase) == 'yes'
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
+
def locked_choices
|
|
44
|
+
return [] unless shuffled?
|
|
45
|
+
|
|
46
|
+
@node.xpath('.//xmlns:response_label').filter_map.with_index do |answer_node, index|
|
|
47
|
+
is_locked = answer_node.attributes['lock']&.value&.downcase == 'yes'
|
|
48
|
+
|
|
49
|
+
is_locked ? index : nil
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
43
53
|
def scoring_data_structs
|
|
44
54
|
raise NotImplementedError
|
|
45
55
|
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module Qti
|
|
2
|
+
module V1
|
|
3
|
+
module Models
|
|
4
|
+
module Interactions
|
|
5
|
+
class CategorizationInteraction < BaseInteraction
|
|
6
|
+
def self.matches(node, parent)
|
|
7
|
+
return false if canvas_multiple_fib?(node)
|
|
8
|
+
matches = node.xpath('.//xmlns:response_lid')
|
|
9
|
+
return false if matches.count <= 1
|
|
10
|
+
rcardinality = matches.first.attributes['rcardinality']&.value || 'Single'
|
|
11
|
+
return false if rcardinality != 'Multiple'
|
|
12
|
+
new(node, parent)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def item_body
|
|
16
|
+
@item_body ||= begin
|
|
17
|
+
node = @node.dup
|
|
18
|
+
presentation = node.at_xpath('.//xmlns:presentation')
|
|
19
|
+
mattext = presentation.at_xpath('.//xmlns:mattext')
|
|
20
|
+
inner_content = return_inner_content!(mattext)
|
|
21
|
+
sanitize_content!(inner_content)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def categories
|
|
26
|
+
node.xpath('.//xmlns:response_lid').map do |lid_node|
|
|
27
|
+
mattext = lid_node.at_xpath('.//xmlns:mattext')
|
|
28
|
+
inner_content = return_inner_content!(mattext)
|
|
29
|
+
item_body = sanitize_content!(inner_content)
|
|
30
|
+
category_id = lid_node.attributes['ident'].value
|
|
31
|
+
[category_id, { id: category_id, item_body: item_body }]
|
|
32
|
+
end.to_h
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def distractors
|
|
36
|
+
@distractors ||= choices.reduce({}) do |acc, answer|
|
|
37
|
+
acc.update answer.identifier => answer.item_body
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def scoring_data_structs
|
|
42
|
+
@scoring_data_structs ||= parse_scoring_data
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def parse_scoring_data
|
|
48
|
+
# This preserves the original behavior while not breaking on item feedback
|
|
49
|
+
path = './/xmlns:respcondition/xmlns:setvar/../xmlns:conditionvar/xmlns:varequal'
|
|
50
|
+
raw_scoring_data = node.xpath(path).reduce({}) do |acc, node|
|
|
51
|
+
category_id = node.attributes['respident'].value
|
|
52
|
+
values = (acc[category_id] || []) + [node.text]
|
|
53
|
+
acc.update category_id => values
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
raw_scoring_data.map do |id, values|
|
|
57
|
+
Models::ScoringData.new(values, rcardinality, id: id)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def choices
|
|
62
|
+
@choices ||= answer_nodes.map do |node|
|
|
63
|
+
V1::Models::Choices::LogicalIdentifierChoice.new(node, self)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def answer_nodes
|
|
68
|
+
responses = []
|
|
69
|
+
response_ids = Set.new
|
|
70
|
+
node.xpath('.//xmlns:response_label').each do |answer_node|
|
|
71
|
+
ident = answer_node.attributes['ident'].value
|
|
72
|
+
responses << answer_node unless response_ids.include? ident
|
|
73
|
+
response_ids << ident
|
|
74
|
+
end
|
|
75
|
+
responses
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -17,7 +17,8 @@ module Qti
|
|
|
17
17
|
'calculated_question' => FormulaInteraction,
|
|
18
18
|
'essay_question ' => StringInteraction,
|
|
19
19
|
'file_upload_question' => UploadInteraction,
|
|
20
|
-
'hot_spot_question' => HotSpotInteraction
|
|
20
|
+
'hot_spot_question' => HotSpotInteraction,
|
|
21
|
+
'categorization_question' => CategorizationInteraction
|
|
21
22
|
# "text_only_question" => StimulusNoQuestion
|
|
22
23
|
}.freeze
|
|
23
24
|
|
data/lib/qti/version.rb
CHANGED
data/lib/qti.rb
CHANGED
|
@@ -123,6 +123,7 @@ require 'qti/v1/models/interactions/choice_interaction'
|
|
|
123
123
|
|
|
124
124
|
require 'qti/v1/models/interactions/base_fill_blank_interaction'
|
|
125
125
|
require 'qti/v1/models/interactions/canvas_multiple_dropdown'
|
|
126
|
+
require 'qti/v1/models/interactions/categorization_interaction'
|
|
126
127
|
require 'qti/v1/models/interactions/fill_blank_interaction'
|
|
127
128
|
require 'qti/v1/models/interactions/formula_interaction'
|
|
128
129
|
require 'qti/v1/models/interactions/hot_spot_interaction'
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
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
|
+
<assessment ident="id2b817165c302c0c57416146dc94ce47" title="Quiz with hot-spot question">
|
|
4
|
+
<qtimetadata>
|
|
5
|
+
<qtimetadatafield>
|
|
6
|
+
<fieldlabel>cc_maxattempts</fieldlabel>
|
|
7
|
+
<fieldentry>1</fieldentry>
|
|
8
|
+
</qtimetadatafield>
|
|
9
|
+
</qtimetadata>
|
|
10
|
+
<section ident="root_section">
|
|
11
|
+
<item ident="d74b47a4abeeed159e030bfecbcecea2" title="quiz with categorization question">
|
|
12
|
+
<itemmetadata>
|
|
13
|
+
<qtimetadata>
|
|
14
|
+
<qtimetadatafield>
|
|
15
|
+
<fieldlabel>question_type</fieldlabel>
|
|
16
|
+
<fieldentry>categorization_question</fieldentry>
|
|
17
|
+
</qtimetadatafield>
|
|
18
|
+
<qtimetadatafield>
|
|
19
|
+
<fieldlabel>points_possible</fieldlabel>
|
|
20
|
+
<fieldentry>1.0</fieldentry>
|
|
21
|
+
</qtimetadatafield>
|
|
22
|
+
<qtimetadatafield>
|
|
23
|
+
<fieldlabel>original_answer_ids</fieldlabel>
|
|
24
|
+
<fieldentry/>
|
|
25
|
+
</qtimetadatafield>
|
|
26
|
+
<qtimetadatafield>
|
|
27
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
|
28
|
+
<fieldentry>9f47365e112840d80a79a960b1b0b6a7</fieldentry>
|
|
29
|
+
</qtimetadatafield>
|
|
30
|
+
</qtimetadata>
|
|
31
|
+
</itemmetadata>
|
|
32
|
+
<presentation>
|
|
33
|
+
<material>
|
|
34
|
+
<mattext texttype="text/html"><p>Hello there</p></mattext>
|
|
35
|
+
</material>
|
|
36
|
+
<response_lid ident="df4fb8d7-8033-445a-b8be-171dd9b973ba" rcardinality="Multiple">
|
|
37
|
+
<material>
|
|
38
|
+
<mattext texttype="text/plain">Category_A</mattext>
|
|
39
|
+
</material>
|
|
40
|
+
<render_choice>
|
|
41
|
+
<response_label ident="19e37ce3-3a8b-4e26-ab61-9770e58af00e">
|
|
42
|
+
<material>
|
|
43
|
+
<mattext texttype="text/plain">Distractor2</mattext>
|
|
44
|
+
</material>
|
|
45
|
+
</response_label>
|
|
46
|
+
<response_label ident="3b8dcef8-c8c1-4827-85b0-6e381739adbf">
|
|
47
|
+
<material>
|
|
48
|
+
<mattext texttype="text/plain">B1</mattext>
|
|
49
|
+
</material>
|
|
50
|
+
</response_label>
|
|
51
|
+
<response_label ident="53a97aa7-d55c-402c-a061-f85d837c7c77">
|
|
52
|
+
<material>
|
|
53
|
+
<mattext texttype="text/plain">A2</mattext>
|
|
54
|
+
</material>
|
|
55
|
+
</response_label>
|
|
56
|
+
<response_label ident="5a67c627-cf85-4b70-922a-c7d1b7c720b8">
|
|
57
|
+
<material>
|
|
58
|
+
<mattext texttype="text/plain">B2</mattext>
|
|
59
|
+
</material>
|
|
60
|
+
</response_label>
|
|
61
|
+
<response_label ident="5d78f3f5-28c2-4e71-9c33-70c6b301e017">
|
|
62
|
+
<material>
|
|
63
|
+
<mattext texttype="text/plain">Distractor1</mattext>
|
|
64
|
+
</material>
|
|
65
|
+
</response_label>
|
|
66
|
+
<response_label ident="9432e8cb-1d3e-4d04-89b5-95185b7e557d">
|
|
67
|
+
<material>
|
|
68
|
+
<mattext texttype="text/plain">A1</mattext>
|
|
69
|
+
</material>
|
|
70
|
+
</response_label>
|
|
71
|
+
</render_choice>
|
|
72
|
+
</response_lid>
|
|
73
|
+
<response_lid ident="eb2f823d-b857-4c06-9d5f-998d14ee8d58" rcardinality="Multiple">
|
|
74
|
+
<material>
|
|
75
|
+
<mattext texttype="text/plain">Category_B</mattext>
|
|
76
|
+
</material>
|
|
77
|
+
<render_choice>
|
|
78
|
+
<response_label ident="19e37ce3-3a8b-4e26-ab61-9770e58af00e">
|
|
79
|
+
<material>
|
|
80
|
+
<mattext texttype="text/plain">Distractor2</mattext>
|
|
81
|
+
</material>
|
|
82
|
+
</response_label>
|
|
83
|
+
<response_label ident="3b8dcef8-c8c1-4827-85b0-6e381739adbf">
|
|
84
|
+
<material>
|
|
85
|
+
<mattext texttype="text/plain">B1</mattext>
|
|
86
|
+
</material>
|
|
87
|
+
</response_label>
|
|
88
|
+
<response_label ident="53a97aa7-d55c-402c-a061-f85d837c7c77">
|
|
89
|
+
<material>
|
|
90
|
+
<mattext texttype="text/plain">A2</mattext>
|
|
91
|
+
</material>
|
|
92
|
+
</response_label>
|
|
93
|
+
<response_label ident="5a67c627-cf85-4b70-922a-c7d1b7c720b8">
|
|
94
|
+
<material>
|
|
95
|
+
<mattext texttype="text/plain">B2</mattext>
|
|
96
|
+
</material>
|
|
97
|
+
</response_label>
|
|
98
|
+
<response_label ident="5d78f3f5-28c2-4e71-9c33-70c6b301e017">
|
|
99
|
+
<material>
|
|
100
|
+
<mattext texttype="text/plain">Distractor1</mattext>
|
|
101
|
+
</material>
|
|
102
|
+
</response_label>
|
|
103
|
+
<response_label ident="9432e8cb-1d3e-4d04-89b5-95185b7e557d">
|
|
104
|
+
<material>
|
|
105
|
+
<mattext texttype="text/plain">A1</mattext>
|
|
106
|
+
</material>
|
|
107
|
+
</response_label>
|
|
108
|
+
</render_choice>
|
|
109
|
+
</response_lid>
|
|
110
|
+
</presentation>
|
|
111
|
+
<resprocessing>
|
|
112
|
+
<outcomes>
|
|
113
|
+
<decvar maxvalue="100" minvalue="0" varname="SCORE" vartype="Decimal"/>
|
|
114
|
+
</outcomes>
|
|
115
|
+
<respcondition>
|
|
116
|
+
<conditionvar>
|
|
117
|
+
<varequal respident="df4fb8d7-8033-445a-b8be-171dd9b973ba">9432e8cb-1d3e-4d04-89b5-95185b7e557d</varequal>
|
|
118
|
+
<varequal respident="df4fb8d7-8033-445a-b8be-171dd9b973ba">53a97aa7-d55c-402c-a061-f85d837c7c77</varequal>
|
|
119
|
+
</conditionvar>
|
|
120
|
+
<setvar action="Add" varname="SCORE">50.00</setvar>
|
|
121
|
+
</respcondition>
|
|
122
|
+
<respcondition>
|
|
123
|
+
<conditionvar>
|
|
124
|
+
<varequal respident="eb2f823d-b857-4c06-9d5f-998d14ee8d58">3b8dcef8-c8c1-4827-85b0-6e381739adbf</varequal>
|
|
125
|
+
<varequal respident="eb2f823d-b857-4c06-9d5f-998d14ee8d58">5a67c627-cf85-4b70-922a-c7d1b7c720b8</varequal>
|
|
126
|
+
</conditionvar>
|
|
127
|
+
<setvar action="Add" varname="SCORE">50.00</setvar>
|
|
128
|
+
</respcondition>
|
|
129
|
+
</resprocessing>
|
|
130
|
+
</item>
|
|
131
|
+
</section>
|
|
132
|
+
</assessment>
|
|
133
|
+
</questestinterop>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
</material>
|
|
22
22
|
<response_lid ident="QUE_1004_RL" rcardinality="Single" rtiming="No">
|
|
23
23
|
<render_choice shuffle="Yes">
|
|
24
|
-
<response_label ident="QUE_1005_A1">
|
|
24
|
+
<response_label ident="QUE_1005_A1" lock="Yes">
|
|
25
25
|
<material>
|
|
26
26
|
<mattext texttype="text/html"><![CDATA[True]]></mattext>
|
|
27
27
|
</material>
|
|
@@ -0,0 +1,90 @@
|
|
|
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
|
+
<assessment title="1.2 Import Quiz" ident="A1001">
|
|
4
|
+
<section title="Main" ident="S1002">
|
|
5
|
+
<item title="Grading - specific - 3 pt score" ident="QUE_1003">
|
|
6
|
+
<itemmetadata>
|
|
7
|
+
<qtimetadata>
|
|
8
|
+
<qtimetadatafield>
|
|
9
|
+
<fieldlabel>question_type</fieldlabel>
|
|
10
|
+
<fieldentry>true_false_question</fieldentry>
|
|
11
|
+
</qtimetadatafield>
|
|
12
|
+
<qtimetadatafield>
|
|
13
|
+
<fieldlabel>assessment_question_identifierref</fieldlabel>
|
|
14
|
+
<fieldentry>iff205c7405d3b36bdca9b75b51198932</fieldentry>
|
|
15
|
+
</qtimetadatafield>
|
|
16
|
+
<qtimetadatafield>
|
|
17
|
+
<fieldlabel>calculator_type</fieldlabel>
|
|
18
|
+
<fieldentry>basic</fieldentry>
|
|
19
|
+
</qtimetadatafield>
|
|
20
|
+
</qtimetadata>
|
|
21
|
+
</itemmetadata>
|
|
22
|
+
<presentation>
|
|
23
|
+
<material>
|
|
24
|
+
<mattext texttype="text/html"><![CDATA[If I get a 3, I must have done something wrong. <img data-equation-content="sample equation" script="alert('bad')" align="bottom" alt="image.png" src="org0/images/image.png" border="0"/> <img script="alert('bad')" align="bottom" alt="image.png" src="org0/images/image.png" border="0"/>]]></mattext>
|
|
25
|
+
</material>
|
|
26
|
+
<response_lid ident="QUE_1004_RL" rcardinality="Single" rtiming="No">
|
|
27
|
+
<render_choice shuffle="Yes">
|
|
28
|
+
<response_label ident="QUE_1005_A1">
|
|
29
|
+
<material>
|
|
30
|
+
<mattext texttype="text/html"><![CDATA[True]]></mattext>
|
|
31
|
+
</material>
|
|
32
|
+
</response_label>
|
|
33
|
+
<response_label ident="QUE_1006_A2">
|
|
34
|
+
<material>
|
|
35
|
+
<mattext texttype="text/html"><![CDATA[False]]></mattext>
|
|
36
|
+
</material>
|
|
37
|
+
</response_label>
|
|
38
|
+
</render_choice>
|
|
39
|
+
</response_lid>
|
|
40
|
+
</presentation>
|
|
41
|
+
<resprocessing>
|
|
42
|
+
<outcomes>
|
|
43
|
+
<decvar vartype="Decimal" defaultval="0" varname="que_score"/>
|
|
44
|
+
</outcomes>
|
|
45
|
+
<respcondition>
|
|
46
|
+
<conditionvar>
|
|
47
|
+
<varequal respident="QUE_1004_RL">QUE_1005_A1</varequal>
|
|
48
|
+
</conditionvar>
|
|
49
|
+
<setvar varname="que_score" action="Add">0</setvar>
|
|
50
|
+
</respcondition>
|
|
51
|
+
<respcondition>
|
|
52
|
+
<conditionvar>
|
|
53
|
+
<varequal respident="QUE_1004_RL">QUE_1006_A2</varequal>
|
|
54
|
+
</conditionvar>
|
|
55
|
+
<setvar varname="que_score" action="Set">10.00</setvar>
|
|
56
|
+
<displayfeedback feedbacktype="Response" linkrefid="fb_QUE_1006_A2"/>
|
|
57
|
+
</respcondition>
|
|
58
|
+
</resprocessing>
|
|
59
|
+
<itemfeedback ident="general_fb">
|
|
60
|
+
<flow_mat>
|
|
61
|
+
<material>
|
|
62
|
+
<mattext texttype="text/html"><p>Neutral</p><img script="alert('bad')" alt="image.png" src="org0/images/image.png"/></mattext>
|
|
63
|
+
</material>
|
|
64
|
+
</flow_mat>
|
|
65
|
+
</itemfeedback>
|
|
66
|
+
<itemfeedback ident="correct_fb">
|
|
67
|
+
<flow_mat>
|
|
68
|
+
<material>
|
|
69
|
+
<mattext texttype="text/html"><p>Correct</p><img script="alert('bad')" alt="image.png" src="org0/images/image.png"/></mattext>
|
|
70
|
+
</material>
|
|
71
|
+
</flow_mat>
|
|
72
|
+
</itemfeedback>
|
|
73
|
+
<itemfeedback ident="general_incorrect_fb">
|
|
74
|
+
<flow_mat>
|
|
75
|
+
<material>
|
|
76
|
+
<mattext texttype="text/html"><p>Incorrect</p><img script="alert('bad')" alt="image.png" src="org0/images/image.png"/></mattext>
|
|
77
|
+
</material>
|
|
78
|
+
</flow_mat>
|
|
79
|
+
</itemfeedback>
|
|
80
|
+
<itemfeedback ident="fb_QUE_1006_A2">
|
|
81
|
+
<flow_mat>
|
|
82
|
+
<material>
|
|
83
|
+
<mattext texttype="text/html"><p>Answer was Correct</p><img script="alert('bad')" alt="image.png" src="org0/images/image.png"/></mattext>
|
|
84
|
+
</material>
|
|
85
|
+
</flow_mat>
|
|
86
|
+
</itemfeedback>
|
|
87
|
+
</item>
|
|
88
|
+
</section>
|
|
89
|
+
</assessment>
|
|
90
|
+
</questestinterop>
|
|
@@ -115,6 +115,26 @@ describe Qti::V1::Models::AssessmentItem do
|
|
|
115
115
|
end
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
describe '#calculator_type' do
|
|
119
|
+
let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
|
|
120
|
+
let(:assessment_item_refs) { test_object.assessment_items }
|
|
121
|
+
let(:loaded_class) { described_class.new(assessment_item_refs) }
|
|
122
|
+
|
|
123
|
+
context 'when it does not contain calculator_type metadata' do
|
|
124
|
+
let(:file_path) { File.join('spec', 'fixtures', 'items_1.2', 'true_false.xml') }
|
|
125
|
+
it 'returns nil' do
|
|
126
|
+
expect(loaded_class.calculator_type).to be_nil
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
context 'when it contains calculator_type metadata' do
|
|
131
|
+
let(:file_path) { File.join('spec', 'fixtures', 'items_1.2', 'true_false_with_calculator.xml') }
|
|
132
|
+
it 'returns the calculator_type value' do
|
|
133
|
+
expect(loaded_class.calculator_type).to eq 'basic'
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
118
138
|
describe '#scoring_data_structs' do
|
|
119
139
|
it 'grabs the rcardinality and scoring data value' do
|
|
120
140
|
struct = loaded_class.send(:scoring_data_structs)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
describe Qti::V1::Models::Interactions::CategorizationInteraction do
|
|
2
|
+
let(:xml_file_name) { 'categorization.xml' }
|
|
3
|
+
let(:fixtures_path) { File.join('spec', 'fixtures', 'items_1.2') }
|
|
4
|
+
let(:file_path) { File.join(fixtures_path, xml_file_name) }
|
|
5
|
+
let(:test_object) { Qti::V1::Models::Assessment.from_path!(file_path) }
|
|
6
|
+
let(:assessment_item_refs) { test_object.assessment_items }
|
|
7
|
+
let(:item) { assessment_item_refs.first }
|
|
8
|
+
|
|
9
|
+
describe '.matches' do
|
|
10
|
+
it 'matches the item in file' do
|
|
11
|
+
expect(described_class.matches(item, test_object)).to be_truthy
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe '#item_body' do
|
|
16
|
+
let(:loaded_class) { described_class.new(item, test_object) }
|
|
17
|
+
it 'returns correct item body' do
|
|
18
|
+
expect(loaded_class.item_body).to eq '<p>Hello there</p>'
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '#categories' do
|
|
23
|
+
let(:loaded_class) { described_class.new(item, test_object) }
|
|
24
|
+
it 'returns correct categories' do
|
|
25
|
+
expected_categories =
|
|
26
|
+
{
|
|
27
|
+
'df4fb8d7-8033-445a-b8be-171dd9b973ba' => { id: 'df4fb8d7-8033-445a-b8be-171dd9b973ba',
|
|
28
|
+
item_body: 'Category_A' },
|
|
29
|
+
'eb2f823d-b857-4c06-9d5f-998d14ee8d58' => { id: 'eb2f823d-b857-4c06-9d5f-998d14ee8d58',
|
|
30
|
+
item_body: 'Category_B' }
|
|
31
|
+
}
|
|
32
|
+
expect(loaded_class.categories).to eq(expected_categories)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '#distractors' do
|
|
37
|
+
let(:loaded_class) { described_class.new(item, test_object) }
|
|
38
|
+
it 'returns the correct distractors' do
|
|
39
|
+
expected_distractors =
|
|
40
|
+
{ '19e37ce3-3a8b-4e26-ab61-9770e58af00e' => 'Distractor2',
|
|
41
|
+
'3b8dcef8-c8c1-4827-85b0-6e381739adbf' => 'B1',
|
|
42
|
+
'53a97aa7-d55c-402c-a061-f85d837c7c77' => 'A2',
|
|
43
|
+
'5a67c627-cf85-4b70-922a-c7d1b7c720b8' => 'B2',
|
|
44
|
+
'5d78f3f5-28c2-4e71-9c33-70c6b301e017' => 'Distractor1',
|
|
45
|
+
'9432e8cb-1d3e-4d04-89b5-95185b7e557d' => 'A1' }
|
|
46
|
+
expect(loaded_class.distractors).to eq(expected_distractors)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe '#scoring_data_structs' do
|
|
51
|
+
let(:loaded_class) { described_class.new(item, test_object) }
|
|
52
|
+
it 'returns the correct scoring data structs' do
|
|
53
|
+
scoring_data_ids = %w[df4fb8d7-8033-445a-b8be-171dd9b973ba eb2f823d-b857-4c06-9d5f-998d14ee8d58]
|
|
54
|
+
scoring_data_values = [
|
|
55
|
+
%w[9432e8cb-1d3e-4d04-89b5-95185b7e557d 53a97aa7-d55c-402c-a061-f85d837c7c77],
|
|
56
|
+
%w[3b8dcef8-c8c1-4827-85b0-6e381739adbf 5a67c627-cf85-4b70-922a-c7d1b7c720b8]
|
|
57
|
+
]
|
|
58
|
+
expect(loaded_class.scoring_data_structs.map(&:id)).to eq(scoring_data_ids)
|
|
59
|
+
expect(loaded_class.scoring_data_structs.map(&:values)).to eq(scoring_data_values)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -10,6 +10,12 @@ describe Qti::V1::Models::Interactions::ChoiceInteraction do
|
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
+
shared_examples_for 'locked_choices' do
|
|
14
|
+
it 'returns locked choices setting' do
|
|
15
|
+
expect(loaded_class.locked_choices).to eq locked_choices_value
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
13
19
|
shared_examples_for 'answers' do
|
|
14
20
|
it 'returns the answers' do
|
|
15
21
|
expect(loaded_class.answers.count).to eq answer_choices_count
|
|
@@ -27,10 +33,12 @@ describe Qti::V1::Models::Interactions::ChoiceInteraction do
|
|
|
27
33
|
context 'multiple_choice.xml' do
|
|
28
34
|
let(:file_path) { File.join(fixtures_path, 'multiple_choice.xml') }
|
|
29
35
|
let(:shuffle_value) { false }
|
|
36
|
+
let(:locked_choices_value) { [] }
|
|
30
37
|
let(:answer_choices_count) { 5 }
|
|
31
38
|
let(:meta_type) { nil }
|
|
32
39
|
|
|
33
40
|
include_examples 'shuffled?'
|
|
41
|
+
include_examples 'locked_choices'
|
|
34
42
|
include_examples 'answers'
|
|
35
43
|
include_examples 'meta_type'
|
|
36
44
|
end
|
|
@@ -38,10 +46,12 @@ describe Qti::V1::Models::Interactions::ChoiceInteraction do
|
|
|
38
46
|
context 'true_false.xml' do
|
|
39
47
|
let(:file_path) { File.join(fixtures_path, 'true_false.xml') }
|
|
40
48
|
let(:shuffle_value) { true }
|
|
49
|
+
let(:locked_choices_value) { [0] }
|
|
41
50
|
let(:answer_choices_count) { 2 }
|
|
42
51
|
let(:meta_type) { 'true_false_question' }
|
|
43
52
|
|
|
44
53
|
include_examples 'shuffled?'
|
|
54
|
+
include_examples 'locked_choices'
|
|
45
55
|
include_examples 'answers'
|
|
46
56
|
include_examples 'meta_type'
|
|
47
57
|
end
|
|
@@ -49,17 +59,21 @@ describe Qti::V1::Models::Interactions::ChoiceInteraction do
|
|
|
49
59
|
context 'multiple_answer.xml' do
|
|
50
60
|
let(:file_path) { File.join(fixtures_path, 'multiple_answer.xml') }
|
|
51
61
|
let(:shuffle_value) { false }
|
|
62
|
+
let(:locked_choices_value) { [] }
|
|
52
63
|
|
|
53
64
|
include_examples 'shuffled?'
|
|
65
|
+
include_examples 'locked_choices'
|
|
54
66
|
end
|
|
55
67
|
|
|
56
68
|
context 'multiple_answer_canvas.xml' do
|
|
57
69
|
let(:file_path) { File.join(fixtures_path, 'multiple_answer_canvas.xml') }
|
|
58
70
|
let(:shuffle_value) { false }
|
|
71
|
+
let(:locked_choices_value) { [] }
|
|
59
72
|
let(:answer_choices_count) { 4 }
|
|
60
73
|
let(:meta_type) { 'multiple_answers_question' }
|
|
61
74
|
|
|
62
75
|
include_examples 'shuffled?'
|
|
76
|
+
include_examples 'locked_choices'
|
|
63
77
|
include_examples 'meta_type'
|
|
64
78
|
end
|
|
65
79
|
|
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.
|
|
4
|
+
version: 2.18.1
|
|
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: 2023-07-
|
|
15
|
+
date: 2023-07-21 00:00:00.000000000 Z
|
|
16
16
|
dependencies:
|
|
17
17
|
- !ruby/object:Gem::Dependency
|
|
18
18
|
name: actionview
|
|
@@ -332,6 +332,7 @@ files:
|
|
|
332
332
|
- lib/qti/v1/models/interactions/base_fill_blank_interaction.rb
|
|
333
333
|
- lib/qti/v1/models/interactions/base_interaction.rb
|
|
334
334
|
- lib/qti/v1/models/interactions/canvas_multiple_dropdown.rb
|
|
335
|
+
- lib/qti/v1/models/interactions/categorization_interaction.rb
|
|
335
336
|
- lib/qti/v1/models/interactions/choice_interaction.rb
|
|
336
337
|
- lib/qti/v1/models/interactions/fill_blank_interaction.rb
|
|
337
338
|
- lib/qti/v1/models/interactions/formula_interaction.rb
|
|
@@ -397,6 +398,7 @@ files:
|
|
|
397
398
|
- spec/fixtures/items_1.2/canvas_multiple_fib.xml
|
|
398
399
|
- spec/fixtures/items_1.2/canvas_multiple_fib_as_single.xml
|
|
399
400
|
- spec/fixtures/items_1.2/canvas_multiple_fib_extra_brackets.xml
|
|
401
|
+
- spec/fixtures/items_1.2/categorization.xml
|
|
400
402
|
- spec/fixtures/items_1.2/choice.xml
|
|
401
403
|
- spec/fixtures/items_1.2/essay.xml
|
|
402
404
|
- spec/fixtures/items_1.2/fib.xml
|
|
@@ -426,6 +428,7 @@ files:
|
|
|
426
428
|
- spec/fixtures/items_1.2/stimulus_with_child_item.xml
|
|
427
429
|
- spec/fixtures/items_1.2/text.no.question.xml
|
|
428
430
|
- spec/fixtures/items_1.2/true_false.xml
|
|
431
|
+
- spec/fixtures/items_1.2/true_false_with_calculator.xml
|
|
429
432
|
- spec/fixtures/items_1.2/upload.xml
|
|
430
433
|
- spec/fixtures/items_2.1/Example02-feedbackInline.xml
|
|
431
434
|
- spec/fixtures/items_2.1/categorization.xml
|
|
@@ -678,6 +681,7 @@ files:
|
|
|
678
681
|
- spec/lib/qti/v1/models/interactions/base_fill_blank_interaction_spec.rb
|
|
679
682
|
- spec/lib/qti/v1/models/interactions/base_interaction_spec.rb
|
|
680
683
|
- spec/lib/qti/v1/models/interactions/canvas_multiple_dropdown_spec.rb
|
|
684
|
+
- spec/lib/qti/v1/models/interactions/categorization_interaction_spec.rb
|
|
681
685
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
|
682
686
|
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
|
683
687
|
- spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb
|
|
@@ -762,6 +766,7 @@ test_files:
|
|
|
762
766
|
- spec/fixtures/items_1.2/canvas_multiple_fib.xml
|
|
763
767
|
- spec/fixtures/items_1.2/canvas_multiple_fib_as_single.xml
|
|
764
768
|
- spec/fixtures/items_1.2/canvas_multiple_fib_extra_brackets.xml
|
|
769
|
+
- spec/fixtures/items_1.2/categorization.xml
|
|
765
770
|
- spec/fixtures/items_1.2/choice.xml
|
|
766
771
|
- spec/fixtures/items_1.2/essay.xml
|
|
767
772
|
- spec/fixtures/items_1.2/fib.xml
|
|
@@ -791,6 +796,7 @@ test_files:
|
|
|
791
796
|
- spec/fixtures/items_1.2/stimulus_with_child_item.xml
|
|
792
797
|
- spec/fixtures/items_1.2/text.no.question.xml
|
|
793
798
|
- spec/fixtures/items_1.2/true_false.xml
|
|
799
|
+
- spec/fixtures/items_1.2/true_false_with_calculator.xml
|
|
794
800
|
- spec/fixtures/items_1.2/upload.xml
|
|
795
801
|
- spec/fixtures/items_2.1/Example02-feedbackInline.xml
|
|
796
802
|
- spec/fixtures/items_2.1/categorization.xml
|
|
@@ -1043,6 +1049,7 @@ test_files:
|
|
|
1043
1049
|
- spec/lib/qti/v1/models/interactions/base_fill_blank_interaction_spec.rb
|
|
1044
1050
|
- spec/lib/qti/v1/models/interactions/base_interaction_spec.rb
|
|
1045
1051
|
- spec/lib/qti/v1/models/interactions/canvas_multiple_dropdown_spec.rb
|
|
1052
|
+
- spec/lib/qti/v1/models/interactions/categorization_interaction_spec.rb
|
|
1046
1053
|
- spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
|
|
1047
1054
|
- spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
|
|
1048
1055
|
- spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb
|