canvas_cc 0.0.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.
Files changed (167) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +1 -0
  7. data/canvas_cc.gemspec +37 -0
  8. data/lib/canvas_cc/canvas/assessment.rb +124 -0
  9. data/lib/canvas_cc/canvas/assignment.rb +98 -0
  10. data/lib/canvas_cc/canvas/converter.rb +30 -0
  11. data/lib/canvas_cc/canvas/course.rb +143 -0
  12. data/lib/canvas_cc/canvas/discussion_topic.rb +64 -0
  13. data/lib/canvas_cc/canvas/label.rb +8 -0
  14. data/lib/canvas_cc/canvas/question.rb +492 -0
  15. data/lib/canvas_cc/canvas/question_bank.rb +57 -0
  16. data/lib/canvas_cc/canvas/question_group.rb +35 -0
  17. data/lib/canvas_cc/canvas/resource.rb +16 -0
  18. data/lib/canvas_cc/canvas/templates/assignment.html.erb +9 -0
  19. data/lib/canvas_cc/canvas/templates/syllabus.html.erb +9 -0
  20. data/lib/canvas_cc/canvas/templates/wiki_content.html.erb +10 -0
  21. data/lib/canvas_cc/canvas/web_content.rb +15 -0
  22. data/lib/canvas_cc/canvas/web_link.rb +16 -0
  23. data/lib/canvas_cc/canvas/wiki.rb +26 -0
  24. data/lib/canvas_cc/canvas_cc/assessment_writer.rb +82 -0
  25. data/lib/canvas_cc/canvas_cc/assignment_group_writer.rb +48 -0
  26. data/lib/canvas_cc/canvas_cc/assignment_writer.rb +68 -0
  27. data/lib/canvas_cc/canvas_cc/calculated_question_writer.rb +72 -0
  28. data/lib/canvas_cc/canvas_cc/canvas_export_writer.rb +18 -0
  29. data/lib/canvas_cc/canvas_cc/cartridge_creator.rb +60 -0
  30. data/lib/canvas_cc/canvas_cc/course_setting_writer.rb +35 -0
  31. data/lib/canvas_cc/canvas_cc/discussion_writer.rb +52 -0
  32. data/lib/canvas_cc/canvas_cc/essay_question_writer.rb +19 -0
  33. data/lib/canvas_cc/canvas_cc/file_meta_writer.rb +38 -0
  34. data/lib/canvas_cc/canvas_cc/ims_manifest_generator.rb +123 -0
  35. data/lib/canvas_cc/canvas_cc/matching_question_writer.rb +43 -0
  36. data/lib/canvas_cc/canvas_cc/models/answer.rb +12 -0
  37. data/lib/canvas_cc/canvas_cc/models/assessment.rb +102 -0
  38. data/lib/canvas_cc/canvas_cc/models/assignment.rb +30 -0
  39. data/lib/canvas_cc/canvas_cc/models/assignment_group.rb +9 -0
  40. data/lib/canvas_cc/canvas_cc/models/calculated_question.rb +19 -0
  41. data/lib/canvas_cc/canvas_cc/models/canvas_file.rb +22 -0
  42. data/lib/canvas_cc/canvas_cc/models/canvas_module.rb +10 -0
  43. data/lib/canvas_cc/canvas_cc/models/course.rb +53 -0
  44. data/lib/canvas_cc/canvas_cc/models/discussion.rb +36 -0
  45. data/lib/canvas_cc/canvas_cc/models/discussion_topic.rb +5 -0
  46. data/lib/canvas_cc/canvas_cc/models/matching_question.rb +7 -0
  47. data/lib/canvas_cc/canvas_cc/models/module_item.rb +16 -0
  48. data/lib/canvas_cc/canvas_cc/models/multiple_dropdowns_question.rb +7 -0
  49. data/lib/canvas_cc/canvas_cc/models/numerical_question.rb +7 -0
  50. data/lib/canvas_cc/canvas_cc/models/page.rb +41 -0
  51. data/lib/canvas_cc/canvas_cc/models/question.rb +37 -0
  52. data/lib/canvas_cc/canvas_cc/models/question_bank.rb +42 -0
  53. data/lib/canvas_cc/canvas_cc/models/question_group.rb +10 -0
  54. data/lib/canvas_cc/canvas_cc/models/resource.rb +23 -0
  55. data/lib/canvas_cc/canvas_cc/models/web_content.rb +7 -0
  56. data/lib/canvas_cc/canvas_cc/models/web_link.rb +7 -0
  57. data/lib/canvas_cc/canvas_cc/models/workflow_state.rb +6 -0
  58. data/lib/canvas_cc/canvas_cc/module_meta_writer.rb +52 -0
  59. data/lib/canvas_cc/canvas_cc/multiple_answers_question_writer.rb +41 -0
  60. data/lib/canvas_cc/canvas_cc/multiple_blanks_question_writer.rb +51 -0
  61. data/lib/canvas_cc/canvas_cc/multiple_choice_question_writer.rb +48 -0
  62. data/lib/canvas_cc/canvas_cc/multiple_dropdowns_question_writer.rb +30 -0
  63. data/lib/canvas_cc/canvas_cc/numerical_question_writer.rb +40 -0
  64. data/lib/canvas_cc/canvas_cc/page_writer.rb +38 -0
  65. data/lib/canvas_cc/canvas_cc/question_bank_writer.rb +44 -0
  66. data/lib/canvas_cc/canvas_cc/question_group_writer.rb +23 -0
  67. data/lib/canvas_cc/canvas_cc/question_writer.rb +129 -0
  68. data/lib/canvas_cc/canvas_cc/short_answer_question_writer.rb +42 -0
  69. data/lib/canvas_cc/canvas_cc/text_only_question_writer.rb +19 -0
  70. data/lib/canvas_cc/canvas_cc/true_false_question_writer.rb +38 -0
  71. data/lib/canvas_cc/cc/assessment.rb +25 -0
  72. data/lib/canvas_cc/cc/assignment.rb +61 -0
  73. data/lib/canvas_cc/cc/cc_helper.rb +285 -0
  74. data/lib/canvas_cc/cc/converter.rb +137 -0
  75. data/lib/canvas_cc/cc/course.rb +16 -0
  76. data/lib/canvas_cc/cc/discussion_topic.rb +53 -0
  77. data/lib/canvas_cc/cc/label.rb +6 -0
  78. data/lib/canvas_cc/cc/question.rb +23 -0
  79. data/lib/canvas_cc/cc/resource.rb +30 -0
  80. data/lib/canvas_cc/cc/templates/assignment.html.erb +13 -0
  81. data/lib/canvas_cc/cc/templates/syllabus.html.erb +9 -0
  82. data/lib/canvas_cc/cc/templates/wiki_content.html.erb +10 -0
  83. data/lib/canvas_cc/cc/web_content.rb +48 -0
  84. data/lib/canvas_cc/cc/web_link.rb +75 -0
  85. data/lib/canvas_cc/cc/wiki.rb +73 -0
  86. data/lib/canvas_cc/version.rb +3 -0
  87. data/lib/canvas_cc.rb +94 -0
  88. data/spec/moodle2cc/canvas_cc/assessment_writer_spec.rb +95 -0
  89. data/spec/moodle2cc/canvas_cc/assignment_group_writer_spec.rb +51 -0
  90. data/spec/moodle2cc/canvas_cc/assignment_writer_spec.rb +74 -0
  91. data/spec/moodle2cc/canvas_cc/calculated_question_writer_spec.rb +88 -0
  92. data/spec/moodle2cc/canvas_cc/canvas_export_writer_spec.rb +26 -0
  93. data/spec/moodle2cc/canvas_cc/cartridge_creator_spec.rb +50 -0
  94. data/spec/moodle2cc/canvas_cc/course_setting_writer_spec.rb +47 -0
  95. data/spec/moodle2cc/canvas_cc/discussion_writer_spec.rb +38 -0
  96. data/spec/moodle2cc/canvas_cc/essay_question_writer_spec.rb +31 -0
  97. data/spec/moodle2cc/canvas_cc/file_meta_writer_spec.rb +57 -0
  98. data/spec/moodle2cc/canvas_cc/ims_manifest_generator_spec.rb +141 -0
  99. data/spec/moodle2cc/canvas_cc/matching_question_writer_spec.rb +51 -0
  100. data/spec/moodle2cc/canvas_cc/models/assessment_spec.rb +131 -0
  101. data/spec/moodle2cc/canvas_cc/models/assignment_group_spec.rb +9 -0
  102. data/spec/moodle2cc/canvas_cc/models/assignment_spec.rb +45 -0
  103. data/spec/moodle2cc/canvas_cc/models/calculated_question_spec.rb +25 -0
  104. data/spec/moodle2cc/canvas_cc/models/canvas_file_spec.rb +23 -0
  105. data/spec/moodle2cc/canvas_cc/models/canvas_module_spec.rb +16 -0
  106. data/spec/moodle2cc/canvas_cc/models/course_spec.rb +43 -0
  107. data/spec/moodle2cc/canvas_cc/models/discussion_spec.rb +47 -0
  108. data/spec/moodle2cc/canvas_cc/models/discussion_topic_spec.rb +7 -0
  109. data/spec/moodle2cc/canvas_cc/models/module_item_spec.rb +15 -0
  110. data/spec/moodle2cc/canvas_cc/models/page_spec.rb +34 -0
  111. data/spec/moodle2cc/canvas_cc/models/question_spec.rb +8 -0
  112. data/spec/moodle2cc/canvas_cc/models/resource_spec.rb +17 -0
  113. data/spec/moodle2cc/canvas_cc/models/web_content_spec.rb +7 -0
  114. data/spec/moodle2cc/canvas_cc/models/web_link_spec.rb +9 -0
  115. data/spec/moodle2cc/canvas_cc/module_meta_writer_spec.rb +118 -0
  116. data/spec/moodle2cc/canvas_cc/multiple_answers_question_writer_spec.rb +50 -0
  117. data/spec/moodle2cc/canvas_cc/multiple_blanks_question_writer_spec.rb +77 -0
  118. data/spec/moodle2cc/canvas_cc/multiple_choice_question_writer_spec.rb +69 -0
  119. data/spec/moodle2cc/canvas_cc/multiple_dropdowns_question_writer_spec.rb +46 -0
  120. data/spec/moodle2cc/canvas_cc/numerical_question_writer_spec.rb +69 -0
  121. data/spec/moodle2cc/canvas_cc/page_writer_spec.rb +29 -0
  122. data/spec/moodle2cc/canvas_cc/question_bank_writer_spec.rb +43 -0
  123. data/spec/moodle2cc/canvas_cc/question_writer_spec.rb +129 -0
  124. data/spec/moodle2cc/canvas_cc/short_answer_question_writer_spec.rb +50 -0
  125. data/spec/moodle2cc/canvas_cc/text_only_question_writer_spec.rb +23 -0
  126. data/spec/moodle2cc/canvas_cc/true_false_question_writer_spec.rb +62 -0
  127. data/spec/spec_helper.rb +12 -0
  128. data/spec/support/shared_examples_for_models.rb +26 -0
  129. data/test/acceptance/migrator_test.rb +24 -0
  130. data/test/fixtures/cc.imscc +0 -0
  131. data/test/fixtures/common_cartridge/ims_manifest_simple.xml +45 -0
  132. data/test/fixtures/common_cartridge/schema/cccv1p0.xsd +563 -0
  133. data/test/fixtures/common_cartridge/schema/ccv1p1_imsccauth_v1p1.xsd +203 -0
  134. data/test/fixtures/common_cartridge/schema/ccv1p1_imscp_v1p2_v1p0.xsd +827 -0
  135. data/test/fixtures/common_cartridge/schema/ccv1p1_lommanifest_v1p0.xsd +822 -0
  136. data/test/fixtures/common_cartridge/schema/ccv1p1_lomresource_v1p0.xsd +273 -0
  137. data/test/fixtures/common_cartridge/schema/xml.xsd +286 -0
  138. data/test/test_helper.rb +71 -0
  139. data/test/test_question_helper.rb +122 -0
  140. data/test/test_wiki_helper.rb +21 -0
  141. data/test/unit/canvas/assessment_test.rb +261 -0
  142. data/test/unit/canvas/assignment_test.rb +220 -0
  143. data/test/unit/canvas/converter_test.rb +171 -0
  144. data/test/unit/canvas/course_test.rb +176 -0
  145. data/test/unit/canvas/discussion_topic_test.rb +129 -0
  146. data/test/unit/canvas/label_test.rb +32 -0
  147. data/test/unit/canvas/question_bank_test.rb +92 -0
  148. data/test/unit/canvas/question_group_test.rb +90 -0
  149. data/test/unit/canvas/question_test.rb +876 -0
  150. data/test/unit/canvas/web_content_test.rb +46 -0
  151. data/test/unit/canvas/web_link_test.rb +48 -0
  152. data/test/unit/canvas/wiki_test.rb +74 -0
  153. data/test/unit/cc/assessment_test.rb +48 -0
  154. data/test/unit/cc/assignment_test.rb +72 -0
  155. data/test/unit/cc/cc_helper_test.rb +19 -0
  156. data/test/unit/cc/converter_test.rb +173 -0
  157. data/test/unit/cc/course_test.rb +36 -0
  158. data/test/unit/cc/discussion_topic_test.rb +83 -0
  159. data/test/unit/cc/label_test.rb +29 -0
  160. data/test/unit/cc/question_test.rb +54 -0
  161. data/test/unit/cc/web_content_test.rb +76 -0
  162. data/test/unit/cc/web_link_test.rb +159 -0
  163. data/test/unit/cc/wiki_test.rb +139 -0
  164. data/test/unit/logger_test.rb +33 -0
  165. data/test/unit/migrator_test.rb +67 -0
  166. data/test/unit/resource_factory_test.rb +216 -0
  167. metadata +499 -0
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ module CanvasCc::CanvasCC
4
+ describe CourseSettingWriter do
5
+
6
+ let(:course) { CanvasCc::CanvasCC::Models::Course.new }
7
+ let(:tmpdir) { Dir.mktmpdir }
8
+
9
+ before :each do
10
+ Dir.mkdir(File.join(tmpdir, CartridgeCreator::COURSE_SETTINGS_DIR))
11
+ end
12
+
13
+ after :each do
14
+ FileUtils.rm_r tmpdir
15
+ end
16
+
17
+ it 'xml contains the correct schema' do
18
+ course.identifier = 'identifier'
19
+ xml = write_xml(course)
20
+
21
+ valid_schema = File.read(fixture_path(File.join('common_cartridge', 'schema', 'cccv1p0.xsd')))
22
+ xsd = Nokogiri::XML::Schema(valid_schema)
23
+ expect(xsd.validate(xml)).to be_true
24
+ end
25
+
26
+ it 'applies settings to xml' do
27
+ course.title = 'course title'
28
+ course.course_code = 'course code'
29
+ course.identifier = 'settings_id'
30
+ xml = write_xml(course)
31
+ expect(xml.at_xpath('/xmlns:course/@identifier').text).to eq('settings_id_settings')
32
+ expect(xml.at_xpath('/xmlns:course/xmlns:title').text).to eq(course.title)
33
+ expect(xml.at_xpath('/xmlns:course/xmlns:course_code').text).to eq(course.course_code)
34
+ end
35
+
36
+ private
37
+
38
+ def write_xml(course)
39
+ CourseSettingWriter.new(tmpdir, course).write
40
+ path = File.join(tmpdir,
41
+ CartridgeCreator::COURSE_SETTINGS_DIR,
42
+ CourseSettingWriter::COURSE_SETTINGS_FILE)
43
+ Nokogiri::XML(File.read(path))
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe CanvasCc::CanvasCC::DiscussionWriter do
4
+ subject(:writer) { CanvasCc::CanvasCC::DiscussionWriter.new(work_dir, discussion) }
5
+ let(:work_dir) { Dir.mktmpdir }
6
+ let(:discussion) {CanvasCc::CanvasCC::Models::Discussion.new}
7
+
8
+ after(:each) do
9
+ FileUtils.rm_r work_dir
10
+ end
11
+
12
+ it 'creates the discussion xml' do
13
+ discussion.identifier = 'discussion_id'
14
+ discussion.title = 'Discussion Title'
15
+ discussion.text = '<p>discussion_text</p>'
16
+ writer.write
17
+ xml = Nokogiri::XML(File.read(File.join(work_dir, discussion.discussion_resource.files.first)))
18
+ expect(xml.%('topic/title').text).to eq 'Discussion Title'
19
+ expect(xml.%('topic/text').text).to eq '<p>discussion_text</p>'
20
+ expect(xml.at_xpath('xmlns:topic/xmlns:text/@texttype').value).to eq('text/html')
21
+ end
22
+
23
+ it 'creates the meta xml' do
24
+ discussion.identifier = 'discussion_id'
25
+ discussion.title = 'Discussion Title'
26
+ discussion.text = '<p>discussion_text</p>'
27
+ discussion.discussion_type = 'threaded'
28
+ writer.write
29
+ xml = Nokogiri::XML(File.read(File.join(work_dir, discussion.meta_resource.href)))
30
+ expect(xml.at_xpath('xmlns:topicMeta/@identifier').value).to eq('discussion_id_meta')
31
+ expect(xml.%('topicMeta/topic_id').text).to eq 'discussion_id'
32
+ expect(xml.%('topicMeta/title').text).to eq 'Discussion Title'
33
+ expect(xml.%('topicMeta/type').text).to eq 'topic'
34
+ expect(xml.%('topicMeta/position').text).to eq ''
35
+ expect(xml.%('topicMeta/discussion_type').text).to eq 'threaded'
36
+ end
37
+
38
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ module CanvasCc::CanvasCC
4
+ describe EssayQuestionWriter do
5
+
6
+ let(:question) { CanvasCc::CanvasCC::Models::Question.create('essay_question')}
7
+
8
+ it 'creates the question item xml for an essay_question' do
9
+ question.identifier = 42
10
+ question.title = 'hi title'
11
+ question.general_feedback = 'unconstructive feedback'
12
+ question.material = 'materia'
13
+
14
+ xml = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |node|
15
+ QuestionWriter.write_question(node, question)
16
+ end.doc
17
+
18
+ expect(xml.at_xpath('item/@ident').value).to eq question.identifier.to_s
19
+ expect(xml.at_xpath('item/@title').value).to eq question.title
20
+ expect(xml.at_xpath("item/itemmetadata/qtimetadata/qtimetadatafield[fieldlabel=\"question_type\" and fieldentry=\"#{question.question_type}\"]")).to_not be_nil
21
+
22
+ response = xml.at_xpath('item/presentation/response_str')
23
+ expect(response.attributes['rcardinality'].value).to eq 'Single'
24
+ expect(response.attributes['ident'].value).to eq 'response1'
25
+ expect(response.at_xpath('render_fib/response_label').attributes['ident'].value).to eq 'answer1'
26
+
27
+ condition = xml.root.at_xpath('resprocessing/respcondition[@continue="No"]')
28
+ expect(condition.at_xpath('conditionvar/other')).to_not be_nil
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ module CanvasCc::CanvasCC
4
+ describe FileMetaWriter do
5
+
6
+ let(:file) { Models::CanvasFile.new }
7
+ let(:tmpdir) { Dir.mktmpdir }
8
+
9
+ before :each do
10
+ Dir.mkdir(File.join(tmpdir, CartridgeCreator::COURSE_SETTINGS_DIR))
11
+ end
12
+
13
+ after :each do
14
+ FileUtils.rm_r tmpdir
15
+ end
16
+
17
+ it 'xml contains the correct schema' do
18
+ meta_writer = writer(file)
19
+ meta_writer.stub(:copy_files) { nil }
20
+ xml = write_xml(meta_writer)
21
+ assert_xml_schema(xml)
22
+ end
23
+
24
+ it '#write' do
25
+ Dir.mktmpdir do |dir|
26
+ source_file = File.join(dir, 'sample.txt')
27
+ FileUtils.touch(source_file)
28
+ file.file_location = source_file
29
+ file.file_path = 'sample.txt'
30
+ write_xml(writer(file))
31
+ path = File.join(tmpdir, Models::CanvasFile::WEB_RESOURCES, 'sample.txt')
32
+ expect(File.exist?(path)).to be_true
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def writer(file)
39
+ FileMetaWriter.new(tmpdir, file)
40
+ end
41
+
42
+ def write_xml(writer)
43
+ writer.write
44
+ path = File.join(tmpdir,
45
+ CartridgeCreator::COURSE_SETTINGS_DIR,
46
+ FileMetaWriter::FILE_META_FILE)
47
+ Nokogiri::XML(File.read(path))
48
+ end
49
+
50
+ def assert_xml_schema(xml)
51
+ valid_schema = File.read(fixture_path(File.join('common_cartridge', 'schema', 'cccv1p0.xsd')))
52
+ xsd = Nokogiri::XML::Schema(valid_schema)
53
+ expect(xsd.validate(xml)).to be_empty
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+
3
+ module CanvasCc::CanvasCC
4
+ describe ImsManifestGenerator do
5
+
6
+ let(:course) { Models::Course.new }
7
+ let(:tmpdir) { Dir.mktmpdir }
8
+
9
+ before :each do
10
+ course.identifier = 'manifest_identifier'
11
+ end
12
+
13
+ after :each do
14
+ FileUtils.rm_r tmpdir
15
+ end
16
+
17
+ it 'xml contains the correct schema' do
18
+ course.title = 'Course Title'
19
+ course.copyright = 'copyright text'
20
+ xml = write_xml(course)
21
+ assert_xml_schema(xml)
22
+ end
23
+
24
+ describe 'metadata' do
25
+ it 'has valid metadata' do
26
+ course.title = 'Course Title'
27
+ xml = write_xml(course)
28
+
29
+ expect(xml.at_xpath('/xmlns:manifest/xmlns:metadata/xmlns:schema').text).to eq('IMS Common Cartridge')
30
+ expect(xml.at_xpath('/xmlns:manifest/xmlns:metadata/xmlns:schemaversion').text).to eq('1.1.0')
31
+
32
+ lom = xml.at_xpath('/xmlns:manifest/xmlns:metadata/lomimscc:lom')
33
+ expect(lom.at_xpath('lomimscc:general/lomimscc:title/lomimscc:string').text).to eq(course.title)
34
+ end
35
+
36
+ it 'has copyright' do
37
+ course.copyright = 'copyright text'
38
+ xml = write_xml(course)
39
+
40
+ lom = xml.at_xpath('/xmlns:manifest/xmlns:metadata/lomimscc:lom')
41
+ expect(lom.at_xpath('lomimscc:rights/lomimscc:copyrightAndOtherRestrictions/lomimscc:value').text).to eq('yes')
42
+ expect(lom.at_xpath('lomimscc:rights/lomimscc:description/lomimscc:string').text).to eq(course.copyright)
43
+ end
44
+
45
+ it 'has no copyright' do
46
+ xml = write_xml(course)
47
+
48
+ lom = xml.at_xpath('/xmlns:manifest/xmlns:metadata/lomimscc:lom')
49
+ expect(lom.at_xpath('lomimscc:rights/lomimscc:copyrightAndOtherRestrictions/lomimscc:value').text).to eq('no')
50
+ expect(lom.at_xpath('lomimscc:rights/lomimscc:description/lomimscc:string')).to be_nil
51
+ end
52
+ end
53
+
54
+ describe 'resources' do
55
+ it 'has valid resource settings' do
56
+ course.canvas_modules << Models::CanvasModule.new
57
+ xml = write_xml(course)
58
+
59
+ resources_node = xml.%('manifest/resources')
60
+ expect(resources_node.at_xpath('xmlns:resource/@href').value).to eq('course_settings/canvas_export.txt')
61
+ expect(resources_node.at_xpath('xmlns:resource/@type').value).to eq('associatedcontent/imscc_xmlv1p1/learning-application-resource')
62
+ expect(resources_node.at_xpath('xmlns:resource/@identifier').value).to eq('manifest_identifier_settings')
63
+
64
+ files = resources_node.xpath('xmlns:resource/xmlns:file/@href').map(&:value)
65
+ expect(files).to include('course_settings/course_settings.xml')
66
+ expect(files).to include('course_settings/module_meta.xml')
67
+ end
68
+
69
+ it 'has valid resource' do
70
+ resource = Models::Resource.new
71
+ resource.identifier = 'resource_identifier'
72
+ resource.type = 'resource_type'
73
+ resource.href = 'resource_href'
74
+ resource.files << 'file_1'
75
+ resource.files << 'file_2'
76
+ resource.dependencies << :dependency
77
+ course.resources << resource
78
+ xml = write_xml(course)
79
+
80
+ base_node = xml.at_xpath("/xmlns:manifest/xmlns:resources/xmlns:resource[@identifier='resource_identifier']")
81
+ expect(base_node.at_xpath('@type').value).to eq('resource_type')
82
+ expect(base_node.at_xpath('@href').value).to eq('resource_href')
83
+ expect(base_node.xpath("xmlns:file[@href='file_1']").count).to eq(1)
84
+ expect(base_node.xpath("xmlns:file[@href='file_2']").count).to eq(1)
85
+ expect(base_node.xpath("xmlns:dependency[@identifierref='dependency']").count).to eq(1)
86
+ end
87
+ end
88
+
89
+ describe 'organizations' do
90
+ it 'writes learning modules' do
91
+ canvas_module = Models::CanvasModule.new
92
+ canvas_module.title = 'my module title'
93
+ canvas_module.identifier = 'my_id'
94
+ course.canvas_modules << canvas_module
95
+ xml = write_xml(course)
96
+
97
+ org_node = xml.at_xpath('/xmlns:manifest/xmlns:organizations/xmlns:organization')
98
+ expect(org_node.at_xpath('@structure').value).to eq('rooted-hierarchy')
99
+ expect(org_node.at_xpath('@identifier').value).to eq('org_1')
100
+ expect(org_node.at_xpath('xmlns:item/@identifier').value).to eq('LearningModules')
101
+ expect(org_node.at_xpath('xmlns:item/xmlns:item/@identifier').value).to eq('my_id')
102
+ expect(org_node.%('item/title').text).to eq('my module title')
103
+ end
104
+
105
+ it 'writes module items' do
106
+ canvas_module = Models::CanvasModule.new
107
+
108
+ module_item = Models::ModuleItem.new
109
+ module_item.identifier = 'module_item_unique_identifier'
110
+ module_item.title = 'Module Item'
111
+ module_item.identifierref = 'resource_unique_identifier'
112
+
113
+ canvas_module.module_items << module_item
114
+ course.canvas_modules << canvas_module
115
+
116
+ xml = write_xml(course)
117
+ module_node = xml.at_xpath('/xmlns:manifest').%('organizations/organization/item/item')
118
+ expect(module_node.at_xpath('xmlns:item/@identifier').value).to eq 'module_item_unique_identifier'
119
+ expect(module_node.at_xpath('xmlns:item/@identifierref').value).to eq 'resource_unique_identifier'
120
+ expect(module_node.%('item/title').text).to eq 'Module Item'
121
+ end
122
+ end
123
+
124
+ private
125
+
126
+ def write_xml(course)
127
+ generator = ImsManifestGenerator.new(tmpdir, course)
128
+ generator.write
129
+
130
+ path = File.join(tmpdir, ImsManifestGenerator::MANIFEST_FILE_NAME)
131
+ Nokogiri::XML(File.read(path))
132
+ end
133
+
134
+ def assert_xml_schema(xml)
135
+ valid_schema = File.read(fixture_path(File.join('common_cartridge', 'schema', 'ccv1p1_imscp_v1p2_v1p0.xsd')))
136
+ xsd = Nokogiri::XML::Schema(valid_schema)
137
+ expect(xsd.validate(xml)).to be_empty
138
+ end
139
+
140
+ end
141
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ module CanvasCc::CanvasCC
4
+ describe MatchingQuestionWriter do
5
+
6
+ let(:question) { CanvasCc::CanvasCC::Models::Question.create('matching_question')}
7
+
8
+ it 'creates the question item xml for a matching question' do
9
+ question.identifier = 9001
10
+ question.title = 'its over nine thousannnd'
11
+ question.general_feedback = 'ur totes awesome'
12
+ question.material = 'this is a question, or is it?'
13
+
14
+ match1 = {:id => '1', :question_text => 'qtext', :question_text_format => '1', :answer_text => 'answer1'}
15
+ match2 = {:id => '2', :question_text => 'qtext2', :question_text_format => '1', :answer_text => 'answer2'}
16
+ question.matches = [match1, match2]
17
+
18
+ xml = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |node|
19
+ QuestionWriter.write_question(node, question)
20
+ end.doc
21
+
22
+ expect(xml.at_xpath('item/@ident').value).to eq question.identifier.to_s
23
+ expect(xml.at_xpath('item/@title').value).to eq question.title
24
+ expect(xml.at_xpath("item/itemmetadata/qtimetadata/qtimetadatafield[fieldlabel=\"question_type\" and fieldentry=\"#{question.question_type}\"]")).to_not be_nil
25
+
26
+ response = xml.at_xpath("item/presentation/response_lid[@ident=\"response_#{match1[:id]}\"]")
27
+ expect(response.at_xpath('material/mattext[@texttype="text/plain"]').text).to eq match1[:question_text]
28
+ expect(response.at_xpath("render_choice/response_label[@ident=\"#{match1[:id]}\"]/material/mattext").text).to eq match1[:answer_text]
29
+ expect(response.at_xpath("render_choice/response_label[@ident=\"#{match2[:id]}\"]/material/mattext").text).to eq match2[:answer_text]
30
+
31
+ response = xml.at_xpath("item/presentation/response_lid[@ident=\"response_#{match2[:id]}\"]")
32
+ expect(response.at_xpath('material/mattext[@texttype="text/plain"]').text).to eq match2[:question_text]
33
+ expect(response.at_xpath("render_choice/response_label[@ident=\"#{match1[:id]}\"]/material/mattext").text).to eq match1[:answer_text]
34
+ expect(response.at_xpath("render_choice/response_label[@ident=\"#{match2[:id]}\"]/material/mattext").text).to eq match2[:answer_text]
35
+
36
+ condition = xml.at_xpath("item/resprocessing/respcondition/conditionvar[varequal=\"#{match1[:id]}\"]/..")
37
+ expect(condition.at_xpath("conditionvar/varequal[@respident=\"response_#{match1[:id]}\"]")).not_to be_nil
38
+ set_var = condition.at_xpath('setvar')
39
+ expect(set_var.attributes['varname'].value).to eq 'SCORE'
40
+ expect(set_var.attributes['action'].value).to eq 'Add'
41
+ expect(set_var.text).to eq '50.00'
42
+
43
+ condition = xml.at_xpath("item/resprocessing/respcondition/conditionvar[varequal=\"#{match2[:id]}\"]/..")
44
+ expect(condition.at_xpath("conditionvar/varequal[@respident=\"response_#{match2[:id]}\"]")).not_to be_nil
45
+ set_var = condition.at_xpath('setvar')
46
+ expect(set_var.attributes['varname'].value).to eq 'SCORE'
47
+ expect(set_var.attributes['action'].value).to eq 'Add'
48
+ expect(set_var.text).to eq '50.00'
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,131 @@
1
+ require 'spec_helper'
2
+
3
+ describe CanvasCc::CanvasCC::Models::Assessment do
4
+
5
+ it_behaves_like 'it has an attribute for', :identifier
6
+ it_behaves_like 'it has an attribute for', :title
7
+ it_behaves_like 'it has an attribute for', :description
8
+ it_behaves_like 'it has an attribute for', :lock_at
9
+ it_behaves_like 'it has an attribute for', :unlock_at
10
+ it_behaves_like 'it has an attribute for', :allowed_attempts
11
+ it_behaves_like 'it has an attribute for', :scoring_policy
12
+ it_behaves_like 'it has an attribute for', :access_code
13
+ it_behaves_like 'it has an attribute for', :ip_filter
14
+ it_behaves_like 'it has an attribute for', :shuffle_answers
15
+ it_behaves_like 'it has an attribute for', :time_limit
16
+ it_behaves_like 'it has an attribute for', :quiz_type
17
+ it_behaves_like 'it has an attribute for', :workflow_state
18
+
19
+ it_behaves_like 'it has an attribute for', :question_references, []
20
+ it_behaves_like 'it has an attribute for', :items
21
+
22
+ it 'returns both resources' do
23
+ subject.stub(:cc_assessment_resource) {:cc_resource}
24
+ subject.stub(:canvas_assessment_resource) {:canvas_resource}
25
+ expect(subject.resources).to eq [:cc_resource, :canvas_resource]
26
+ end
27
+
28
+ it 'creates resources' do
29
+ subject.identifier = 'assessment_id'
30
+ subject.title = 'My Assessment'
31
+
32
+ cc_resource = subject.cc_assessment_resource
33
+ expect(cc_resource).to be_a_kind_of CanvasCc::CanvasCC::Models::Resource
34
+ expect(cc_resource.type).to eq 'imsqti_xmlv1p2/imscc_xmlv1p1/assessment'
35
+ expect(cc_resource.identifier).to eq 'assessment_id'
36
+ expect(cc_resource.dependencies).to include 'assessment_id_meta'
37
+
38
+ canvas_resource = subject.canvas_assessment_resource
39
+ expect(canvas_resource).to be_a_kind_of CanvasCc::CanvasCC::Models::Resource
40
+ expect(canvas_resource.files.count).to eq 2
41
+ expect(canvas_resource.identifier).to eq 'assessment_id_meta'
42
+ expect(canvas_resource.type).to eq 'associatedcontent/imscc_xmlv1p1/learning-application-resource'
43
+ expect(canvas_resource.href).to eq 'assessment_id/assessment_meta.xml'
44
+ expect(canvas_resource.files).to include 'assessment_id/assessment_meta.xml'
45
+ expect(canvas_resource.files).to include 'non_cc_assessments/assessment_id.xml.qti'
46
+ end
47
+
48
+ it 'resolves assessment questions' do
49
+ subject.question_references = [
50
+ {:question => '1', :grade => '2'},
51
+ {:question => '2', :grade => '3'},
52
+ {:question => '3', :grade => '5'},
53
+ {:question => 'grouppy', :grade => '8.0'},
54
+ {:question => 'nonexistent', :grade => '4'}
55
+ ]
56
+
57
+ qb1 = CanvasCc::CanvasCC::Models::QuestionBank.new
58
+ q1 = CanvasCc::CanvasCC::Models::Question.new
59
+ q1.original_identifier = '1'
60
+ q2 = CanvasCc::CanvasCC::Models::Question.new
61
+ q2.original_identifier = '3'
62
+ qb1.questions = [q1, q2]
63
+
64
+ qb2 = CanvasCc::CanvasCC::Models::QuestionBank.new
65
+ q3 = CanvasCc::CanvasCC::Models::Question.new
66
+ q3.original_identifier = '2'
67
+ qb2.questions = [q3]
68
+
69
+ group = CanvasCc::CanvasCC::Models::QuestionGroup.new
70
+ group.selection_number = 4
71
+ group.identifier = 'grouppy'
72
+ group.questions = [q2]
73
+ qb2.question_groups = [group]
74
+
75
+ subject.resolve_question_references!([qb1, qb2])
76
+
77
+ expect(subject.items.count).to eq 3
78
+ expect(subject.items[0].points_possible).to eq '2'
79
+ expect(subject.items[1].points_possible).to eq '3'
80
+ # should not include q2 because it's already part of the group
81
+ expect(subject.items[2].points_per_item).to eq 2
82
+ end
83
+
84
+
85
+ it 'resolves random quesiton references' do
86
+ subject.question_references = [
87
+ {:question => 'random1', :grade => '2'},
88
+ {:question => 'random2', :grade => '3'},
89
+ {:question => 'random3', :grade => '3'},
90
+ {:question => 'nonexistent', :grade => '4'}
91
+ ]
92
+
93
+ qb1 = CanvasCc::CanvasCC::Models::QuestionBank.new
94
+ q1 = CanvasCc::CanvasCC::Models::Question.new
95
+ q1.identifier = '1'
96
+ q2 = CanvasCc::CanvasCC::Models::Question.new
97
+ q2.identifier = '2'
98
+
99
+ qb1.questions = [q1, q2]
100
+ qb1.original_id = 'parent'
101
+ qb1.random_question_references = ['random1', 'random2']
102
+
103
+ qb2 = CanvasCc::CanvasCC::Models::QuestionBank.new
104
+ q3 = CanvasCc::CanvasCC::Models::Question.new
105
+ q3.identifier = '3'
106
+ qb2.parent_id = 'parent'
107
+ qb2.questions = [q3]
108
+
109
+ qb3 = CanvasCc::CanvasCC::Models::QuestionBank.new
110
+ q4 = CanvasCc::CanvasCC::Models::Question.new
111
+ q4.identifier = '4'
112
+ q5 = CanvasCc::CanvasCC::Models::Question.new
113
+ q5.identifier = '5'
114
+ qb3.questions = [q4, q5]
115
+ qb3.random_question_references = ['random3']
116
+
117
+ subject.resolve_question_references!([qb1, qb2, qb3])
118
+
119
+ expect(subject.items.count).to eq 2
120
+ group1 = subject.items[0]
121
+ expect(group1.class).to eq CanvasCc::CanvasCC::Models::QuestionGroup
122
+ expect(group1.selection_number).to eq 2
123
+ expect(group1.questions.map(&:identifier)).to eq [q1, q2, q3].map(&:identifier)
124
+
125
+ group2 = subject.items[1]
126
+ expect(group2.class).to eq CanvasCc::CanvasCC::Models::QuestionGroup
127
+ expect(group2.selection_number).to eq 1
128
+ expect(group2.questions.map(&:identifier)).to eq qb3.questions.map(&:identifier)
129
+ end
130
+
131
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe CanvasCc::CanvasCC::Models::AssignmentGroup do
4
+
5
+ it_behaves_like 'it has an attribute for', :title
6
+ it_behaves_like 'it has an attribute for', :position
7
+ it_behaves_like 'it has an attribute for', :group_weight
8
+ it_behaves_like 'it has an attribute for', :identifier
9
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ describe CanvasCc::CanvasCC::Models::Assignment do
4
+
5
+ it_behaves_like 'it has an attribute for', :title
6
+ it_behaves_like 'it has an attribute for', :body
7
+ it_behaves_like 'it has an attribute for', :due_at
8
+ it_behaves_like 'it has an attribute for', :position
9
+ it_behaves_like 'it has an attribute for', :identifier
10
+ it_behaves_like 'it has an attribute for', :lock_at
11
+ it_behaves_like 'it has an attribute for', :unlock_at
12
+ it_behaves_like 'it has an attribute for', :all_day_date
13
+ it_behaves_like 'it has an attribute for', :peer_reviews_due_at
14
+ it_behaves_like 'it has an attribute for', :assignment_group_identifier_ref
15
+ it_behaves_like 'it has an attribute for', :workflow_state
16
+ it_behaves_like 'it has an attribute for', :points_possible
17
+ it_behaves_like 'it has an attribute for', :grading_type
18
+ it_behaves_like 'it has an attribute for', :all_day
19
+ it_behaves_like 'it has an attribute for', :submission_types, []
20
+ it_behaves_like 'it has an attribute for', :peer_review_count
21
+ it_behaves_like 'it has an attribute for', :peer_reviews_assigned
22
+ it_behaves_like 'it has an attribute for', :peer_reviews
23
+ it_behaves_like 'it has an attribute for', :automatic_peer_reviews
24
+ it_behaves_like 'it has an attribute for', :grade_group_students_individually
25
+
26
+ it 'creates a resource' do
27
+ subject.stub(:assignment_resource) {:assignment_resource}
28
+ expect(subject.resources).to eq [:assignment_resource]
29
+ end
30
+
31
+ it 'generates an assignment resource' do
32
+ subject.identifier = 'assignment_id'
33
+ subject.title = 'My Assignment'
34
+
35
+ resource = subject.assignment_resource
36
+ expect(resource).to be_a_kind_of CanvasCc::CanvasCC::Models::Resource
37
+ expect(resource.files.count).to eq 2
38
+ expect(resource.identifier).to eq 'assignment_id'
39
+ expect(resource.type).to eq 'associatedcontent/imscc_xmlv1p1/learning-application-resource'
40
+ expect(resource.href).to eq 'assignment_id/assignment-my-assignment.html'
41
+ expect(resource.files).to include 'assignment_id/assignment-my-assignment.html'
42
+ expect(resource.files).to include 'assignment_id/assignment_settings.xml'
43
+ end
44
+
45
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe CanvasCc::CanvasCC::Models::CalculatedQuestion do
4
+
5
+ context '#post_process!' do
6
+ it 'should replace {variables} with [variables] in material' do
7
+ subject.material = "{varname} {not * s valid var name and stuff}"
8
+
9
+ subject.post_process!
10
+
11
+ expect(subject.material).to eq "[varname] {not * s valid var name and stuff}"
12
+ end
13
+
14
+ it 'should replace {variables} with variables in formulae (and strip =)' do
15
+ answer = CanvasCc::CanvasCC::Models::Answer.new
16
+ answer.answer_text = "={A}*{B}"
17
+ subject.answers = [answer]
18
+
19
+ subject.post_process!
20
+
21
+ expect(subject.answers.first.answer_text).to eq "A*B"
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ module CanvasCc::CanvasCC::Models
4
+ describe CanvasFile do
5
+
6
+ it_behaves_like 'a CanvasCc::CanvasCC::Models::Resource'
7
+ it_behaves_like 'it has an attribute for', :file_location
8
+
9
+ it 'has a type to webcontent' do
10
+ expect(subject.type).to eq(Resource::WEB_CONTENT_TYPE)
11
+ end
12
+
13
+ it 'sets up href, file_path and files on #file_path=' do
14
+ filename = 'myfile.txt'
15
+ subject.file_path = filename
16
+ expect(subject.href).to eq('web_resources/myfile.txt')
17
+ expect(subject.file_path).to eq(filename)
18
+ expect(subject.files.count).to eq(1)
19
+ expect(subject.files.first).to eq('web_resources/myfile.txt')
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ require 'spec_helper'
2
+
3
+ module CanvasCc::CanvasCC::Models
4
+ describe CanvasModule do
5
+
6
+ it_behaves_like 'it has an attribute for', :title
7
+ it_behaves_like 'it has an attribute for', :workflow_state
8
+ it_behaves_like 'it has an attribute for', :module_items, []
9
+
10
+ it 'adds MD5 to identifier on #identifier=' do
11
+ subject.identifier = 'foo_bar'
12
+ expect(subject.identifier).to eq('foo_bar')
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module CanvasCc::CanvasCC::Models
4
+ describe Course do
5
+ subject(:course) { Course.new }
6
+
7
+ it_behaves_like 'it has an attribute for', :format
8
+ it_behaves_like 'it has an attribute for', :copyright
9
+ it_behaves_like 'it has an attribute for', :settings, {}
10
+ it_behaves_like 'it has an attribute for', :resources, []
11
+ it_behaves_like 'it has an attribute for', :canvas_modules, []
12
+ it_behaves_like 'it has an attribute for', :files, []
13
+ it_behaves_like 'it has an attribute for', :pages, []
14
+ it_behaves_like 'it has an attribute for', :discussions, []
15
+ it_behaves_like 'it has an attribute for', :assignments, []
16
+
17
+ it 'formats date strings' do
18
+ course.start_at = Time.parse('Sat, 08 Feb 2014 16:00:00 GMT')
19
+ course.conclude_at = Time.parse('Sat, 10 Feb 2014 16:00:00 GMT')
20
+ expect(course.start_at).to eq '2014-02-08T16:00:00'
21
+ expect(course.conclude_at).to eq '2014-02-10T16:00:00'
22
+ end
23
+
24
+ it 'creates settings for unknown attributes' do
25
+ course.title = 'course_title'
26
+ expect(course.settings[:title]).to eq 'course_title'
27
+ end
28
+
29
+ describe '#all_resources' do
30
+ it 'includes files and resources' do
31
+ discussion = double('discussion', resources: [:discussion, :meta])
32
+ assignment = double('assignment', resources: [:assignment])
33
+ course.resources << :resource
34
+ course.files << :file
35
+ course.pages << :page
36
+ course.discussions << discussion
37
+ course.assignments << assignment
38
+ expect(course.all_resources).to eq [:resource, :file, :page, :discussion, :meta, :assignment]
39
+ end
40
+ end
41
+
42
+ end
43
+ end