superdupe 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/README.markdown +10 -0
  2. data/lib/superdupe/active_resource_extensions.rb +161 -0
  3. data/lib/superdupe/attribute_template.rb +71 -0
  4. data/lib/superdupe/cucumber_hooks.rb +16 -0
  5. data/lib/superdupe/custom_mocks.rb +116 -0
  6. data/lib/superdupe/database.rb +69 -0
  7. data/lib/superdupe/dupe.rb +534 -0
  8. data/lib/superdupe/hash_pruner.rb +37 -0
  9. data/lib/superdupe/log.rb +38 -0
  10. data/lib/superdupe/mock.rb +127 -0
  11. data/lib/superdupe/model.rb +59 -0
  12. data/lib/superdupe/network.rb +56 -0
  13. data/lib/superdupe/record.rb +42 -0
  14. data/lib/superdupe/rest_validation.rb +16 -0
  15. data/lib/superdupe/schema.rb +52 -0
  16. data/lib/superdupe/sequence.rb +20 -0
  17. data/lib/superdupe/singular_plural_detection.rb +9 -0
  18. data/lib/superdupe/string.rb +7 -0
  19. data/lib/superdupe/symbol.rb +3 -0
  20. data/lib/superdupe.rb +20 -0
  21. data/rails_generators/dupe/dupe_generator.rb +20 -0
  22. data/rails_generators/dupe/templates/custom_mocks.rb +4 -0
  23. data/rails_generators/dupe/templates/definitions.rb +9 -0
  24. data/rails_generators/dupe/templates/load_dupe.rb +9 -0
  25. data/spec/lib_specs/active_resource_extensions_spec.rb +141 -0
  26. data/spec/lib_specs/attribute_template_spec.rb +173 -0
  27. data/spec/lib_specs/database_spec.rb +163 -0
  28. data/spec/lib_specs/dupe_spec.rb +522 -0
  29. data/spec/lib_specs/hash_pruner_spec.rb +73 -0
  30. data/spec/lib_specs/log_spec.rb +78 -0
  31. data/spec/lib_specs/logged_request_spec.rb +22 -0
  32. data/spec/lib_specs/mock_definitions_spec.rb +58 -0
  33. data/spec/lib_specs/mock_spec.rb +194 -0
  34. data/spec/lib_specs/model_spec.rb +95 -0
  35. data/spec/lib_specs/network_spec.rb +130 -0
  36. data/spec/lib_specs/record_spec.rb +70 -0
  37. data/spec/lib_specs/rest_validation_spec.rb +17 -0
  38. data/spec/lib_specs/schema_spec.rb +109 -0
  39. data/spec/lib_specs/sequence_spec.rb +39 -0
  40. data/spec/lib_specs/string_spec.rb +31 -0
  41. data/spec/lib_specs/symbol_spec.rb +17 -0
  42. data/spec/spec_helper.rb +8 -0
  43. metadata +142 -0
@@ -0,0 +1,58 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Mock Definition Methods" do
4
+ before do
5
+ Dupe.reset
6
+ end
7
+
8
+ describe "Get" do
9
+ it "should require a url pattern that is a regex" do
10
+ proc { Get() }.should raise_error(ArgumentError)
11
+ proc { Get 'not a regexp' }.should raise_error(ArgumentError)
12
+ proc { Get %r{/some_url} }.should_not raise_error
13
+ end
14
+
15
+ it "should create and return a Dupe::Network::Mock of type :get" do
16
+ Dupe.network.mocks[:get].should be_empty
17
+ @book = Dupe.create :book, :label => 'rooby'
18
+ Dupe.network.mocks[:get].should_not be_empty
19
+ Dupe.network.mocks[:get].length.should == 2
20
+
21
+ mock = Get %r{/books/([^&]+)\.xml} do |label|
22
+ Dupe.find(:book) {|b| b.label == label}
23
+ end
24
+
25
+ Dupe.network.mocks[:get].length.should == 3
26
+ Dupe.network.mocks[:get].last.should == mock
27
+ Dupe.network.mocks[:get].last.url_pattern.should == %r{/books/([^&]+)\.xml}
28
+ book = Dupe.find(:book)
29
+ Dupe.network.request(:get, '/books/rooby.xml').should == book.to_xml_safe(:root => 'book')
30
+ end
31
+ end
32
+
33
+ describe "Post" do
34
+ it "should require a url pattern that is a regex" do
35
+ proc { Post() }.should raise_error(ArgumentError)
36
+ proc { Post 'not a regexp' }.should raise_error(ArgumentError)
37
+ proc { Post %r{/some_url} }.should_not raise_error
38
+ end
39
+
40
+ it "should create and return a Dupe::Network::Mock of type :post" do
41
+ @book = Dupe.create :book, :label => 'rooby'
42
+ Dupe.network.mocks[:post].should_not be_empty
43
+ Dupe.network.mocks[:post].length.should == 1
44
+
45
+ mock = Post %r{/books\.xml} do |post_data|
46
+ Dupe.create(:book, post_data)
47
+ end
48
+
49
+ Dupe.network.mocks[:post].length.should == 2
50
+ Dupe.network.mocks[:post].first.should == mock
51
+ Dupe.network.mocks[:post].first.url_pattern.should == %r{/books\.xml}
52
+ book_post = Dupe.create(:book, {:title => "Rooby", :label => "rooby"})
53
+ book_post.delete(:id)
54
+ book_response = Dupe.create(:book, {:title => "Rooby", :label => "rooby"})
55
+ Dupe.network.request(:post, '/books.xml', book_post).should == [Dupe.find(:book) {|b| b.id == 4}.to_xml_safe(:root => 'book'), "/books/4.xml"]
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,194 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Dupe::Network::Mock do
4
+ before do
5
+ Dupe.reset
6
+ end
7
+
8
+ describe "new" do
9
+ it "should require the url be a kind of regular expression" do
10
+ proc { Dupe::Network::Mock.new '', proc {} }.should raise_error(
11
+ ArgumentError,
12
+ "The URL pattern parameter must be a type of regular expression."
13
+ )
14
+ end
15
+
16
+ it "should set the, @url, and @response parameters accordingly" do
17
+ url_pattern = /\//
18
+ response = proc {}
19
+ mock = Dupe::Network::Mock.new url_pattern, response
20
+ mock.url_pattern.should == url_pattern
21
+ mock.response.should == response
22
+ end
23
+ end
24
+
25
+ describe "match?" do
26
+ it "should determine if a given string matches the mock's url pattern" do
27
+ url = %r{/blogs/(\d+).xml}
28
+ response = proc {}
29
+ mock = Dupe::Network::Mock.new url, response
30
+ mock.match?('/blogs/1.xml').should == true
31
+ mock.match?('/bogs/1.xml').should == false
32
+ end
33
+ end
34
+ end
35
+
36
+ describe Dupe::Network::GetMock do
37
+ before do
38
+ Dupe.reset
39
+ end
40
+
41
+ describe "mocked_response" do
42
+ describe "on a mock object whose response returns a Dupe.find with actual results" do
43
+ it "should convert the response result to xml" do
44
+ url_pattern = %r{/books/(\d+)\.xml}
45
+ response = proc {|id| Dupe.find(:book) {|b| b.id == id.to_i}}
46
+ book = Dupe.create :book
47
+ mock = Dupe::Network::GetMock.new url_pattern, response
48
+ mock.mocked_response('/books/1.xml').should == book.to_xml(:root => 'book')
49
+
50
+ proc { mock.mocked_response('/books/2.xml') }.should raise_error(Dupe::Network::GetMock::ResourceNotFoundError)
51
+
52
+ Dupe.define :author
53
+ mock = Dupe::Network::GetMock.new %r{/authors\.xml$}, proc {Dupe.find :authors}
54
+ mock.mocked_response('/authors.xml').should == [].to_xml(:root => 'results')
55
+ end
56
+
57
+ it "should add a request to the Dupe::Network#log" do
58
+ url_pattern = %r{/books/([a-zA-Z0-9-]+)\.xml}
59
+ response = proc {|label| Dupe.find(:book) {|b| b.label == label}}
60
+ book = Dupe.create :book, :label => 'rooby'
61
+ mock = Dupe::Network::GetMock.new url_pattern, response
62
+ Dupe.network.log.requests.length.should == 0
63
+ mock.mocked_response('/books/rooby.xml')
64
+ Dupe.network.log.requests.length.should == 1
65
+ end
66
+ end
67
+
68
+ describe "on a mock object whose response returns nil" do
69
+ it "should raise an error" do
70
+ url_pattern = %r{/authors/(\d+)\.xml}
71
+ response = proc { |id| Dupe.find(:author) {|a| a.id == id.to_i}}
72
+ Dupe.define :author
73
+ mock = Dupe::Network::GetMock.new url_pattern, response
74
+ proc {mock.mocked_response('/authors/1.xml')}.should raise_error(Dupe::Network::GetMock::ResourceNotFoundError)
75
+ end
76
+ end
77
+
78
+ describe "on a mock object whose response returns an empty array" do
79
+ it "should convert the empty array to an xml array record set with root 'results'" do
80
+ Dupe.define :author
81
+ mock = Dupe::Network::GetMock.new %r{/authors\.xml$}, proc {Dupe.find :authors}
82
+ mock.mocked_response('/authors.xml').should == [].to_xml(:root => 'results')
83
+ end
84
+
85
+ it "should add a request to the Dupe::Network#log" do
86
+ Dupe.define :author
87
+ mock = Dupe::Network::GetMock.new %r{/authors\.xml$}, proc {Dupe.find :authors}
88
+ Dupe.network.log.requests.length.should == 0
89
+ mock.mocked_response('/authors.xml')
90
+ Dupe.network.log.requests.length.should == 1
91
+ end
92
+ end
93
+
94
+ describe "on a mock object whose response returns an array of duped records" do
95
+ it "should convert the array to xml" do
96
+ Dupe.create :author
97
+ mock = Dupe::Network::GetMock.new %r{/authors\.xml$}, proc {Dupe.find :authors}
98
+ mock.mocked_response('/authors.xml').should == Dupe.find(:authors).to_xml(:root => 'authors')
99
+ end
100
+
101
+ it "should add a request to the Dupe::Network#log" do
102
+ Dupe.create :author
103
+ mock = Dupe::Network::GetMock.new %r{/authors\.xml$}, proc {Dupe.find :authors}
104
+ Dupe.network.log.requests.length.should == 0
105
+ mock.mocked_response('/authors.xml')
106
+ Dupe.network.log.requests.length.should == 1
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ describe Dupe::Network::PostMock do
113
+ before do
114
+ Dupe.reset
115
+ end
116
+
117
+ describe "mocked_response" do
118
+ describe "on a mock object whose response returns a location of a new record" do
119
+ it "should convert the new post to xml" do
120
+ Dupe.define :author
121
+ mock = Dupe::Network::PostMock.new %r{/authors\.xml$}, proc {|post_data| Dupe.create(:author, post_data)}
122
+ resp, url = mock.mocked_response('/authors.xml', {:name => "Rachel"})
123
+ resp.should == Dupe.find(:authors).first.to_xml_safe(:root => 'author')
124
+ url.should == "/authors/1.xml"
125
+ end
126
+
127
+ it "should add a request to the Dupe::Network#log" do
128
+ Dupe.define :author
129
+ mock = Dupe::Network::PostMock.new %r{/authors\.xml$}, proc {|post_data| Dupe.create(:author, post_data)}
130
+ Dupe.network.log.requests.length.should == 0
131
+ mock.mocked_response('/authors.xml', {:name => "Rachel"})
132
+ Dupe.network.log.requests.length.should == 1
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ describe Dupe::Network::PutMock do
139
+ before do
140
+ Dupe.reset
141
+ end
142
+
143
+ describe "mocked_response" do
144
+ describe "on a mock object whose response returns a location of a new record" do
145
+ before do
146
+ Dupe.define :author
147
+ @a = Dupe.create :author, :name => "Matt"
148
+ @mock = Dupe::Network::PutMock.new %r{/authors/(\d+)\.xml$}, proc {|id, put_data| Dupe.find(:author) {|a| a.id == id.to_i}.merge!(put_data)}
149
+ end
150
+
151
+ it "should convert the put to xml" do
152
+ resp, url = @mock.mocked_response('/authors/1.xml', {:name => "Rachel"})
153
+ resp.should == nil
154
+ @a.name.should == "Rachel"
155
+ url.should == "/authors/1.xml"
156
+ end
157
+
158
+ it "should add a request to the Dupe::Network#log" do
159
+ Dupe.network.log.requests.length.should == 0
160
+ @mock.mocked_response('/authors/1.xml', {:name => "Rachel"})
161
+ Dupe.network.log.requests.length.should == 1
162
+ end
163
+ end
164
+ end
165
+ end
166
+
167
+ describe Dupe::Network::DeleteMock do
168
+ before do
169
+ Dupe.reset
170
+ end
171
+
172
+ describe "mocked_response" do
173
+ describe "on a mock object whose response returns a location of a new record" do
174
+ before do
175
+ Dupe.define :author
176
+ @a = Dupe.create :author, :name => "Matt"
177
+ @mock = Dupe::Network::DeleteMock.new %r{/authors/(\d+)\.xml$}, proc {|id| Dupe.delete(:author) {|a| a.id == id.to_i}}
178
+ end
179
+
180
+ it "should convert the put to xml" do
181
+ Dupe.find(:authors).length.should == 1
182
+ resp = @mock.mocked_response('/authors/1.xml')
183
+ resp.should == nil
184
+ Dupe.find(:authors).length.should == 0
185
+ end
186
+
187
+ it "should add a request to the Dupe::Network#log" do
188
+ Dupe.network.log.requests.length.should == 0
189
+ @mock.mocked_response('/authors/1.xml')
190
+ Dupe.network.log.requests.length.should == 1
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,95 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Dupe::Model do
4
+ describe "new" do
5
+ it "should require a model name" do
6
+ proc { Dupe::Model.new }.should raise_error(ArgumentError)
7
+ end
8
+
9
+ it "should set the model name to what was passed in during initialization" do
10
+ m = Dupe::Model.new :book
11
+ m.name.should == :book
12
+ end
13
+
14
+ it "should initialize an empty schema" do
15
+ m = Dupe::Model.new :book
16
+ m.schema.should be_kind_of(Dupe::Model::Schema)
17
+ end
18
+
19
+ it "should setup an id_sequence initialized to 0" do
20
+ m = Dupe::Model.new :book
21
+ m.id_sequence.current_value.should == 1
22
+ end
23
+ end
24
+
25
+ describe "define" do
26
+ describe "when passed a proc" do
27
+ before do
28
+ @model = Dupe::Model.new :book
29
+ @definition = proc { |attrs|
30
+ attrs.author('Anonymous') do |dont_care|
31
+ 'Flying Spaghetti Monster'
32
+ end
33
+ }
34
+ end
35
+
36
+ it "should pass that proc off to it's schema" do
37
+ @model.schema.should_receive(:method_missing).once
38
+ @model.define @definition
39
+ end
40
+
41
+ it "should result in a schema with the desired attribute templates" do
42
+ @model.define @definition
43
+ @model.schema.attribute_templates[:author].name.should == :author
44
+ @model.schema.attribute_templates[:author].default.should == 'Anonymous'
45
+ @model.schema.attribute_templates[:author].transformer.call(
46
+ 'dont care'
47
+ ).should == 'Flying Spaghetti Monster'
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "create" do
53
+ before do
54
+ Dupe.define :book do |attrs|
55
+ attrs.title 'Untitled'
56
+ attrs.author 'Anon' do |author|
57
+ "Author: #{author}"
58
+ end
59
+ attrs.after_create do |book|
60
+ book.label = book.title.downcase.gsub(/\ +/, '-')
61
+ end
62
+ end
63
+
64
+ @book_model = Dupe.models[:book]
65
+ end
66
+
67
+ it "shouldn't require any parameters" do
68
+ proc {
69
+ @book_model.create
70
+ }.should_not raise_error
71
+ end
72
+
73
+ it "should return a Dupe::Database::Record instance with the desired parameters" do
74
+ book = @book_model.create
75
+ book.should be_kind_of(Dupe::Database::Record)
76
+ book.__model__.name.should == :book
77
+ book.id.should == 1
78
+ book.title.should == 'Untitled'
79
+ book.author.should == 'Anon'
80
+
81
+ # the callback shouldn't get run until the database record is inserted into the duped 'database'
82
+ book.label.should == nil
83
+
84
+ book = @book_model.create :title => 'Rooby On Rails', :author => 'Matt Parker'
85
+ book.__model__.name.should == :book
86
+ book.id.should == 2
87
+ book.title.should == 'Rooby On Rails'
88
+
89
+ # the callback shouldn't get run until the database record is inserted into the duped 'database'
90
+ book.label.should == nil
91
+
92
+ book.author.should == 'Author: Matt Parker'
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,130 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Dupe::Network do
4
+
5
+ describe "new" do
6
+ before do
7
+ @network = Dupe::Network.new
8
+ end
9
+
10
+ it "should initialize @mocks to a hash of empty arrays keyed with valid REST verbs" do
11
+ Dupe::Network::VERBS.each do |verb|
12
+ @network.mocks[verb].should == []
13
+ end
14
+ end
15
+
16
+ it "should initialize @log to a new Dupe::Network::Log" do
17
+ @network.log.should be_kind_of(Dupe::Network::Log)
18
+ end
19
+ end
20
+
21
+ describe "request" do
22
+ before do
23
+ @network = Dupe::Network.new
24
+ end
25
+
26
+ it "should require a valid REST verb" do
27
+ proc { @network.request }.should raise_error
28
+ proc { @network.request :invalid_rest_verb, '/some_url' }.should raise_error(Dupe::Network::UnknownRestVerbError)
29
+ proc { @network.request :get, '/some_url' }.should_not raise_error(Dupe::Network::UnknownRestVerbError)
30
+ proc { @network.request :post, '/some_url', 'some body' }.should_not raise_error(Dupe::Network::UnknownRestVerbError)
31
+ proc { @network.request :put, '/some_url' }.should_not raise_error(Dupe::Network::UnknownRestVerbError)
32
+ proc { @network.request :delete, '/some_url' }.should_not raise_error(Dupe::Network::UnknownRestVerbError)
33
+ end
34
+
35
+ it "should require a URL" do
36
+ proc { @network.request :get }.should raise_error(ArgumentError)
37
+ proc { @network.request :get, 'some_url'}.should_not raise_error(ArgumentError)
38
+ proc { @network.request :post, 'some_url', 'some body'}.should_not raise_error(ArgumentError)
39
+ proc { @network.request :put, 'some_url'}.should_not raise_error(ArgumentError)
40
+ proc { @network.request :delete, 'some_url'}.should_not raise_error(ArgumentError)
41
+ end
42
+
43
+ it "should raise an exception if the network has no mocks that match the url" do
44
+ proc { @network.request(:get, '/some_url')}.should raise_error(Dupe::Network::RequestNotFoundError)
45
+ proc { @network.request(:post, '/some_url', 'some body')}.should raise_error(Dupe::Network::RequestNotFoundError)
46
+ proc { @network.request(:put, '/some_url')}.should raise_error(Dupe::Network::RequestNotFoundError)
47
+ proc { @network.request(:delete, '/some_url')}.should raise_error(Dupe::Network::RequestNotFoundError)
48
+ end
49
+
50
+ it "should return the appropriate mock response if a mock matches the url" do
51
+ @network.define_service_mock :get, %r{/greeting$}, proc { "hello" }
52
+ @network.request(:get, '/greeting').should == 'hello'
53
+
54
+ @network.define_service_mock :post, %r{/greeting$}, proc { |post_data| Dupe.create(:greeting, post_data) }
55
+ resp, url = @network.request(:post, '/greeting', {} )
56
+ resp.should == Dupe.find(:greeting).to_xml_safe(:root => 'greeting')
57
+ url.should == "/greetings/1.xml"
58
+ end
59
+ end
60
+
61
+ describe "define_service_mock" do
62
+ before do
63
+ @network = Dupe::Network.new
64
+ end
65
+
66
+ it "should require a valid REST verb" do
67
+ proc { @network.define_service_mock }.should raise_error
68
+ proc { @network.define_service_mock :invalid_rest_verb, // }.should raise_error(Dupe::Network::UnknownRestVerbError)
69
+ proc { @network.define_service_mock :get, // }.should_not raise_error(Dupe::Network::UnknownRestVerbError)
70
+ proc { @network.define_service_mock :post, // }.should_not raise_error(Dupe::Network::UnknownRestVerbError)
71
+ proc { @network.define_service_mock :put, // }.should_not raise_error(Dupe::Network::UnknownRestVerbError)
72
+ end
73
+
74
+ it "should require a valid Regexp url pattern" do
75
+ proc { @network.define_service_mock :get, 'not a regular expression' }.should raise_error(ArgumentError)
76
+ proc { @network.define_service_mock :post, 'not a regular expression' }.should raise_error(ArgumentError)
77
+ proc { @network.define_service_mock :get, // }.should_not raise_error
78
+ proc { @network.define_service_mock :post, // }.should_not raise_error
79
+ end
80
+
81
+ it "should create and return a new get service mock when given valid parameters" do
82
+ verb = :get
83
+ pattern = //
84
+ response = proc { 'test' }
85
+ @network.mocks[:get].should be_empty
86
+ mock = @network.define_service_mock verb, pattern, response
87
+ @network.mocks[:get].should_not be_empty
88
+ @network.mocks[:get].first.class.should == Dupe::Network::GetMock
89
+ @network.mocks[:get].length.should == 1
90
+ @network.mocks[:get].first.should == mock
91
+ end
92
+
93
+ it "should create and return a new post service mock when given valid parameters" do
94
+ verb = :post
95
+ pattern = //
96
+ response = proc { 'test' }
97
+ @network.mocks[:post].should be_empty
98
+ mock = @network.define_service_mock verb, pattern, response
99
+ @network.mocks[:post].should_not be_empty
100
+ @network.mocks[:post].first.class.should == Dupe::Network::PostMock
101
+ @network.mocks[:post].length.should == 1
102
+ @network.mocks[:post].first.should == mock
103
+ end
104
+
105
+ it "should create and return a new put service mock when given valid parameters" do
106
+ verb = :put
107
+ pattern = //
108
+ response = proc { 'test' }
109
+ @network.mocks[:put].should be_empty
110
+ mock = @network.define_service_mock verb, pattern, response
111
+ @network.mocks[:put].should_not be_empty
112
+ @network.mocks[:put].first.class.should == Dupe::Network::PutMock
113
+ @network.mocks[:put].length.should == 1
114
+ @network.mocks[:put].first.should == mock
115
+ end
116
+
117
+ it "should create and return a new delete service mock when given valid parameters" do
118
+ verb = :delete
119
+ pattern = //
120
+ response = proc { 'test' }
121
+ @network.mocks[:delete].should be_empty
122
+ mock = @network.define_service_mock verb, pattern, response
123
+ @network.mocks[:delete].should_not be_empty
124
+ @network.mocks[:delete].first.class.should == Dupe::Network::DeleteMock
125
+ @network.mocks[:delete].length.should == 1
126
+ @network.mocks[:delete].first.should == mock
127
+ end
128
+ end
129
+
130
+ end
@@ -0,0 +1,70 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Dupe::Database::Record do
4
+ describe "new" do
5
+ it "should create an object that is a kind of Hash" do
6
+ Dupe::Database::Record.new.should be_kind_of(Hash)
7
+ end
8
+ end
9
+
10
+ describe "id" do
11
+ it "should allow us to set the record id (and not the object id)" do
12
+ d = Dupe::Database::Record.new
13
+ d.id.should == nil
14
+ d[:id].should == nil
15
+ d.id = 1
16
+ d.id.should == 1
17
+ d[:id].should == 1
18
+ end
19
+ end
20
+
21
+ describe "method_missing" do
22
+ it "should allow us to access hash keys as if they were object attributes" do
23
+ d = Dupe::Database::Record.new
24
+ d[:some_key].should == nil
25
+ d.some_key.should == nil
26
+ d.some_key = 1
27
+ d.some_key.should == 1
28
+ d[:some_key].should == 1
29
+ d[:another_key] = 2
30
+ d.another_key.should == 2
31
+ d[:another_key].should == 2
32
+ end
33
+ end
34
+
35
+ describe "inspect" do
36
+ it "should show the class name" do
37
+ d = Dupe::Database::Record.new
38
+ d.inspect.should match(/^<#Dupe::Database::Record/)
39
+ end
40
+
41
+ it "should show the key/value pairs as attributes" do
42
+ d = Dupe::Database::Record.new
43
+ d.title = 'test'
44
+ d.inspect.should match(/title="test"/)
45
+ d.author = Dupe::Database::Record.new
46
+ d.inspect.should match(/author=<#Dupe::Database::Record/)
47
+ end
48
+
49
+ it "should show Fake::<model_name> when the record has a model" do
50
+ b = Dupe.create :book
51
+ b.inspect.should match(/^<#Duped::Book/)
52
+ b.author = Dupe.create :author
53
+ b.inspect.should match(/^<#Duped::Book/)
54
+ b.inspect.should match(/author=<#Duped::Author/)
55
+ end
56
+ end
57
+
58
+ describe "__model__" do
59
+ it "should have a __model__ instance variable" do
60
+ proc {Dupe::Database::Record.new.__model__}.should_not raise_error
61
+ end
62
+
63
+ it "should all you to set the __model_name__ instance variable" do
64
+ r = Dupe::Database::Record.new
65
+ proc {r.__model__ = :book}.should_not raise_error
66
+ r.__model__.should == :book
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Dupe::Network::RestValidation do
4
+ before do
5
+ class TestRestValidation
6
+ include Dupe::Network::RestValidation
7
+ end
8
+ end
9
+
10
+ describe "validate_request_type" do
11
+ it "should raise an exception if the request type isn't :get, :post, :put, or :delete" do
12
+ proc {
13
+ TestRestValidation.new.validate_request_type(:unknown_request_type)
14
+ }.should raise_error(Dupe::Network::UnknownRestVerbError)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,109 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Dupe::Model::Schema do
4
+ describe "new" do
5
+ it "should initialize attribute_templates to an empty hash" do
6
+ Dupe::Model::Schema.new.attribute_templates.should == {}
7
+ end
8
+
9
+ it "should initialize after_create_callbacks to an empty array" do
10
+ Dupe::Model::Schema.new.after_create_callbacks.should == []
11
+ end
12
+ end
13
+
14
+ describe "dynamic attribute_template creation methods" do
15
+ before do
16
+ @schema = Dupe::Model::Schema.new
17
+ end
18
+
19
+ describe "called with no parameters" do
20
+ it "should create a new attribute template with no transformer and no default value" do
21
+ @schema.title
22
+ @schema.attribute_templates[:title].should be_kind_of(Dupe::Model::Schema::AttributeTemplate)
23
+ @schema.attribute_templates[:title].name.should == :title
24
+ @schema.attribute_templates[:title].default.should be_nil
25
+ @schema.attribute_templates[:title].transformer.should be_nil
26
+ end
27
+ end
28
+
29
+ describe "called with a single parameter, but no block" do
30
+ it "should create a new attribute template with a default value but no transformer" do
31
+ @schema.title 'Untitled'
32
+ @schema.attribute_templates[:title].should be_kind_of(Dupe::Model::Schema::AttributeTemplate)
33
+ @schema.attribute_templates[:title].name.should == :title
34
+ @schema.attribute_templates[:title].default.should == 'Untitled'
35
+ @schema.attribute_templates[:title].transformer.should be_nil
36
+ end
37
+ end
38
+
39
+ describe "called with a block that accepts a parameter" do
40
+ it "should create a new attribute template without a default value, but with a tranformer" do
41
+ @schema.title {|dont_care| 'test'}
42
+ @schema.attribute_templates[:title].should be_kind_of(Dupe::Model::Schema::AttributeTemplate)
43
+ @schema.attribute_templates[:title].name.should == :title
44
+ @schema.attribute_templates[:title].default.should be_nil
45
+ @schema.attribute_templates[:title].transformer.should be_kind_of(Proc)
46
+ end
47
+ end
48
+
49
+ describe "called with a block that doesn't accept a parameter" do
50
+ it "should create a new attribute template without a transformer, and with the block as the default value" do
51
+ @schema.title { 'knock' * 3 }
52
+ @schema.attribute_templates[:title].should be_kind_of(Dupe::Model::Schema::AttributeTemplate)
53
+ @schema.attribute_templates[:title].name.should == :title
54
+ @schema.attribute_templates[:title].default.should be_kind_of(Proc)
55
+ @schema.attribute_templates[:title].default.call.should == "knockknockknock"
56
+ @schema.attribute_templates[:title].transformer.should be_nil
57
+ end
58
+ end
59
+
60
+ describe "called with a block and a parameter" do
61
+ it "should create a new attribute template with a default value AND with a tranformer" do
62
+ @schema.title('Untitled') {|dont_care| 'test'}
63
+ @schema.attribute_templates[:title].should be_kind_of(Dupe::Model::Schema::AttributeTemplate)
64
+ @schema.attribute_templates[:title].name.should == :title
65
+ @schema.attribute_templates[:title].default.should == 'Untitled'
66
+ @schema.attribute_templates[:title].transformer.should be_kind_of(Proc)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#after_create" do
72
+ before do
73
+ @schema = Dupe::Model::Schema.new
74
+ end
75
+
76
+ it "should require a block that accepts a single parameter" do
77
+ proc { @schema.after_create }.should raise_error(ArgumentError)
78
+ proc { @schema.after_create { "parameterless block" } }.should raise_error(ArgumentError)
79
+ proc { @schema.after_create {|s| s.title = 'test' } }.should_not raise_error
80
+ end
81
+
82
+ it "should add the callback to the list of after_create_callbacks" do
83
+ @schema.after_create_callbacks.should be_empty
84
+ @schema.after_create {|s| s.title = 'test'}
85
+ @schema.after_create_callbacks.length.should == 1
86
+ @schema.after_create_callbacks.first.should be_kind_of(Proc)
87
+ end
88
+
89
+ end
90
+
91
+ describe "#uniquify" do
92
+ before do
93
+ @schema = Dupe::Model::Schema.new
94
+ end
95
+
96
+ it "should only accept a list of symbols" do
97
+ proc { @schema.uniquify }.should raise_error(ArgumentError, "You must pass at least one attribute to uniquify.")
98
+ proc { @schema.uniquify :hash => 'value' }.should raise_error(ArgumentError, "You may only pass symbols to uniquify.")
99
+ proc { @schema.uniquify :one, :two}.should_not raise_error
100
+ end
101
+
102
+ it "should create after_create_callbacks for each symbol passed to it" do
103
+ @schema.after_create_callbacks.should be_empty
104
+ @schema.uniquify :title, :label
105
+ @schema.after_create_callbacks.length.should == 2
106
+ @schema.after_create_callbacks.first.should be_kind_of(Proc)
107
+ end
108
+ end
109
+ end