canvas_cc 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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