qti 2.15.4 → 2.17.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: f4084fe51b2f6fe08be8575473463acf9654f015d2e314ac7dc5b0cc66bbc7a0
4
- data.tar.gz: 7aef361ec589ca5656e4bb6c0850593e3a0014e1b5e59c06a3f84cc762ca4b49
3
+ metadata.gz: 8ecae7fca00b12644bc2942b43f7fe47c6b959823c6b4b3a92e70193529b064f
4
+ data.tar.gz: b9c35c2873033a84e0b673b58e4859d434de0ea0052a4891b38e448de034759d
5
5
  SHA512:
6
- metadata.gz: fccaad1a37691535248d7f2f6c8f587c9cbf319f4db2abd918f682e4a78a9a8351ab3b42e75a2e78f38557babbd437de049bcfb8c4d6b8aea8ed3a407a6355ab
7
- data.tar.gz: 31746c6c8de63f0d854a329b9932245c36b19fb32dbb0e1183d8ff20f04c2ca2f93bf4fd63192083c8cbdd67e749bc46c9cc07fc4b50809ba0d4015f56bf8a5e
6
+ metadata.gz: c7ec25c08693f1b467121f8d528859c99ff58d57ad9eb55d44fb31871210a6d04f0184517db425ce62509ab3ea00700ea6203e1d4ae3323de4b4eaad3577f0a1
7
+ data.tar.gz: aa5a807baa86a4554c52a83c0d2c16c7421c82ef1bb5a4c680cfc1e2f4cb9c5bbcea79936d1bc02984fb0bb74d6c4b6d44a8d1bdc0b8d7f4272f49fc27249018
@@ -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
@@ -0,0 +1,71 @@
1
+ module Qti
2
+ module V1
3
+ module Models
4
+ module Interactions
5
+ class HotSpotInteraction < BaseInteraction
6
+ def self.matches(node, parent)
7
+ presentation = node.at_xpath('.//xmlns:presentation')
8
+ return false unless presentation
9
+ xy_responses = presentation.xpath('.//xmlns:response_xy')
10
+ return false unless xy_responses.count.positive?
11
+ new(node, parent)
12
+ end
13
+
14
+ def item_body
15
+ @item_body ||= begin
16
+ node = @node.dup
17
+ presentation = node.at_xpath('.//xmlns:presentation')
18
+ mattext = presentation.at_xpath('.//xmlns:mattext')
19
+ inner_content = return_inner_content!(mattext)
20
+ sanitize_content!(inner_content)
21
+ end
22
+ end
23
+
24
+ def image_url
25
+ @image_url ||= begin
26
+ node = @node.dup
27
+ presentation = node.at_xpath('.//xmlns:presentation')
28
+ matimage = presentation.at_xpath('.//xmlns:matimage')
29
+ matimage&.attributes&.[]('uri')&.value
30
+ end
31
+ end
32
+
33
+ def shape_type
34
+ @shape_type ||= response_label&.attributes&.[]('rarea')&.value
35
+ end
36
+
37
+ def coordinates
38
+ @coordinates ||= begin
39
+ raw_coordinates_array = raw_coordinates.split(',')
40
+ return [] unless (raw_coordinates_array.length % 2).zero?
41
+
42
+ raw_coordinates_array.each_slice(2).map do |point|
43
+ { x: point[0].to_f, y: point[1].to_f }
44
+ end
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def response_label
51
+ @response_label ||= begin
52
+ node = @node.dup
53
+ presentation = node.at_xpath('.//xmlns:presentation')
54
+ presentation.at_xpath('.//xmlns:response_label')
55
+ end
56
+ end
57
+
58
+ def raw_coordinates
59
+ @raw_coordinates ||= response_label&.text || ''
60
+ end
61
+
62
+ def coordinate_hash(coordinate_node)
63
+ %w[x y].map do |axis|
64
+ [axis.to_sym, coordinate_node&.attributes&.[](axis)&.value&.to_f]
65
+ end.to_h
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -16,7 +16,9 @@ module Qti
16
16
  'numerical_question' => NumericInteraction,
17
17
  'calculated_question' => FormulaInteraction,
18
18
  'essay_question ' => StringInteraction,
19
- 'file_upload_question' => UploadInteraction
19
+ 'file_upload_question' => UploadInteraction,
20
+ 'hot_spot_question' => HotSpotInteraction,
21
+ 'categorization_question' => CategorizationInteraction
20
22
  # "text_only_question" => StimulusNoQuestion
21
23
  }.freeze
22
24
 
data/lib/qti/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '2.15.4'.freeze
2
+ VERSION = '2.17.0'.freeze
3
3
  end
data/lib/qti.rb CHANGED
@@ -123,8 +123,10 @@ 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'
129
+ require 'qti/v1/models/interactions/hot_spot_interaction'
128
130
  require 'qti/v1/models/interactions/match_interaction'
129
131
  require 'qti/v1/models/interactions/numeric_interaction'
130
132
  require 'qti/v1/models/interactions/ordering_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">&lt;p&gt;Hello there&lt;/p&gt;</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>
@@ -0,0 +1,124 @@
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="g515255148f5a3cae1832584071aa8528" title="this is a hot-spot question">
12
+ <itemmetadata>
13
+ <qtimetadata>
14
+ <qtimetadatafield>
15
+ <fieldlabel>question_type</fieldlabel>
16
+ <fieldentry>hot_spot_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>gd6ff15355f3dd3f532816fa268230130</fieldentry>
29
+ </qtimetadatafield>
30
+ </qtimetadata>
31
+ </itemmetadata>
32
+ <presentation>
33
+ <flow>
34
+ <response_xy ident="response1" rcardinality="Single" rtiming="No">
35
+ <material>
36
+ <mattext texttype="text/html">&lt;p&gt;point something on the image&lt;/p&gt;</mattext>
37
+ </material>
38
+ <render_hotspot>
39
+ <material>
40
+ <matimage uri="$IMS-CC-FILEBASE$/Uploaded Media/someuuid"/>
41
+ </material>
42
+ <response_label ident="response1" rarea="square">0.372,0.1376,0.616,0.4256</response_label>
43
+ </render_hotspot>
44
+ </response_xy>
45
+ </flow>
46
+ </presentation>
47
+ </item>
48
+ <item ident="g515255148f5a3cae1832584071aa8529" title="hot-spot with invalid coordinates">
49
+ <itemmetadata>
50
+ <qtimetadata>
51
+ <qtimetadatafield>
52
+ <fieldlabel>question_type</fieldlabel>
53
+ <fieldentry>hot_spot_question</fieldentry>
54
+ </qtimetadatafield>
55
+ <qtimetadatafield>
56
+ <fieldlabel>points_possible</fieldlabel>
57
+ <fieldentry>1.0</fieldentry>
58
+ </qtimetadatafield>
59
+ <qtimetadatafield>
60
+ <fieldlabel>original_answer_ids</fieldlabel>
61
+ <fieldentry/>
62
+ </qtimetadatafield>
63
+ <qtimetadatafield>
64
+ <fieldlabel>assessment_question_identifierref</fieldlabel>
65
+ <fieldentry>gd6ff15355f3dd3f532816fa268230130</fieldentry>
66
+ </qtimetadatafield>
67
+ </qtimetadata>
68
+ </itemmetadata>
69
+ <presentation>
70
+ <flow>
71
+ <response_xy ident="response1" rcardinality="Single" rtiming="No">
72
+ <material>
73
+ <mattext texttype="text/html">&lt;p&gt;point something on the image&lt;/p&gt;</mattext>
74
+ </material>
75
+ <render_hotspot>
76
+ <material>
77
+ <matimage uri="$IMS-CC-FILEBASE$/Uploaded Media/someuuid"/>
78
+ </material>
79
+ <response_label ident="response1" rarea="square">0.372</response_label>
80
+ </render_hotspot>
81
+ </response_xy>
82
+ </flow>
83
+ </presentation>
84
+ </item>
85
+ <item ident="g515255148f5a3cae1832584071aa8529" title="hot-spot without coordinates">
86
+ <itemmetadata>
87
+ <qtimetadata>
88
+ <qtimetadatafield>
89
+ <fieldlabel>question_type</fieldlabel>
90
+ <fieldentry>hot_spot_question</fieldentry>
91
+ </qtimetadatafield>
92
+ <qtimetadatafield>
93
+ <fieldlabel>points_possible</fieldlabel>
94
+ <fieldentry>1.0</fieldentry>
95
+ </qtimetadatafield>
96
+ <qtimetadatafield>
97
+ <fieldlabel>original_answer_ids</fieldlabel>
98
+ <fieldentry/>
99
+ </qtimetadatafield>
100
+ <qtimetadatafield>
101
+ <fieldlabel>assessment_question_identifierref</fieldlabel>
102
+ <fieldentry>gd6ff15355f3dd3f532816fa268230130</fieldentry>
103
+ </qtimetadatafield>
104
+ </qtimetadata>
105
+ </itemmetadata>
106
+ <presentation>
107
+ <flow>
108
+ <response_xy ident="response1" rcardinality="Single" rtiming="No">
109
+ <material>
110
+ <mattext texttype="text/html">&lt;p&gt;point something on the image&lt;/p&gt;</mattext>
111
+ </material>
112
+ <render_hotspot>
113
+ <material>
114
+ <matimage uri="$IMS-CC-FILEBASE$/Uploaded Media/someuuid"/>
115
+ </material>
116
+ <response_label ident="response1" rarea="square"></response_label>
117
+ </render_hotspot>
118
+ </response_xy>
119
+ </flow>
120
+ </presentation>
121
+ </item>
122
+ </section>
123
+ </assessment>
124
+ </questestinterop>
@@ -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
@@ -0,0 +1,57 @@
1
+ describe Qti::V1::Models::Interactions::HotSpotInteraction do
2
+ let(:xml_file_name) { 'hot_spot.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
+
8
+ describe '.matches' do
9
+ it 'matches the item in file' do
10
+ expect(described_class.matches(test_object.assessment_items, test_object)).to be_truthy
11
+ end
12
+ end
13
+
14
+ describe '#item_body' do
15
+ let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
16
+ it 'returns correct item body' do
17
+ expect(loaded_class.item_body).to eq '<p>point something on the image</p>'
18
+ end
19
+ end
20
+
21
+ describe '#image_url' do
22
+ let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
23
+ it 'returns correct image url' do
24
+ expect(loaded_class.image_url).to eq '$IMS-CC-FILEBASE$/Uploaded Media/someuuid'
25
+ end
26
+ end
27
+
28
+ describe '#shape_type' do
29
+ let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
30
+ it 'returns correct shape type' do
31
+ expect(loaded_class.shape_type).to eq 'square'
32
+ end
33
+ end
34
+
35
+ describe '#coordinates' do
36
+ let(:loaded_class) { described_class.new(assessment_item_refs.first, test_object) }
37
+ it 'returns correct coordinates' do
38
+ expect(loaded_class.coordinates).to eq [{ "x": 0.372, "y": 0.1376 }, { "x": 0.616, "y": 0.4256 }]
39
+ end
40
+
41
+ context 'when the response label does not have an even amount of numbers' do
42
+ let(:loaded_class) { described_class.new(assessment_item_refs[1], test_object) }
43
+
44
+ it 'returns an empty array' do
45
+ expect(loaded_class.coordinates).to eq []
46
+ end
47
+ end
48
+
49
+ context 'when the response label is empty' do
50
+ let(:loaded_class) { described_class.new(assessment_item_refs[2], test_object) }
51
+
52
+ it 'returns an empty array' do
53
+ expect(loaded_class.coordinates).to eq []
54
+ end
55
+ end
56
+ end
57
+ 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.15.4
4
+ version: 2.17.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: 2023-06-27 00:00:00.000000000 Z
15
+ date: 2023-07-10 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: actionview
@@ -332,9 +332,11 @@ 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
339
+ - lib/qti/v1/models/interactions/hot_spot_interaction.rb
338
340
  - lib/qti/v1/models/interactions/match_interaction.rb
339
341
  - lib/qti/v1/models/interactions/numeric_interaction.rb
340
342
  - lib/qti/v1/models/interactions/ordering_interaction.rb
@@ -396,6 +398,7 @@ files:
396
398
  - spec/fixtures/items_1.2/canvas_multiple_fib.xml
397
399
  - spec/fixtures/items_1.2/canvas_multiple_fib_as_single.xml
398
400
  - spec/fixtures/items_1.2/canvas_multiple_fib_extra_brackets.xml
401
+ - spec/fixtures/items_1.2/categorization.xml
399
402
  - spec/fixtures/items_1.2/choice.xml
400
403
  - spec/fixtures/items_1.2/essay.xml
401
404
  - spec/fixtures/items_1.2/fib.xml
@@ -404,6 +407,7 @@ files:
404
407
  - spec/fixtures/items_1.2/formula.xml
405
408
  - spec/fixtures/items_1.2/formula_mform.xml
406
409
  - spec/fixtures/items_1.2/formula_mvar.xml
410
+ - spec/fixtures/items_1.2/hot_spot.xml
407
411
  - spec/fixtures/items_1.2/item_no_title.xml
408
412
  - spec/fixtures/items_1.2/matching.xml
409
413
  - spec/fixtures/items_1.2/matching_feedback.xml
@@ -676,9 +680,11 @@ files:
676
680
  - spec/lib/qti/v1/models/interactions/base_fill_blank_interaction_spec.rb
677
681
  - spec/lib/qti/v1/models/interactions/base_interaction_spec.rb
678
682
  - spec/lib/qti/v1/models/interactions/canvas_multiple_dropdown_spec.rb
683
+ - spec/lib/qti/v1/models/interactions/categorization_interaction_spec.rb
679
684
  - spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
680
685
  - spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
681
686
  - spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb
687
+ - spec/lib/qti/v1/models/interactions/hot_spot_interaction_spec.rb
682
688
  - spec/lib/qti/v1/models/interactions/match_interaction_spec.rb
683
689
  - spec/lib/qti/v1/models/interactions/numeric_interaction_spec.rb
684
690
  - spec/lib/qti/v1/models/interactions/ordering_interaction_spec.rb
@@ -759,6 +765,7 @@ test_files:
759
765
  - spec/fixtures/items_1.2/canvas_multiple_fib.xml
760
766
  - spec/fixtures/items_1.2/canvas_multiple_fib_as_single.xml
761
767
  - spec/fixtures/items_1.2/canvas_multiple_fib_extra_brackets.xml
768
+ - spec/fixtures/items_1.2/categorization.xml
762
769
  - spec/fixtures/items_1.2/choice.xml
763
770
  - spec/fixtures/items_1.2/essay.xml
764
771
  - spec/fixtures/items_1.2/fib.xml
@@ -767,6 +774,7 @@ test_files:
767
774
  - spec/fixtures/items_1.2/formula.xml
768
775
  - spec/fixtures/items_1.2/formula_mform.xml
769
776
  - spec/fixtures/items_1.2/formula_mvar.xml
777
+ - spec/fixtures/items_1.2/hot_spot.xml
770
778
  - spec/fixtures/items_1.2/item_no_title.xml
771
779
  - spec/fixtures/items_1.2/matching.xml
772
780
  - spec/fixtures/items_1.2/matching_feedback.xml
@@ -1039,9 +1047,11 @@ test_files:
1039
1047
  - spec/lib/qti/v1/models/interactions/base_fill_blank_interaction_spec.rb
1040
1048
  - spec/lib/qti/v1/models/interactions/base_interaction_spec.rb
1041
1049
  - spec/lib/qti/v1/models/interactions/canvas_multiple_dropdown_spec.rb
1050
+ - spec/lib/qti/v1/models/interactions/categorization_interaction_spec.rb
1042
1051
  - spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb
1043
1052
  - spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb
1044
1053
  - spec/lib/qti/v1/models/interactions/formula_interaction_spec.rb
1054
+ - spec/lib/qti/v1/models/interactions/hot_spot_interaction_spec.rb
1045
1055
  - spec/lib/qti/v1/models/interactions/match_interaction_spec.rb
1046
1056
  - spec/lib/qti/v1/models/interactions/numeric_interaction_spec.rb
1047
1057
  - spec/lib/qti/v1/models/interactions/ordering_interaction_spec.rb