rtunesu 0.2.4 → 0.3.5

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 (120) hide show
  1. data/.gitignore +3 -0
  2. data/History.txt +0 -5
  3. data/README.txt +2 -2
  4. data/Rakefile +15 -2
  5. data/VERSION +1 -0
  6. data/lib/rtunesu/connection.rb +152 -54
  7. data/lib/rtunesu/document.rb +21 -26
  8. data/lib/rtunesu/entities/course.rb +4 -13
  9. data/lib/rtunesu/entities/division.rb +5 -12
  10. data/lib/rtunesu/entities/external_feed.rb +14 -0
  11. data/lib/rtunesu/entities/group.rb +5 -14
  12. data/lib/rtunesu/entities/permission.rb +1 -5
  13. data/lib/rtunesu/entities/section.rb +15 -11
  14. data/lib/rtunesu/entities/site.rb +6 -13
  15. data/lib/rtunesu/entities/template.rb +4 -0
  16. data/lib/rtunesu/entities/theme.rb +3 -15
  17. data/lib/rtunesu/entities/track.rb +12 -27
  18. data/lib/rtunesu/entity.rb +185 -74
  19. data/lib/rtunesu/log.rb +69 -0
  20. data/lib/rtunesu/subentities.rb +60 -0
  21. data/lib/rtunesu/user.rb +3 -1
  22. data/lib/rtunesu/version.rb +2 -2
  23. data/lib/rtunesu.rb +11 -6
  24. data/lib/show_tree.xml +7 -0
  25. data/spec/connection_spec.rb +6 -30
  26. data/spec/document_spec.rb +82 -8
  27. data/spec/entities/course_spec.rb +13 -40
  28. data/spec/entities/division_spec.rb +13 -3
  29. data/spec/entities/external_feed_spec.rb +21 -0
  30. data/spec/entities/group_spec.rb +14 -3
  31. data/spec/entities/permission_spec.rb +12 -3
  32. data/spec/entities/section_spec.rb +32 -3
  33. data/spec/entities/site_spec.rb +16 -3
  34. data/spec/entities/track_spec.rb +32 -3
  35. data/spec/entity_spec.rb +147 -86
  36. data/spec/fixtures/requests/create_course.xml +17 -0
  37. data/spec/fixtures/requests/create_division.xml +11 -0
  38. data/spec/fixtures/requests/create_group.xml +11 -0
  39. data/spec/fixtures/requests/create_section.xml +11 -0
  40. data/spec/fixtures/requests/delete_course.xml +8 -0
  41. data/spec/fixtures/requests/delete_group.xml +8 -0
  42. data/spec/fixtures/requests/delete_section.txt +8 -0
  43. data/spec/fixtures/requests/show_course.xml +8 -0
  44. data/spec/fixtures/requests/show_group.xml +8 -0
  45. data/spec/fixtures/requests/show_section.xml +8 -0
  46. data/spec/fixtures/requests/update_course.xml +10 -0
  47. data/spec/fixtures/requests/update_group.xml +9 -0
  48. data/spec/fixtures/requests/update_section.txt +10 -0
  49. data/spec/fixtures/responses/failure/create_course.xml +5 -0
  50. data/spec/fixtures/responses/failure/create_division.xml +5 -0
  51. data/spec/fixtures/responses/failure/create_group.xml +5 -0
  52. data/spec/fixtures/responses/failure/create_section.xml +5 -0
  53. data/spec/fixtures/responses/failure/delete_group.xml +5 -0
  54. data/spec/fixtures/responses/failure/show_course.xml +11 -0
  55. data/spec/fixtures/responses/failure/show_division.xml +11 -0
  56. data/spec/fixtures/responses/failure/show_group.xml +11 -0
  57. data/spec/fixtures/responses/failure/show_section.xml +11 -0
  58. data/spec/fixtures/responses/failure/show_site.xml +11 -0
  59. data/spec/fixtures/responses/failure/update_section.txt +5 -0
  60. data/spec/fixtures/responses/success/create_course.xml +5 -0
  61. data/spec/fixtures/responses/success/create_division.xml +5 -0
  62. data/spec/fixtures/responses/success/create_group.xml +5 -0
  63. data/spec/fixtures/responses/success/create_section.xml +5 -0
  64. data/spec/fixtures/responses/success/delete_course.xml +4 -0
  65. data/spec/fixtures/responses/success/delete_division.xml +4 -0
  66. data/spec/fixtures/responses/success/delete_group.xml +4 -0
  67. data/spec/fixtures/responses/success/delete_section.txt +4 -0
  68. data/spec/fixtures/responses/success/delete_section.xml +4 -0
  69. data/spec/fixtures/responses/success/show_course.xml +393 -0
  70. data/spec/fixtures/responses/success/show_division.xml +393 -0
  71. data/spec/fixtures/responses/success/show_group.xml +137 -0
  72. data/spec/fixtures/responses/success/show_section.xml +152 -0
  73. data/spec/fixtures/responses/success/show_site.xml +393 -0
  74. data/spec/fixtures/responses/success/update_course.xml +4 -0
  75. data/spec/fixtures/responses/success/update_division.xml +4 -0
  76. data/spec/fixtures/responses/success/update_group.xml +4 -0
  77. data/spec/fixtures/responses/success/update_section.txt +4 -0
  78. data/spec/fixtures/responses/success/update_section.xml +4 -0
  79. data/spec/fixtures/responses/success/update_site.xml +4 -0
  80. data/spec/spec_helper.rb +72 -7
  81. data/spec/token_generation_spec.rb +23 -0
  82. data/spec/user_spec.rb +3 -3
  83. metadata +81 -76
  84. data/Manifest.txt +0 -77
  85. data/config/hoe.rb +0 -76
  86. data/config/requirements.rb +0 -15
  87. data/lib/multipart.rb +0 -53
  88. data/spec/documents/add_spec.rb +0 -41
  89. data/spec/documents/delete_spec.rb +0 -30
  90. data/spec/documents/merge_spec.rb +0 -30
  91. data/spec/documents/show_tree_spec.rb +0 -16
  92. data/spec/fixtures/add_course.xml +0 -26
  93. data/spec/fixtures/add_division.xml +0 -26
  94. data/spec/fixtures/add_group.xml +0 -27
  95. data/spec/fixtures/add_permission.xml +0 -12
  96. data/spec/fixtures/add_section.xml +0 -34
  97. data/spec/fixtures/add_track.xml +0 -19
  98. data/spec/fixtures/delete_course.xml +0 -8
  99. data/spec/fixtures/delete_division.xml +0 -8
  100. data/spec/fixtures/delete_group.xml +0 -8
  101. data/spec/fixtures/delete_permission.xml +0 -9
  102. data/spec/fixtures/delete_section.xml +0 -8
  103. data/spec/fixtures/delete_track.xml +0 -7
  104. data/spec/fixtures/merge_course.xml +0 -38
  105. data/spec/fixtures/merge_division.xml +0 -47
  106. data/spec/fixtures/merge_group.xml +0 -29
  107. data/spec/fixtures/merge_permission.xml +0 -12
  108. data/spec/fixtures/merge_section.xml +0 -36
  109. data/spec/fixtures/merge_site.xml +0 -31
  110. data/spec/fixtures/merge_track.xml +0 -18
  111. data/spec/fixtures/requests/add_coures_request.xml +0 -0
  112. data/spec/fixtures/show_tree.xml +0 -273
  113. data/spec/fixtures/update_group.xml +0 -7
  114. data/tasks/deployment.rake +0 -34
  115. data/tasks/website.rake +0 -17
  116. data/website/index.html +0 -54
  117. data/website/index.txt +0 -7
  118. data/website/javascripts/rounded_corners_lite.inc.js +0 -285
  119. data/website/stylesheets/screen.css +0 -138
  120. data/website/template.html.erb +0 -48
@@ -1,16 +1,90 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
  include RTunesU
3
+ include Document
3
4
 
4
- describe Document do
5
- before(:all) do
6
- @xml = Document::Merge.new(Course.new).xml
5
+ [Course, Division, Section, Group].each do |klass|
6
+ [:Add, :Merge, :Delete].each do |action|
7
+ describe "Document building for #{klass} for #{action}" do
8
+ before(:each) do
9
+ @entity = klass.new
10
+ @entity.parent_handle = '1'
11
+ @document = Hpricot.XML(Document.const_get(action).new(@entity).xml)
12
+ end
13
+
14
+ it "should have a base element of ITunesUDocument" do
15
+ @document.at("ITunesUDocument").should_not be_nil
16
+ end
17
+
18
+ it "should have a Version element with the iTunesU Version as content" do
19
+ @document.at("ITunesUDocument/Version").should_not be_nil
20
+ end
21
+ end
7
22
  end
8
23
 
9
- it 'includes a base element of ITunesUDocument' do
10
- (Hpricot.XML(@xml) % 'ITunesUDocument').should_not be_nil
24
+ describe "Document::Add for #{klass}" do
25
+ before(:each) do
26
+ @entity = klass.new
27
+ @entity.parent_handle = '1'
28
+ @document = Hpricot.XML(Document::Add.new(@entity).xml)
29
+ end
30
+
31
+ it "should raise error without parent handle" do
32
+ @entity.parent_handle = nil
33
+ lambda { Hpricot.XML(Document::Add.new(@entity).xml) }.should raise_error(MissingParent)
34
+ end
35
+
36
+ it "should have a Add element" do
37
+ @document.at("ITunesUDocument/Add#{@entity.class_name}").should_not be_nil
38
+ end
39
+
40
+ it "should have a ParentHandle element" do
41
+ @document.at("ITunesUDocument/Add#{@entity.class_name}/ParentHandle").should_not be_nil
42
+ end
43
+
44
+ it "should have a ParentPath element" do
45
+ @document.at("ITunesUDocument/Add#{@entity.class_name}/ParentPath").should_not be_nil
46
+ end
47
+
48
+ it "should have an element for its Entity" do
49
+ @document.at("ITunesUDocument/Add#{@entity.class_name}/#{@entity.class_name}").should_not be_nil
50
+ end
11
51
  end
12
52
 
13
- it 'includes a version number' do
14
- (Hpricot.XML(@xml) % 'ITunesUDocument/Version').should_not be_nil
53
+ describe "Document::Merge for #{klass}" do
54
+ before(:each) do
55
+ @entity = klass.new
56
+ @document = Hpricot.XML(Document::Merge.new(@entity).xml)
57
+ end
58
+
59
+ it "should have a Merge element" do
60
+ @document.at("ITunesUDocument/Merge#{@entity.class_name}").should_not be_nil
61
+ end
62
+
63
+ it "should have a Handle element" do
64
+ @document.at("ITunesUDocument/Merge#{@entity.class_name}/#{@entity.class_name}Handle").should_not be_nil
65
+ end
66
+
67
+ it "should have an element for its Entity" do
68
+ @document.at("ITunesUDocument/Merge#{@entity.class_name}/#{@entity.class_name}").should_not be_nil
69
+ end
70
+ end
71
+
72
+ describe "Document::Delete for #{klass}" do
73
+ before(:each) do
74
+ @entity = klass.new
75
+ @document = Hpricot.XML(Document::Delete.new(@entity).xml)
76
+ end
77
+
78
+ it "should have a Delete element" do
79
+ @document.at("ITunesUDocument/Delete#{@entity.class_name}").should_not be_nil
80
+ end
81
+
82
+ it "should have a Handle element" do
83
+ @document.at("ITunesUDocument/Delete#{@entity.class_name}/#{@entity.class_name}Handle").should_not be_nil
84
+ end
85
+
86
+ it "should have a Path element" do
87
+ @document.at("ITunesUDocument/Delete#{@entity.class_name}/#{@entity.class_name}Path").should_not be_nil
88
+ end
15
89
  end
16
- end
90
+ end
@@ -1,47 +1,20 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../entity_spec.rb'
3
+ require File.dirname(__FILE__) + '/../document_spec.rb'
4
+
2
5
  include RTunesU
3
6
 
4
- describe Course do
5
- before do
6
- u = RTunesU::User.new(0, 'admin', 'Admin', 'admin@example.com')
7
- u.credentials = ['Administrator@urn:mace:example.edu']
8
- @connection = RTunesU::Connection.new(:user => u, :site => 'example.edu', :shared_secret => 'STRINGOFTHIRTYTWOLETTERSORDIGITS')
7
+ describe Course do
8
+ before(:each) do
9
+ @klass = Course
10
+ @entity = Course.new
11
+ @course = @entity
12
+ @attributes = {:name => 'Sample Course'}
9
13
  end
10
14
 
11
- describe 'finding' do
12
- it 'can find itself in iTunesU' do
13
- @connection.should_receive(:process).and_return(File.open(File.dirname(__FILE__) + '/../fixtures/responses/show_tree_course.xml'))
14
- @course = Course.find(1257981186, @connection)
15
- end
16
- end
15
+ it_should_behave_like "an Entity"
17
16
 
18
- describe ' after successful finding' do
19
- before(:all) do
20
- @connection.should_receive(:process).and_return(File.open(File.dirname(__FILE__) + '/../fixtures/responses/show_tree_course.xml'))
21
- @course = Course.find(1257981186, @connection)
22
- end
23
-
24
- it 'should access its attributes from the returned xml' do
25
- @course.Name.should eql('SI 539 001 W07')
26
- @course.Handle.should eql('1257981186')
27
- end
28
-
29
- it 'should find its parent element' do
30
- @course.parent.should be_an_instance_of(RTunesU::Section)
31
- end
32
-
33
- it 'should be able to find its groups (tabs)' do
34
- @course.Groups.should be_an_instance_of(Array)
35
- @course.Groups[0].should be_an_instance_of(RTunesU::Group)
36
- end
37
-
38
- it 'should be able to access it groups attributes' do
39
- @course.Groups[0].Handle.should eql('1257981189')
40
- end
41
-
42
- it 'should be able to access it groups tracks' do
43
- @course.Groups[0].Tracks.should be_an_instance_of(Array)
44
- @course.Groups[0].Tracks[0].should be_an_instance_of(RTunesU::Track)
45
- end
46
- end
17
+ it_should_be_composed_of :name, :instructor, :description, :identifier, :theme_handle, :short_name, :allow_subscription
18
+ it_should_be_composed_of_readonly :aggregate_file_size
19
+ it_should_have_many :permissions, :groups
47
20
  end
@@ -1,8 +1,18 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../entity_spec.rb'
2
3
  include RTunesU
3
4
 
4
5
  describe Division do
5
- it 'should find itself in iTunes U'
6
- it 'is valid'
7
- it 'converts itself to an xml document'
6
+ before(:each) do
7
+ @klass = Division
8
+ @entity = Division.new
9
+ @division = @entity
10
+ @attributes = {:name => 'Sample Division'}
11
+ end
12
+
13
+ it_should_behave_like "an Entity"
14
+
15
+ it_should_be_composed_of :name, :short_name, :identifier, :allow_subscription, :theme_handle, :description
16
+ it_should_be_composed_of_readonly :aggregate_file_size
17
+ it_should_have_many :permissions, :sections
8
18
  end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../entity_spec.rb'
3
+
4
+ include RTunesU
5
+
6
+ describe ExternalFeed do
7
+ before(:each) do
8
+ @klass = ExternalFeed
9
+ @entity = ExternalFeed.new
10
+ @external_feed = @entity
11
+ @attributes = {:owner_email => 'owner@exmaple.com'}
12
+ end
13
+
14
+ it_should_behave_like "an Entity with attribute assignment"
15
+ it_should_be_composed_of :polling_interval, :owner_email, :security_type, :signature_type, :basic_auth_username, :basic_auth_password
16
+
17
+ it "have a blank parent handle for polymorphism" do
18
+ @external_feed.parent_handle.should_not be_nil
19
+ @external_feed.parent_handle.should be_empty
20
+ end
21
+ end
@@ -1,8 +1,19 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../entity_spec.rb'
2
3
  include RTunesU
3
4
 
4
5
  describe Group do
5
- it 'should find itself in iTunes U'
6
- it 'is valid'
7
- it 'converts itself to an xml document'
6
+ before(:each) do
7
+ @klass = Group
8
+ @entity = Group.new
9
+ @group = @entity
10
+ @attributes = {:name => 'Sample Tab'}
11
+ end
12
+
13
+ it_should_behave_like "an Entity"
14
+
15
+ it_should_be_composed_of :name, :group_type, :short_name, :allow_subscription, :explicit
16
+ it_should_be_composed_of_readonly :aggregate_file_size
17
+ it_should_have_many :permissions, :tracks, :shared_objects
18
+ it_should_have_a :external_feed
8
19
  end
@@ -1,8 +1,17 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../entity_spec.rb'
3
+
2
4
  include RTunesU
3
5
 
4
6
  describe Permission do
5
- it 'should find itself in iTunes U'
6
- it 'is valid'
7
- it 'converts itself to an xml document'
7
+ before(:each) do
8
+ @klass = Permission
9
+ @entity = Permission.new
10
+ @permission = @entity
11
+ @attributes = {:credential => 'Administrator@urn:mace:itunesu.com:sites:example.edu'}
12
+ end
13
+
14
+ it_should_behave_like "an Entity with attribute assignment"
15
+ it_should_be_composed_of :credential, :access
16
+
8
17
  end
@@ -1,8 +1,37 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../entity_spec.rb'
3
+
2
4
  include RTunesU
3
5
 
4
6
  describe Section do
5
- it 'should find itself in iTunes U'
6
- it 'is valid'
7
- it 'converts itself to an xml document'
7
+ before(:each) do
8
+ @klass = Section
9
+ @entity = Section.new
10
+ @section = @entity
11
+ @attributes = {:name => 'Sample Course'}
12
+ end
13
+
14
+ it_should_behave_like "an Entity"
15
+
16
+ it_should_be_composed_of :name
17
+ it_should_have_many :courses
18
+
19
+ describe "converted to XML" do
20
+ before(:each) do
21
+ @document = Hpricot.XML(@section.to_xml)
22
+ end
23
+ it "should have SectionPath element" do
24
+ @document.at('SectionPath').should_not == nil
25
+ end
26
+
27
+ it "should have MergeByHandle element" do
28
+ @document.at('MergeByHandle').should_not == nil
29
+ @document.at('MergeByHandle').innerHTML.should == "false"
30
+ end
31
+
32
+ it "should have Destructive element" do
33
+ @document.at('Destructive').should_not == nil
34
+ @document.at('Destructive').innerHTML.should == "false"
35
+ end
36
+ end
8
37
  end
@@ -1,8 +1,21 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../entity_spec.rb'
3
+
2
4
  include RTunesU
3
5
 
4
6
  describe Site do
5
- it 'should find itself in iTunes U'
6
- it 'is valid'
7
- it 'converts itself to an xml document'
7
+ before(:each) do
8
+ @klass = Site
9
+ @entity = Site.new
10
+ @site = @entity
11
+ @attributes = {:name => 'Example University'}
12
+ end
13
+
14
+ it_should_behave_like "a findable Entity"
15
+ it_should_behave_like "an updateable Entity"
16
+ it_should_behave_like "an Entity with attribute assignment"
17
+
18
+ it "should not allow deletion" do
19
+ lambda {@site.delete}.should raise_error
20
+ end
8
21
  end
@@ -1,8 +1,37 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+ require File.dirname(__FILE__) + '/../entity_spec.rb'
3
+
2
4
  include RTunesU
3
5
 
4
6
  describe Track do
5
- it 'should find itself in iTunes U'
6
- it 'is valid'
7
- it 'converts itself to an xml document'
7
+ before(:each) do
8
+ @klass = Track
9
+ @entity = Track.new
10
+ @track = @entity
11
+ @attributes = {:name => 'Sample Lecture'}
12
+ end
13
+
14
+ # it_should_behave_like "a creatable Entity"
15
+ # it_should_behave_like "an updateable Entity"
16
+ # it_should_behave_like "a deleteable Entity"
17
+ it_should_behave_like "an Entity with attribute assignment"
18
+
19
+ describe "finding" do
20
+ before(:each) do
21
+ mock_connect!
22
+ FakeWeb.register_uri(:get,
23
+ "https://deimos.apple.com/WebObjects/Core.woa/API/GetUploadURL/example.edu.2394598528?credentials=Administrator%40urn%3Amace%3Aitunesu.com%3Asites%3Aexample.edu&identity=%22Admin%22+%3Cadmin%40example.edu%3E+%28admin%29+%5B0%5D&time=1214619134&signature=121a6cf76c9c5ecda41450d87e3394b9d02c570a5f76b2bd16287f860f068302&type=XMLControlFile",
24
+ :body => mock_upload_url_for_handle(1))
25
+ FakeWeb.register_uri(:post, mock_upload_url_for_handle(1), :body => response_for(Course, 'show', true))
26
+ end
27
+
28
+ after(:each) do
29
+ FakeWeb.clean_registry
30
+ end
31
+
32
+ it "should have an handle" do
33
+ lambda { Track.find(2449134252, 2394598528) }.should_not raise_error
34
+ end
35
+
36
+ end
8
37
  end
data/spec/entity_spec.rb CHANGED
@@ -1,108 +1,169 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper.rb'
2
2
  include RTunesU
3
-
4
- # describe Entity do
5
- # it 'finds itself in iTunes U'
6
- # it 'rasies an error if it cannot be found in iTunes U'
7
- #
8
- # it "saves to iTunes U"
9
- # it "appepts to saves if valid"
10
- # it "it won't attempt to save (and rasies an error) if it's missing require attributes"
11
- #
12
- # it "creates if it didn't previously exist"
13
- # it "updates if it previously existed"
14
- #
15
- # it "rasies an error if saving failed"
16
- #
17
- # it "deletes"
18
- # it "raises an error if delting failed"
19
- #
20
- # it "converts to an xml string"
21
- # it "creats from a ITunesU Response"
22
- # end
23
- describe Entity, 'attribute assignment' do
24
- before do
25
- @entity = Entity.new
26
- end
27
-
28
- it 'assigns singular attributes to the edits hash as a string' do
29
- @entity.Name = 'Eng211'
30
- @entity.edits['Name'].should eql('Eng211')
31
- @entity.Name.should eql('Eng211')
32
- end
33
-
34
- it 'returns a default empty array for plural attributes' do
35
- @entity.Groups.should eql([])
36
- @entity.edits['Groups'].should eql([])
3
+ shared_examples_for "an updateable Entity" do
4
+ describe "updating" do
5
+ before(:each) do
6
+ mock_connect!
7
+ @entity = @klass.new(@attributes)
8
+ @entity.instance_variable_set("@handle", '1')
9
+ @entity.parent_handle = '1'
10
+ end
11
+
12
+ it "should clear its edits" do
13
+ FakeWeb.register_uri(:post,
14
+ "https://deimos.apple.com/WebObjects/Core.woa/API/ProcessWebServicesDocument/example.edu?credentials=Administrator%40urn%3Amace%3Aitunesu.com%3Asites%3Aexample.edu&identity=%22Admin%22+%3Cadmin%40example.edu%3E+%28admin%29+%5B0%5D&time=1214619134&signature=121a6cf76c9c5ecda41450d87e3394b9d02c570a5f76b2bd16287f860f068302",
15
+ :body => response_for(@klass, 'update', true)
16
+ )
17
+ @entity.name = 'some name'
18
+ @entity.edits.should_not be_empty
19
+ @entity.save
20
+ @entity.edits.should be_empty
21
+ end
22
+
37
23
  end
38
24
 
39
- it 'assigns plural attribute to the edits hash an array' do
40
- @entity.Groups = [Group.new(:name => 'does not matter')]
41
- @entity.Groups.size.should be(1)
42
- @entity.edits['Groups'].size.should be(1)
43
- end
44
25
 
45
- it 'adds plural attributes with <<' do
46
- @entity.Groups = [Group.new(:name => 'does not matter')]
47
- @entity.Groups.size.should be(1)
48
- @entity.Groups << Group.new(:name => 'another group')
49
- @entity.edits['Groups'].size.should be(2)
26
+ end
27
+
28
+ shared_examples_for "a deleteable Entity" do
29
+ describe "deleting" do
30
+ before(:each) do
31
+ mock_connect!
32
+ @entity = @klass.new(@attributes)
33
+ @entity.instance_variable_set("@handle", '1')
34
+ @entity.parent_handle = '1'
35
+ end
36
+
37
+ it "should no longer have a handle" do
38
+ FakeWeb.register_uri(:post,
39
+ "https://deimos.apple.com/WebObjects/Core.woa/API/ProcessWebServicesDocument/example.edu?credentials=Administrator%40urn%3Amace%3Aitunesu.com%3Asites%3Aexample.edu&identity=%22Admin%22+%3Cadmin%40example.edu%3E+%28admin%29+%5B0%5D&time=1214619134&signature=121a6cf76c9c5ecda41450d87e3394b9d02c570a5f76b2bd16287f860f068302",
40
+ :body => response_for(@klass, 'delete', true)
41
+ )
42
+ @entity.delete
43
+ @entity.handle.should == nil
44
+ end
50
45
  end
51
46
  end
52
47
 
53
- describe Entity, 'converting to XML' do
54
- describe 'with nested elements' do
55
- before do
56
- @entity = Entity.new(:Name => 'Example')
57
- @entity.Groups = [Group.new(:Name => 'example group 1'), Group.new(:Name => 'example group 2', :Description => 'Blah, blah, blah')]
58
- @xml = @entity.to_xml
48
+ shared_examples_for "a findable Entity" do
49
+ describe "finding" do
50
+ before(:each) do
51
+ mock_connect!
59
52
  end
60
53
 
61
- it 'should contain nested XML edits' do
62
- (Hpricot.XML(@xml) / 'Entity/Group').size.should be(2)
54
+ after(:each) do
55
+ FakeWeb.clean_registry
63
56
  end
64
57
 
65
- it 'has nested elements that propely converted their singular attributes' do
66
- (Hpricot.XML(@xml) / 'Entity/Group')[0].at('Name').innerHTML.should eql('example group 1')
58
+ describe "with existing handle" do
59
+ it "should load external data into object" do
60
+ FakeWeb.register_uri(:get,
61
+ "https://deimos.apple.com/WebObjects/Core.woa/API/GetUploadURL/example.edu.1?credentials=Administrator%40urn%3Amace%3Aitunesu.com%3Asites%3Aexample.edu&identity=%22Admin%22+%3Cadmin%40example.edu%3E+%28admin%29+%5B0%5D&time=1214619134&signature=121a6cf76c9c5ecda41450d87e3394b9d02c570a5f76b2bd16287f860f068302&type=XMLControlFile",
62
+ :body => mock_upload_url_for_handle(1))
63
+ FakeWeb.register_uri(:post, mock_upload_url_for_handle(1), :body => response_for(@klass, 'show', true))
64
+ @entity = @klass.find(1)
65
+ end
67
66
  end
68
67
 
68
+ describe "with non-existant handle" do
69
+ it "should raise EntityNotFound" do
70
+ FakeWeb.register_uri(:get,
71
+ "https://deimos.apple.com/WebObjects/Core.woa/API/GetUploadURL/example.edu.1?credentials=Administrator%40urn%3Amace%3Aitunesu.com%3Asites%3Aexample.edu&identity=%22Admin%22+%3Cadmin%40example.edu%3E+%28admin%29+%5B0%5D&time=1214619134&signature=121a6cf76c9c5ecda41450d87e3394b9d02c570a5f76b2bd16287f860f068302&type=XMLControlFile",
72
+ :body => response_for(@klass, 'show', false),
73
+ :status => [404, "Not Found"]
74
+ )
75
+ lambda { @entity = @klass.find(1) }.should raise_error(EntityNotFound)
76
+ end
77
+ end
69
78
  end
70
79
  end
71
80
 
72
- describe Entity, 'loading from XML' do
73
- before do
74
- @source = File.read(File.dirname(__FILE__) + '/fixtures/responses/generic_entity_response.xml')
75
- @entity = Entity.new(:handle => 789)
76
- end
77
-
78
- it 'access attributes from XML source or from the edits hash' do
79
- @entity.load_from_xml(@source)
80
- @entity.Name.should eql('Example Entity Inside of A Section')
81
- @entity.Name = 'new test name'
82
- @entity.Name.should eql('new test name')
81
+ shared_examples_for "a creatable Entity" do
82
+ describe "creating" do
83
+ before(:each) do
84
+ mock_connect!
85
+ @entity = @klass.new(@attributes)
86
+ @entity.parent_handle = '1'
87
+ @entity.handle.should == nil
88
+ end
89
+
90
+ after(:each) do
91
+ FakeWeb.clean_registry
92
+ end
93
+
94
+ it "should not have a handle until saved" do
95
+ @entity.handle.should == nil
96
+ end
97
+
98
+ it "should obtain a handle from iTunes U when saved" do
99
+ FakeWeb.register_uri(:post,
100
+ "https://deimos.apple.com/WebObjects/Core.woa/API/ProcessWebServicesDocument/example.edu?credentials=Administrator%40urn%3Amace%3Aitunesu.com%3Asites%3Aexample.edu&identity=%22Admin%22+%3Cadmin%40example.edu%3E+%28admin%29+%5B0%5D&time=1214619134&signature=121a6cf76c9c5ecda41450d87e3394b9d02c570a5f76b2bd16287f860f068302",
101
+ :body => response_for(@klass, 'create', true)
102
+ )
103
+ @entity.save
104
+ @entity.handle.should_not == nil
105
+ end
106
+
107
+ it "should raise InvalidRecord if it cannot be saved" do
108
+ FakeWeb.register_uri(:post,
109
+ "https://deimos.apple.com/WebObjects/Core.woa/API/ProcessWebServicesDocument/example.edu?credentials=Administrator%40urn%3Amace%3Aitunesu.com%3Asites%3Aexample.edu&identity=%22Admin%22+%3Cadmin%40example.edu%3E+%28admin%29+%5B0%5D&time=1214619134&signature=121a6cf76c9c5ecda41450d87e3394b9d02c570a5f76b2bd16287f860f068302",
110
+ :body => response_for(@klass, 'create', false)
111
+ )
112
+ lambda { @entity.save }.should raise_error(CannotSave)
113
+ end
114
+
115
+ it "should clear its edits" do
116
+ FakeWeb.register_uri(:post,
117
+ "https://deimos.apple.com/WebObjects/Core.woa/API/ProcessWebServicesDocument/example.edu?credentials=Administrator%40urn%3Amace%3Aitunesu.com%3Asites%3Aexample.edu&identity=%22Admin%22+%3Cadmin%40example.edu%3E+%28admin%29+%5B0%5D&time=1214619134&signature=121a6cf76c9c5ecda41450d87e3394b9d02c570a5f76b2bd16287f860f068302",
118
+ :body => response_for(@klass, 'create', true)
119
+ )
120
+ @entity.name = 'some name'
121
+ @entity.edits.should_not be_empty
122
+ @entity.save
123
+ @entity.edits.should be_empty
124
+ end
83
125
  end
84
-
85
- it 'can reset its edits' do
86
- @entity.load_from_xml(@source)
87
- @entity.Name.should eql('Example Entity Inside of A Section')
88
- @entity.Name = 'new test name'
89
- @entity.Name.should eql('new test name')
90
- @entity.reload
91
- @entity.Name.should eql('Example Entity Inside of A Section')
126
+ end
127
+
128
+ shared_examples_for "an Entity with attribute assignment" do
129
+ it "should initialize with optional starting attributes" do
130
+ @entity = @klass.new(@attributes)
131
+ @attributes.each do |attr,value|
132
+ @entity.send(attr).should == value
133
+ end
92
134
  end
93
135
 
94
- it 'should find its appropriate node in the XML based on node name and <Handle> element' do
95
- @entity.load_from_xml(@source)
96
- @entity.source_xml.name.should eql('Entity')
97
- end
136
+ describe "accessing handle" do
137
+ describe "when handle instance variable is set" do
138
+ it "should return the handle" do
139
+ @entity.instance_variable_set("@handle", "1")
140
+ @entity.handle.should == "1"
141
+ end
142
+ end
98
143
 
99
- it 'should raise an EntityNotFound error if the specific entity cannot be found' do
100
- @entity.handle = 1
101
- lambda { @entity.load_from_xml(@source) }.should raise_error(EntityNotFound)
102
- end
103
-
104
- it 'should still be able to access its parent XML node' do
105
- @entity.load_from_xml(@source)
106
- @entity.source_xml.parent.name.should eql('Section')
144
+ describe "when handle instance variable is not set" do
145
+ it "should access the handle from source xml if availabe" do
146
+ @entity.source_xml = Hpricot.XML(<<-XML
147
+ <#{@klass.name.demodulize}>
148
+ <Handle>1</Handle>
149
+ </#{@klass.name.demodulize}>
150
+ XML
151
+ )
152
+ @entity.handle.should == "1"
153
+ end
154
+
155
+ it "should retrun nil if source xml doesn't contain handle" do
156
+ @entity.handle.should be_nil
157
+ end
158
+ end
107
159
  end
108
- end
160
+ end
161
+
162
+
163
+ shared_examples_for "an Entity" do
164
+ it_should_behave_like "a creatable Entity"
165
+ it_should_behave_like "a findable Entity"
166
+ it_should_behave_like "an updateable Entity"
167
+ it_should_behave_like "a deleteable Entity"
168
+ it_should_behave_like "an Entity with attribute assignment"
169
+ end
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ITunesUDocument>
3
+ <Version>1.1.1</Version>
4
+ <AddCourse>
5
+ <ParentHandle>123456789</ParentHandle>
6
+ <ParentPath></ParentPath>
7
+ <TemplateHandle>987654321</TemplateHandle>
8
+ <Course>
9
+ <Name>Introduction to the Humanities</Name>
10
+ <ShortName>HUM 211</ShortName>
11
+ <Identifier>identifier value</Identifier>
12
+ <Instructor>Dr. Jesse Sielaff</Instructor>
13
+ <Description>Lorem ipsum dolor sit amet</Description>
14
+ <AllowSubscription>true</AllowSubscription>
15
+ </Course>
16
+ </AddCourse>
17
+ </ITunesUDocument>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ITunesUDocument>
3
+ <Version>1.1.3</Version>
4
+ <AddDivision>
5
+ <ParentHandle>720939</ParentHandle>
6
+ <ParentPath></ParentPath>
7
+ <Division>
8
+ <Name>Example Division</Name>
9
+ </Division>
10
+ </AddDivision>
11
+ </ITunesUDocument>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ITunesUDocument>
3
+ <Version>1.1.3</Version>
4
+ <AddGroup>
5
+ <ParentHandle>2514401752</ParentHandle>
6
+ <ParentPath></ParentPath>
7
+ <Group>
8
+ <Name>Tab 1</Name>
9
+ </Group>
10
+ </AddGroup>
11
+ </ITunesUDocument>