qti 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/lib/qti/assessment_item_exporter.rb +1 -1
  3. data/lib/qti/content_packaging/assessment_item.rb +1 -1
  4. data/lib/qti/content_packaging/assessment_test.rb +2 -2
  5. data/lib/qti/content_packaging/choice_interaction.rb +1 -1
  6. data/lib/qti/models/base.rb +13 -5
  7. data/lib/qti/models/manifest.rb +21 -7
  8. data/lib/qti/v1/models/assessment.rb +3 -1
  9. data/lib/qti/v1/models/assessment_item.rb +13 -5
  10. data/lib/qti/v1/models/choices/fill_blank_choice.rb +1 -1
  11. data/lib/qti/v1/models/choices/logical_identifier_choice.rb +1 -1
  12. data/lib/qti/v1/models/interactions/base_interaction.rb +1 -1
  13. data/lib/qti/v1/models/interactions/choice_interaction.rb +19 -5
  14. data/lib/qti/v2/models/assessment_item.rb +23 -6
  15. data/lib/qti/v2/models/assessment_test.rb +3 -1
  16. data/lib/qti/v2/models/choices/gap_match_choice.rb +1 -1
  17. data/lib/qti/v2/models/choices/simple_choice.rb +1 -1
  18. data/lib/qti/v2/models/interactions/base_interaction.rb +1 -1
  19. data/lib/qti/v2/models/interactions/gap_match_interaction.rb +16 -7
  20. data/lib/qti/version.rb +1 -1
  21. data/spec/lib/qti/v1/models/interactions/choice_interaction_spec.rb +9 -2
  22. data/spec/lib/qti/v2/models/assessment_item_spec.rb +12 -0
  23. data/spec/lib/qti/v2/models/assessment_test_spec.rb +9 -2
  24. data/spec/lib/qti_spec.rb +1 -0
  25. data/spec/lib/stupid.xml +128 -0
  26. metadata +19 -17
  27. data/spec/gemfiles/nokogiri-1.6.gemfile.lock +0 -126
  28. data/spec/gemfiles/nokogiri-1.8.gemfile.lock +0 -126
  29. data/spec/gemfiles/rails-4.2.gemfile.lock +0 -203
  30. data/spec/gemfiles/rails-5.0.gemfile.lock +0 -209
  31. data/spec/gemfiles/rails-5.1.gemfile.lock +0 -209
  32. data/spec/gemfiles/sanitize-4.2.gemfile.lock +0 -126
  33. data/spec/gemfiles/sanitize-4.5.gemfile.lock +0 -126
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 202d9ba3ef99c4e0df030cf13a8e25f4e19441c2
4
- data.tar.gz: 077f7118e61d94d1d7796494e481355e0b399833
3
+ metadata.gz: 9278a5814a878f23f53159c3adb0c64e7d7a8e69
4
+ data.tar.gz: 8892e930ffbf68ef68b5f08fddd5ed3fa63f34da
5
5
  SHA512:
6
- metadata.gz: 6119e426a2f6c4b91cfb84ac7da7ca78317490439c0ace3ec067fc65ffa1b8b929979dfa76a4cb648b9d44781e5cb55d38490c89151ab1e66581c9315c8b88ff
7
- data.tar.gz: 76f7caf87c7c9efd299b770d2adfcfa5737991dbaa3b2ee450616d0ae987bac40bd2a362932769f462006e80a11b40b4cb00c249cf48b1565c70fa50b71d559e
6
+ metadata.gz: 25f42764b0ac0109aa2ab6edf7e3e814fd4150b94b195684f856acaa6faaa859712287a6262141352456b1e341e6d1caef0e037fdfce476d2742cc67d53f3203
7
+ data.tar.gz: e3cda7d07238a30879125895ef9b73bb1283d2776803ace6489e5226e0ddd736ebf09321e8f65a7fe5cb01a1783ba8a01d0ddb9476be4724b8b34a79d07146b2
@@ -1,6 +1,6 @@
1
1
  module Qti
2
2
  class AssessmentItemExporter
3
- attr_reader :assessment_item, :package_root_path, :exported_file_path
3
+ attr_reader :assessment_item, :package_root_path
4
4
 
5
5
  def initialize(assessment_item, args = {})
6
6
  @assessment_item = assessment_item
@@ -4,7 +4,7 @@ module Qti
4
4
  attribute :identifier, Types::Strict::String
5
5
  attribute :title, Types::Strict::String
6
6
  attribute :interaction, ContentPackaging::ChoiceInteraction
7
- attribute :response, Types::Strict::Array.member(String) | Types::Strict::String
7
+ attribute :response, Types::Strict::Array.of(String) | Types::Strict::String
8
8
  end
9
9
  end
10
10
  end
@@ -3,8 +3,8 @@ module Qti
3
3
  class AssessmentTest < Dry::Struct
4
4
  attribute :identifier, Types::Strict::String
5
5
  attribute :title, Types::Strict::String
6
- attribute :items, Types::Strict::Array.member(ContentPackaging::AssessmentItem)
7
- attribute :outcome_declarations, Types::Strict::Array.member(ContentPackaging::OutcomeDeclaration)
6
+ attribute :items, Types::Strict::Array.of(ContentPackaging::AssessmentItem)
7
+ attribute :outcome_declarations, Types::Strict::Array.of(ContentPackaging::OutcomeDeclaration)
8
8
  end
9
9
  end
10
10
  end
@@ -6,7 +6,7 @@ module Qti
6
6
  attribute :prompt, Types::Strict::String
7
7
  attribute :shuffle, Types::Strict::Bool.default(false)
8
8
  attribute :maxChoices, Types::Coercible::Int
9
- attribute :choices, Types::Strict::Array.member(ContentPackaging::SimpleChoice)
9
+ attribute :choices, Types::Strict::Array.of(ContentPackaging::SimpleChoice)
10
10
  end
11
11
  end
12
12
  end
@@ -10,6 +10,7 @@ module Qti
10
10
  module Models
11
11
  class Base
12
12
  attr_reader :doc, :path, :package_root
13
+ attr_accessor :manifest
13
14
 
14
15
  ELEMENTS_REMAP = {
15
16
  'prompt' => 'div',
@@ -58,7 +59,7 @@ module Qti
58
59
 
59
60
  def initialize(path:, package_root: nil, html: false)
60
61
  @path = path
61
- set_package_root(package_root || File.dirname(path))
62
+ self.package_root = package_root || File.dirname(path)
62
63
  @doc = html ? parse_html(File.read(path)) : parse_xml(File.read(path))
63
64
  raise ArgumentError unless @doc
64
65
  end
@@ -89,20 +90,27 @@ module Qti
89
90
  if @package_root.nil?
90
91
  raise Qti::ParseError, "Potentially unsafe href '#{href}'" if href.split('/').include?('..')
91
92
  else
92
- raise Qti::ParseError, "Unsafe href '#{href}'" unless Pathname.new(path).cleanpath.to_s.start_with?(@package_root)
93
+ unless Pathname.new(path).cleanpath.to_s.start_with?(@package_root)
94
+ raise Qti::ParseError, "Unsafe href '#{href}'"
95
+ end
93
96
  end
94
97
  path
95
98
  end
96
99
 
97
100
  protected
98
101
 
99
- def set_package_root(package_root)
102
+ def package_root=(package_root)
100
103
  @package_root = package_root
101
104
  return unless @package_root
102
105
  @package_root = Pathname.new(@package_root).cleanpath.to_s + '/'
103
106
  end
104
107
 
105
- def set_paths_from_item(other_item)
108
+ def relative_path
109
+ return nil if @path.nil? || @package_root.nil?
110
+ @path.sub(/\A#{Regexp.quote(@package_root)}/, '')
111
+ end
112
+
113
+ def copy_paths_from_item(other_item)
106
114
  @package_root = other_item.package_root
107
115
  @path = other_item.path
108
116
  end
@@ -111,7 +119,7 @@ module Qti
111
119
  path = remap_href_path(node[:data])
112
120
  if path
113
121
  case node[:type]
114
- when /^image\//
122
+ when %r{^image\/}
115
123
  return replace_with_image(node, node[:data])
116
124
  when 'text/html'
117
125
  return replace_with_html(node, path)
@@ -4,19 +4,27 @@ module Qti
4
4
  module Models
5
5
  class Manifest < Qti::Models::Base
6
6
  def assessment_test
7
- qti_2_x_href || qti_1_href || qti_2_non_assessment_href || unknown_type
7
+ test = qti_2_x_href || qti_1_href || qti_2_non_assessment_href || unknown_type
8
+ test.manifest = self
9
+ test
8
10
  end
9
11
 
10
12
  def qti_1_href
11
- test_path = xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_xmlv1p2']/@href")&.content ||
12
- xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_xmlv1p2']/xmlns:file/@href")&.content
13
- Qti::V1::Models::Assessment.from_path!(remap_href_path(test_path), @package_root) if test_path
13
+ test_path = xmlns_resource("[@type='imsqti_xmlv1p2']/@href") ||
14
+ xmlns_resource("[@type='imsqti_xmlv1p2']/xmlns:file/@href")
15
+ return unless test_path
16
+ Qti::V1::Models::Assessment.from_path!(
17
+ remap_href_path(test_path), @package_root
18
+ )
14
19
  end
15
20
 
16
21
  def qti_2_x_href
17
- test_path = xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_test_xmlv2p1']/@href")&.content ||
18
- xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_test_xmlv2p2']/@href")&.content
19
- Qti::V2::Models::AssessmentTest.from_path!(remap_href_path(test_path), @package_root) if test_path
22
+ test_path = xmlns_resource("[@type='imsqti_test_xmlv2p1']/@href") ||
23
+ xmlns_resource("[@type='imsqti_test_xmlv2p2']/@href")
24
+ return unless test_path
25
+ Qti::V2::Models::AssessmentTest.from_path!(
26
+ remap_href_path(test_path), @package_root
27
+ )
20
28
  end
21
29
 
22
30
  def qti_2_non_assessment_href
@@ -27,6 +35,12 @@ module Qti
27
35
  def unknown_type
28
36
  raise Qti::UnsupportedSchema, 'Unsupported QTI version'
29
37
  end
38
+
39
+ private
40
+
41
+ def xmlns_resource(type)
42
+ xpath_with_single_check("//xmlns:resources/xmlns:resource#{type}")&.content
43
+ end
30
44
  end
31
45
  end
32
46
  end
@@ -13,7 +13,9 @@ module Qti
13
13
  end
14
14
 
15
15
  def create_assessment_item(assessment_item)
16
- Qti::V1::Models::AssessmentItem.new(assessment_item, @package_root)
16
+ item = Qti::V1::Models::AssessmentItem.new(assessment_item, @package_root)
17
+ item.manifest = manifest
18
+ item
17
19
  end
18
20
 
19
21
  def stimulus_ref(_ref)
@@ -10,7 +10,7 @@ module Qti
10
10
  def initialize(item, package_root = nil)
11
11
  @doc = item
12
12
  @path = item.document.url
13
- set_package_root(package_root)
13
+ self.package_root = package_root
14
14
  end
15
15
 
16
16
  def item_body
@@ -34,7 +34,7 @@ module Qti
34
34
  @doc.at_xpath('.//xmlns:qtimetadata')&.children
35
35
  end
36
36
 
37
- def has_points_possible_qti_metadata?
37
+ def points_possible_qti_metadata?
38
38
  if @doc.at_xpath('.//xmlns:qtimetadata').present?
39
39
  points_possible_label = qti_metadata_children.children.find { |node| node.text == 'points_possible' }
40
40
  points_possible_label.present?
@@ -43,11 +43,19 @@ module Qti
43
43
  end
44
44
  end
45
45
 
46
+ # @deprecated Please use {#points_possible_qti_metadata?} instead
47
+ def has_points_possible_qti_metadata? # rubocop:disable Naming/PredicateName
48
+ warn "DEPRECATED: '#{__method__}' is renamed to 'points_possible_qti_metadata?'."
49
+ points_possible_qti_metadata?
50
+ end
51
+
46
52
  def points_possible
47
53
  @points_possible ||= begin
48
- if has_points_possible_qti_metadata?
49
- points_possible_label = qti_metadata_children.children.find { |node| node.text == 'points_possible' }
50
- points_possible_node = points_possible_label.next.text
54
+ if points_possible_qti_metadata?
55
+ points_possible_label = qti_metadata_children.children.find do |node|
56
+ node.text == 'points_possible'
57
+ end
58
+ points_possible_label.next.text
51
59
  else
52
60
  decvar_maxvalue
53
61
  end
@@ -7,7 +7,7 @@ module Qti
7
7
  class FillBlankChoice < Qti::V1::Models::Base
8
8
  def initialize(node, parent)
9
9
  @node = node
10
- set_paths_from_item(parent)
10
+ copy_paths_from_item(parent)
11
11
  end
12
12
 
13
13
  def identifier
@@ -7,7 +7,7 @@ module Qti
7
7
  class LogicalIdentifierChoice < Qti::V1::Models::Base
8
8
  def initialize(node, parent)
9
9
  @node = node
10
- set_paths_from_item(parent)
10
+ copy_paths_from_item(parent)
11
11
  end
12
12
 
13
13
  def identifier
@@ -11,7 +11,7 @@ module Qti
11
11
 
12
12
  def initialize(node, parent)
13
13
  @node = node
14
- set_paths_from_item(parent)
14
+ copy_paths_from_item(parent)
15
15
  end
16
16
 
17
17
  def shuffled?
@@ -21,12 +21,9 @@ module Qti
21
21
  def scoring_data_structs
22
22
  choice_nodes = node.xpath('.//xmlns:respcondition')
23
23
  if choice_nodes.at_xpath('.//xmlns:and').present?
24
- answer_choices = choice_nodes.at_xpath('.//xmlns:and')
25
- answer_choices.children.filter('not').each(&:remove)
26
- answer_choices.children.map { |value_node| ScoringData.new(value_node.content, rcardinality) }
24
+ scoring_data_condition(choice_nodes)
27
25
  else
28
- set_var_nodes = choice_nodes.select { |choice_node| choice_node.at_xpath('.//xmlns:setvar')&.content&.to_f&.positive? }
29
- set_var_nodes.map { |value_node| ScoringData.new(value_node.at_xpath('.//xmlns:varequal').content, rcardinality) }
26
+ scoring_data(choice_nodes)
30
27
  end
31
28
  end
32
29
 
@@ -35,6 +32,23 @@ module Qti
35
32
  def answer_nodes
36
33
  node.xpath('.//xmlns:response_label')
37
34
  end
35
+
36
+ def scoring_data_condition(choice_nodes)
37
+ answer_choices = choice_nodes.at_xpath('.//xmlns:and')
38
+ answer_choices.children.filter('not').each(&:remove)
39
+ answer_choices.children.map do |value_node|
40
+ ScoringData.new(value_node.content, rcardinality)
41
+ end
42
+ end
43
+
44
+ def scoring_data(choice_nodes)
45
+ set_var_nodes = choice_nodes.select do |choice_node|
46
+ choice_node.at_xpath('.//xmlns:setvar')&.content&.to_f&.positive?
47
+ end
48
+ set_var_nodes.map do |value_node|
49
+ ScoringData.new(value_node.at_xpath('.//xmlns:varequal').content, rcardinality)
50
+ end
51
+ end
38
52
  end
39
53
  end
40
54
  end
@@ -12,12 +12,7 @@ module Qti
12
12
  node = item_body_node.dup
13
13
  # ensure a prompt is carried into the html
14
14
  prompt = node.at_xpath('//xmlns:prompt')
15
-
16
- # Filter undesired interaction nodes out of the list (need to make this a deep traversal)
17
- node.children.filter(INTERACTION_ELEMENTS_CSS).map(&:unlink)
18
- # Filter out rubrics
19
- node.children.filter('rubricBlock').map(&:unlink)
20
-
15
+ filter_item_body(node)
21
16
  node.add_child(prompt) if prompt&.parent && prompt.parent != node
22
17
  sanitize_content!(node.to_html)
23
18
  end
@@ -54,6 +49,28 @@ module Qti
54
49
  def item_body_node
55
50
  @item_body_node ||= xpath_with_single_check('//xmlns:itemBody')
56
51
  end
52
+
53
+ def filter_item_body(node)
54
+ # Filter undesired interaction nodes out of the list (need to make this a deep traversal)
55
+ node.children.filter(INTERACTION_ELEMENTS_CSS).map(&:unlink)
56
+ # Filter out rubrics
57
+ node.children.filter('rubricBlock').map(&:unlink)
58
+ # Filter out stimulus passages (these will be handled separately)
59
+ filter_stimulus_passages!(node)
60
+ end
61
+
62
+ def dependency_hrefs
63
+ return [] unless manifest
64
+ manifest.doc.xpath("//xmlns:resource[@href='#{relative_path}']/xmlns:dependency/@identifierref").map do |id|
65
+ manifest.xpath_with_single_check("//xmlns:resource[@identifier='#{id}']/@href")
66
+ end
67
+ end
68
+
69
+ def filter_stimulus_passages!(node)
70
+ dependency_hrefs.each do |href|
71
+ node.at_css("object[type='text/html'][data='#{href}']").try(:unlink)
72
+ end
73
+ end
57
74
  end
58
75
  end
59
76
  end
@@ -26,7 +26,9 @@ module Qti
26
26
  end
27
27
 
28
28
  def create_assessment_item(assessment_item_ref)
29
- Qti::V2::Models::AssessmentItem.from_path!(assessment_item_ref, @package_root)
29
+ item = Qti::V2::Models::AssessmentItem.from_path!(assessment_item_ref, @package_root)
30
+ item.manifest = manifest
31
+ item
30
32
  end
31
33
 
32
34
  def stimulus_ref(_ref)
@@ -8,7 +8,7 @@ module Qti
8
8
  PROHIBITED_NODE_NAMES = 'feedbackInline'.freeze
9
9
  def initialize(node, parent)
10
10
  @node = node
11
- set_paths_from_item(parent)
11
+ copy_paths_from_item(parent)
12
12
  end
13
13
 
14
14
  def identifier
@@ -9,7 +9,7 @@ module Qti
9
9
 
10
10
  def initialize(node, parent)
11
11
  @node = node
12
- set_paths_from_item(parent)
12
+ copy_paths_from_item(parent)
13
13
  end
14
14
 
15
15
  def identifier
@@ -11,7 +11,7 @@ module Qti
11
11
 
12
12
  def initialize(node, parent)
13
13
  @node = node
14
- set_paths_from_item(parent)
14
+ copy_paths_from_item(parent)
15
15
  end
16
16
 
17
17
  def shuffled?
@@ -85,16 +85,11 @@ module Qti
85
85
  end
86
86
 
87
87
  def scoring_data_structs
88
- question_response_pairs = node.xpath('.//xmlns:correctResponse//xmlns:value').map do |value|
89
- value.content.split
90
- end
91
- question_response_pairs.map!(&:reverse)
92
- question_response_id_mapping = Hash[question_response_pairs]
88
+ mapping = question_response_id_mapping
93
89
  answer_nodes.map do |value_node|
94
90
  node_id = value_node.attributes['identifier']&.value
95
- answer_choice = choices.find { |choice| choice.attributes['identifier']&.value == question_response_id_mapping[node_id] }
96
91
  ScoringData.new(
97
- answer_choice.content,
92
+ answer_choice(choices, mapping[node_id]).content,
98
93
  'directedPair',
99
94
  id: node_id,
100
95
  case: false
@@ -111,6 +106,20 @@ module Qti
111
106
  def answer_nodes
112
107
  @node.xpath('.//xmlns:gap')
113
108
  end
109
+
110
+ def answer_choice(choices, response)
111
+ choices.find do |choice|
112
+ choice.attributes['identifier']&.value == response
113
+ end
114
+ end
115
+
116
+ def question_response_id_mapping
117
+ question_response_pairs = node.xpath('.//xmlns:correctResponse//xmlns:value').map do |value|
118
+ value.content.split
119
+ end
120
+ question_response_pairs.map!(&:reverse)
121
+ Hash[question_response_pairs]
122
+ end
114
123
  end
115
124
  end
116
125
  end
data/lib/qti/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '0.9.1'.freeze
2
+ VERSION = '0.9.2'.freeze
3
3
  end
@@ -15,7 +15,8 @@ describe Qti::V1::Models::Interactions::ChoiceInteraction do
15
15
  shared_examples_for 'answers' do
16
16
  it 'returns the answers' do
17
17
  expect(loaded_class.answers.count).to eq answer_choices_count
18
- expect(loaded_class.answers.first).to be_an_instance_of(Qti::V1::Models::Choices::LogicalIdentifierChoice)
18
+ expect(loaded_class.answers.first)
19
+ .to be_an_instance_of(Qti::V1::Models::Choices::LogicalIdentifierChoice)
19
20
  end
20
21
  end
21
22
 
@@ -54,7 +55,13 @@ describe Qti::V1::Models::Interactions::ChoiceInteraction do
54
55
 
55
56
  context 'multiple respconditions with empty setvars' do
56
57
  let(:fixtures_path) { File.join('spec', 'fixtures', 'test_with_comments') }
57
- let(:file_path) { File.join(fixtures_path, 'i6c88aaf29feba2ffa58a487a20665394', 'i6c88aaf29feba2ffa58a487a20665394.xml') }
58
+ let(:file_path) do
59
+ File.join(
60
+ fixtures_path,
61
+ 'i6c88aaf29feba2ffa58a487a20665394',
62
+ 'i6c88aaf29feba2ffa58a487a20665394.xml'
63
+ )
64
+ end
58
65
 
59
66
  it 'loads the items' do
60
67
  expect(loaded_class.scoring_data_structs.count).to eq 1
@@ -77,4 +77,16 @@ describe Qti::V2::Models::AssessmentItem do
77
77
  end
78
78
  end
79
79
  end
80
+
81
+ context 'stimulus passages' do
82
+ let(:file_path) { File.join('spec', 'fixtures', 'no_assessment_XML') }
83
+ let(:importer) { Qti::Importer.new(file_path) }
84
+ let(:test_object) { importer.test_object }
85
+ let(:item_ref) { File.join(file_path, 'a4f3621a-195c-4847-a72c-69388250a078.xml') }
86
+
87
+ it 'removes the passage from the item_body' do
88
+ item = test_object.create_assessment_item(item_ref)
89
+ expect(item.item_body).not_to include '¡El equipo de hockey te necesita!'
90
+ end
91
+ end
80
92
  end
@@ -35,7 +35,11 @@ describe Qti::V2::Models::AssessmentTest do
35
35
  test_files = Dir.glob(File.join(fixtures_path, 'tests', 'tests', 'rtest[0-9][0-9].xml'))
36
36
  test_files << File.join(fixtures_path, 'tests', 'tests', 'complete.xml')
37
37
  test_files << File.join(fixtures_path, 'tests', 'feedbackTest', 'assessment.xml')
38
- test_files << File.join(fixtures_path, 'tests', 'interactionmix_saxony_v3', 'InteractionMixSachsen_1901710679.xml')
38
+ test_files << File.join(
39
+ fixtures_path, 'tests',
40
+ 'interactionmix_saxony_v3',
41
+ 'InteractionMixSachsen_1901710679.xml'
42
+ )
39
43
  test_files.each do |file|
40
44
  context File.basename(file) do
41
45
  let(:loaded_class) { described_class.from_path!(file) }
@@ -77,7 +81,10 @@ describe Qti::V2::Models::AssessmentTest do
77
81
  let(:loaded_class) { described_class.from_path!(path) }
78
82
 
79
83
  it 'creates a stimulus from a given file' do
80
- stimulus_path = File.join(fixtures_path, 'no_assessment_XML', 'passages', '0cfd5cf7-2c91-4b35-a57a-9f5d1709f68f.html')
84
+ stimulus_path = File.join(
85
+ fixtures_path, 'no_assessment_XML',
86
+ 'passages', '0cfd5cf7-2c91-4b35-a57a-9f5d1709f68f.html'
87
+ )
81
88
  stimulus = loaded_class.create_stimulus(stimulus_path)
82
89
  expect(stimulus.title).to eq '¡El equipo de hockey te necesita!'
83
90
  end
data/spec/lib/qti_spec.rb CHANGED
@@ -67,6 +67,7 @@ describe Qti::Importer do
67
67
  item = importer.create_assessment_item(ref)
68
68
  expect(item.path).to eq ref
69
69
  expect(item.package_root).to eq file_path + '/'
70
+ expect(item.manifest).not_to be_nil
70
71
  end
71
72
  end
72
73
  end
@@ -0,0 +1,128 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" identifier="Manifest-d1042982-b88a-4c04-a6e0-9bb718b41178"
3
+ xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2"
4
+ xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_v2p1">
5
+ <organizations/>
6
+ <metadata>
7
+ <schema>IMS Content</schema>
8
+ <schemaversion>2.1</schemaversion>
9
+ <imsmd:lom xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2">
10
+ <imsmd:general>
11
+ <imsmd:title>
12
+ <imsmd:langstring>Assignment test? Worth Points Question Pool 1</imsmd:langstring>
13
+ </imsmd:title>
14
+ </imsmd:general>
15
+ </imsmd:lom>
16
+ </metadata>
17
+ <resources>
18
+ <resource href="1009/question4928.xml" identifier="1788:4928" type="imsqti_item_xmlv2p1">
19
+ <metadata>
20
+ <imsqti:qtiMetadata xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_v2p1">
21
+ <imsqti:itemTemplate>false</imsqti:itemTemplate>
22
+ <imsqti:composite>false</imsqti:composite>
23
+ <imsqti:interactionType>extendedTextInteraction</imsqti:interactionType>
24
+ <imsqti:feedbackType>none</imsqti:feedbackType>
25
+ </imsqti:qtiMetadata>
26
+ </metadata>
27
+ <file href="1009/question4928.xml"/>
28
+ <file href="1009/Resources/Ixia.gif"/>
29
+ <file href="1009/Resources/aperture.png"/>
30
+ </resource>
31
+ <resource href="1009/question4900.xml" identifier="1785:4900" type="imsqti_item_xmlv2p1">
32
+ <metadata>
33
+ <imsqti:qtiMetadata xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_v2p1">
34
+ <imsqti:itemTemplate>false</imsqti:itemTemplate>
35
+ <imsqti:composite>false</imsqti:composite>
36
+ <imsqti:interactionType>choiceInteraction</imsqti:interactionType>
37
+ <imsqti:feedbackType>none</imsqti:feedbackType>
38
+ </imsqti:qtiMetadata>
39
+ </metadata>
40
+ <file href="1009/question4900.xml"/>
41
+ <file href="1009/Resources/512634641600_00_93874928374.jpg"/>
42
+ <file href="1009/Resources/fmath-equation-9666DCA9-6656-C4BA-4E2D-63AA5B5954C1.png"/>
43
+ </resource>
44
+ <resource href="1009/question4961.xml" identifier="1785:4961" type="imsqti_item_xmlv2p1">
45
+ <metadata>
46
+ <imsqti:qtiMetadata xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_v2p1">
47
+ <imsqti:itemTemplate>false</imsqti:itemTemplate>
48
+ <imsqti:composite>false</imsqti:composite>
49
+ <imsqti:interactionType>choiceInteraction</imsqti:interactionType>
50
+ <imsqti:feedbackType>none</imsqti:feedbackType>
51
+ </imsqti:qtiMetadata>
52
+ </metadata>
53
+ <file href="1009/question4961.xml"/>
54
+ </resource>
55
+ <resource href="1009/question4962.xml" identifier="1785:4962" type="imsqti_item_xmlv2p1">
56
+ <metadata>
57
+ <imsqti:qtiMetadata xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_v2p1">
58
+ <imsqti:itemTemplate>false</imsqti:itemTemplate>
59
+ <imsqti:composite>false</imsqti:composite>
60
+ <imsqti:interactionType>choiceInteraction</imsqti:interactionType>
61
+ <imsqti:feedbackType>none</imsqti:feedbackType>
62
+ </imsqti:qtiMetadata>
63
+ </metadata>
64
+ <file href="1009/question4962.xml"/>
65
+ <file href="1009/Resources/waterfall_desktop_background-1440x900.jpg"/>
66
+ </resource>
67
+ <resource href="1009/question4967.xml" identifier="1788:4967" type="imsqti_item_xmlv2p1">
68
+ <metadata>
69
+ <imsqti:qtiMetadata xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_v2p1">
70
+ <imsqti:itemTemplate>false</imsqti:itemTemplate>
71
+ <imsqti:composite>false</imsqti:composite>
72
+ <imsqti:interactionType>matchInteraction</imsqti:interactionType>
73
+ <imsqti:feedbackType>none</imsqti:feedbackType>
74
+ </imsqti:qtiMetadata>
75
+ </metadata>
76
+ <file href="1009/question4967.xml"/>
77
+ </resource>
78
+ <resource href="1009/question4965.xml" identifier="1788:4965" type="imsqti_item_xmlv2p1">
79
+ <metadata>
80
+ <imsmd:lom xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2">
81
+ <imsmd:general>
82
+ <imsmd:identifier>survey</imsmd:identifier>
83
+ </imsmd:general>
84
+ </imsmd:lom>
85
+ <imsqti:qtiMetadata xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_v2p1">
86
+ <imsqti:itemTemplate>false</imsqti:itemTemplate>
87
+ <imsqti:composite>false</imsqti:composite>
88
+ <imsqti:interactionType>choiceInteraction</imsqti:interactionType>
89
+ <imsqti:feedbackType>none</imsqti:feedbackType>
90
+ </imsqti:qtiMetadata>
91
+ </metadata>
92
+ <file href="1009/question4965.xml"/>
93
+ </resource>
94
+ <resource href="1009/question4966.xml" identifier="1788:4966" type="imsqti_item_xmlv2p1">
95
+ <metadata>
96
+ <imsqti:qtiMetadata xmlns:imsqti="http://www.imsglobal.org/xsd/imsqti_v2p1">
97
+ <imsqti:itemTemplate>false</imsqti:itemTemplate>
98
+ <imsqti:composite>false</imsqti:composite>
99
+ <imsqti:interactionType>textEntryInteraction</imsqti:interactionType>
100
+ <imsqti:feedbackType>none</imsqti:feedbackType>
101
+ </imsqti:qtiMetadata>
102
+ </metadata>
103
+ <file href="1009/question4966.xml"/>
104
+ </resource>
105
+ <resource href="1009/assessment1.xml" identifier="Resource1" type="imsqti_test_xmlv2p1">
106
+ <metadata>
107
+ <imsmd:lom xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2">
108
+ <imsmd:general>
109
+ <imsmd:identifier>assignment</imsmd:identifier>
110
+ <imsmd:title>
111
+ <imsmd:langstring>Assignment test? Worth Points</imsmd:langstring>
112
+ </imsmd:title>
113
+ </imsmd:general>
114
+ </imsmd:lom>
115
+ </metadata>
116
+ <file href="1009/assessment1.xml"/>
117
+ <dependency identifierref="1788:4928"/>
118
+ <dependency identifierref="1785:4900"/>
119
+ <dependency identifierref="1785:4961"/>
120
+ <dependency identifierref="1785:4962"/>
121
+ <dependency identifierref="1788:4967"/>
122
+ <dependency identifierref="1788:4965"/>
123
+ <dependency identifierref="1788:4966"/>
124
+ </resource>
125
+ <resource identifier="POOL1788" title="Assignment test? Worth Points"/>
126
+ <resource identifier="POOL1785" title="Question Pool 1"/>
127
+ </resources>
128
+ </manifest>