amazon-associates 0.6.3

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 (50) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG +29 -0
  3. data/LICENSE +21 -0
  4. data/README.rdoc +84 -0
  5. data/Rakefile +62 -0
  6. data/VERSION.yml +5 -0
  7. data/amazon-associates.gemspec +118 -0
  8. data/lib/amazon-associates.rb +90 -0
  9. data/lib/amazon-associates/caching/filesystem_cache.rb +121 -0
  10. data/lib/amazon-associates/errors.rb +23 -0
  11. data/lib/amazon-associates/extensions/core.rb +31 -0
  12. data/lib/amazon-associates/extensions/hpricot.rb +115 -0
  13. data/lib/amazon-associates/request.rb +143 -0
  14. data/lib/amazon-associates/requests/browse_node.rb +10 -0
  15. data/lib/amazon-associates/requests/cart.rb +81 -0
  16. data/lib/amazon-associates/requests/item.rb +13 -0
  17. data/lib/amazon-associates/responses/browse_node_lookup_response.rb +10 -0
  18. data/lib/amazon-associates/responses/cart_responses.rb +26 -0
  19. data/lib/amazon-associates/responses/item_lookup_response.rb +16 -0
  20. data/lib/amazon-associates/responses/item_search_response.rb +20 -0
  21. data/lib/amazon-associates/responses/response.rb +27 -0
  22. data/lib/amazon-associates/responses/similarity_lookup_response.rb +9 -0
  23. data/lib/amazon-associates/types/api_result.rb +8 -0
  24. data/lib/amazon-associates/types/browse_node.rb +48 -0
  25. data/lib/amazon-associates/types/cart.rb +87 -0
  26. data/lib/amazon-associates/types/customer_review.rb +15 -0
  27. data/lib/amazon-associates/types/editorial_review.rb +8 -0
  28. data/lib/amazon-associates/types/error.rb +8 -0
  29. data/lib/amazon-associates/types/image.rb +37 -0
  30. data/lib/amazon-associates/types/image_set.rb +11 -0
  31. data/lib/amazon-associates/types/item.rb +156 -0
  32. data/lib/amazon-associates/types/listmania_list.rb +9 -0
  33. data/lib/amazon-associates/types/measurement.rb +47 -0
  34. data/lib/amazon-associates/types/offer.rb +10 -0
  35. data/lib/amazon-associates/types/ordinal.rb +24 -0
  36. data/lib/amazon-associates/types/price.rb +29 -0
  37. data/lib/amazon-associates/types/requests.rb +50 -0
  38. data/spec/requests/browse_node_lookup_spec.rb +41 -0
  39. data/spec/requests/item_search_spec.rb +27 -0
  40. data/spec/spec_helper.rb +8 -0
  41. data/spec/types/cart_spec.rb +294 -0
  42. data/spec/types/item_spec.rb +55 -0
  43. data/spec/types/measurement_spec.rb +43 -0
  44. data/test/amazon/browse_node_test.rb +34 -0
  45. data/test/amazon/cache_test.rb +33 -0
  46. data/test/amazon/caching/filesystem_cache_test.rb +198 -0
  47. data/test/amazon/item_test.rb +397 -0
  48. data/test/test_helper.rb +9 -0
  49. data/test/utilities/filesystem_test_helper.rb +35 -0
  50. metadata +216 -0
@@ -0,0 +1,55 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Amazon
4
+ module Associates
5
+ describe Item do
6
+ before(:all) do
7
+ @item = Amazon::Associates::item_lookup("0545010225").item
8
+ end
9
+
10
+ it "should equal anything with the same #asin" do
11
+ asin = @item.asin
12
+ @item.should == Struct.new(:asin).new(asin)
13
+ end
14
+
15
+ describe "query for items", :shared => true do
16
+ it "should return a list of items" do
17
+ @result.should have_at_least(10).items
18
+ @result.each {|item| item.should be_an_instance_of(Item) }
19
+ end
20
+ end
21
+
22
+ describe "query for related items", :shared => true do
23
+ it_should_behave_like "query for items"
24
+ it "should not include the item related to the result" do
25
+ @result.should_not include(@item)
26
+ end
27
+ end
28
+
29
+ describe ".similar" do
30
+ before(:all) do
31
+ @result = Item.similar(@item.asin)
32
+ end
33
+ it_should_behave_like "query for related items"
34
+ end
35
+
36
+ describe ".all" do
37
+ before(:all) do
38
+ @result = Item.all("search_index"=>"Blended", "keywords"=>"potter")
39
+ end
40
+ it_should_behave_like "query for items"
41
+
42
+ it "should handle hashes with indifferent access" do
43
+ Item.all(HashWithIndifferentAccess.new("search_index"=>"Blended", "keywords"=>"hello")).should_not == nil
44
+ end
45
+ end
46
+
47
+ describe "#similar" do
48
+ before(:all) do
49
+ @result = @item.similar
50
+ end
51
+ it_should_behave_like "query for related items"
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "measurement object", :shared => true do
4
+ it "should take a quantity and units" do
5
+ m = measurement_with(:value => 11.3, :units => 'inches')
6
+ m.value.should == 11.3
7
+ m.units.should == 'inches'
8
+ end
9
+
10
+ it "should default units to 'pixels', as we use it mostly for images" do
11
+ m = measurement_with(:value => 22.19)
12
+ m.value.should == 22.19
13
+ m.units.should == 'pixels'
14
+ end
15
+
16
+ it "should translate 'hundredths-' units to standard quantities" do
17
+ m = measurement_with(:value => 1130, :units => 'hundredths-inches')
18
+ m.value.should == 11.3
19
+ m.units.should == 'inches'
20
+ end
21
+ end
22
+
23
+ describe Amazon::Associates::Measurement do
24
+ describe "#initialize" do
25
+ def measurement_with(opts)
26
+ Amazon::Associates::Measurement.new(*opts.values_at(:value, :units).compact)
27
+ end
28
+
29
+ it_should_behave_like "measurement object"
30
+ end
31
+
32
+ describe "#from_xml" do
33
+ def measurement_with(opts)
34
+ doc = ROXML::XML::Document.new
35
+ doc.root = ROXML::XML::Node.new('width', doc)
36
+ doc.root.add_child( Nokogiri::XML::Text.new(opts[:value].to_s, doc))
37
+ doc.root['Units'] = opts[:units] unless opts[:units].blank?
38
+ Amazon::Associates::Measurement.from_xml(doc.root)
39
+ end
40
+
41
+ it_should_behave_like "measurement object"
42
+ end
43
+ end
@@ -0,0 +1,34 @@
1
+ require File.dirname(__FILE__) + "/../test_helper"
2
+
3
+ class Amazon::Associates::BrowseNodeLookupTest < Test::Unit::TestCase
4
+ include FilesystemTestHelper
5
+
6
+ def setup
7
+ set_valid_caching_options
8
+ end
9
+
10
+ def test_browse_node_lookup_with_invalid_request
11
+ assert_raise(Amazon::Associates::RequiredParameterMissing) do
12
+ Amazon::Associates.browse_node_lookup(nil)
13
+ end
14
+ end
15
+
16
+ def test_browse_node_lookup_with_no_result
17
+ assert_raise(Amazon::Associates::InvalidParameterValue) do
18
+ Amazon::Associates.browse_node_lookup("abc")
19
+ end
20
+ end
21
+
22
+ def test_items_have_browsenodes
23
+ item = Amazon::Associates.item_lookup('B000ROI682', :response_group => 'BrowseNodes').items.first
24
+ assert item.browse_nodes.size > 1
25
+ item.browse_nodes.each do |browsenode|
26
+ assert_kind_of Amazon::Associates::BrowseNode, browsenode
27
+ assert !browsenode.to_s.include?('&amp;'), browsenode.to_s
28
+ end
29
+ end
30
+
31
+ def test_browse_nodes_have_top_sellers
32
+ assert !Amazon::Associates.browse_node_lookup(:response_group => 'TopSellers', :browse_node_id => 493964).browse_nodes.first.top_sellers.empty?
33
+ end
34
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + "/../test_helper"
2
+
3
+ module Amazon
4
+ module Associates
5
+ class CacheTest < Test::Unit::TestCase
6
+ include FilesystemTestHelper
7
+ context "caching get" do
8
+ setup do
9
+ set_valid_caching_options(CACHE_TEST_PATH)
10
+ end
11
+
12
+ teardown do
13
+ reset_cache
14
+ end
15
+
16
+ should "optionally allow for a caching strategy in configuration" do
17
+ assert_nothing_raised do
18
+ set_valid_caching_options(CACHE_TEST_PATH)
19
+ end
20
+ assert Amazon::Associates.caching_enabled?
21
+ end
22
+
23
+ should "raise an exception if a caching strategy is specified that is not found" do
24
+ assert_raise Amazon::Associates::ConfigurationError do
25
+ Amazon::Associates.configure do |options|
26
+ options[:caching_strategy] = "foo"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,198 @@
1
+ require File.dirname(__FILE__) + "/../../test_helper"
2
+
3
+ module Amazon
4
+ module Associates
5
+ class FilesystemCacheTest < Test::Unit::TestCase
6
+ include FilesystemTestHelper
7
+ context "setting up filesystem caching" do
8
+ teardown do
9
+ Amazon::Associates.configure do |options|
10
+ options[:caching_strategy] = nil
11
+ options[:caching_options] = nil
12
+ end
13
+ end
14
+
15
+ should "require a caching options hash with a cache_path key" do
16
+ assert_raise Amazon::Associates::ConfigurationError do
17
+ Amazon::Associates.configure do |options|
18
+ options[:caching_strategy] = :filesystem
19
+ options[:caching_options] = nil
20
+ end
21
+ end
22
+ end
23
+
24
+ should "raise an exception when a cache_path is specified that doesn't exist" do
25
+ assert_raise Amazon::Associates::ConfigurationError do
26
+ Amazon::Associates.configure do |options|
27
+ options[:caching_strategy] = :filesystem
28
+ options[:caching_options] = {:cache_path => "foo123"}
29
+ end
30
+ end
31
+ end
32
+
33
+ should "set default values for disk_quota and sweep_frequency" do
34
+ Amazon::Associates.configure do |options|
35
+ options[:caching_strategy] = :filesystem
36
+ options[:caching_options] = {:cache_path => "."}
37
+ end
38
+
39
+ assert_equal Amazon::Associates::FilesystemCache.disk_quota, Amazon::Associates::FilesystemCache.disk_quota
40
+ assert_equal Amazon::Associates::FilesystemCache.sweep_frequency, Amazon::Associates::FilesystemCache.sweep_frequency
41
+ end
42
+
43
+ should "override the default value for disk quota if I specify one" do
44
+ quota = 400
45
+ Amazon::Associates.configure do |options|
46
+ options[:caching_strategy] = :filesystem
47
+ options[:caching_options] = {:cache_path => ".", :disk_quota => quota}
48
+ end
49
+
50
+ assert_equal quota, Amazon::Associates::FilesystemCache.disk_quota
51
+ end
52
+
53
+ should "override the default value for cache_frequency if I specify one" do
54
+ frequency = 4
55
+ Amazon::Associates.configure do |options|
56
+ options[:caching_strategy] = :filesystem
57
+ options[:caching_options] = {:cache_path => ".", :sweep_frequency => frequency}
58
+ end
59
+
60
+ assert_equal frequency, Amazon::Associates::FilesystemCache.sweep_frequency
61
+ end
62
+ end
63
+
64
+ context "caching a request" do
65
+
66
+ setup do
67
+ set_valid_caching_options(CACHE_TEST_PATH)
68
+ @resp = Amazon::Associates.item_lookup("0974514055")
69
+ @filename = Digest::SHA1.hexdigest(@resp.url)
70
+ end
71
+
72
+ teardown do
73
+ reset_cache
74
+ end
75
+
76
+ should "create a folder in the cache path with the first three letters of the digested filename" do
77
+ assert FileTest.exists?(File.join(CACHE_TEST_PATH, @filename[0..2]))
78
+ end
79
+
80
+ should "create a file in the cache path with a digested version of the url " do
81
+ assert FileTest.exists?(File.join(CACHE_TEST_PATH, @filename[0..2], @filename))
82
+ end
83
+
84
+ should "create a file in the cache path with the response inside it" do
85
+ open(File.join(CACHE_TEST_PATH + @filename[0..2], @filename)) do |f|
86
+ response = Marshal.load(f)
87
+ equivalent = eval(ROXML::XML::Parser.parse(response.body).root.name).from_xml(response.body, @resp.url)
88
+
89
+ assert_equal @resp, equivalent
90
+ end
91
+ end
92
+
93
+ should "not attemt to cache cart requests" do
94
+ Amazon::Associates::FilesystemCache.expects(:cache).never
95
+
96
+ resp = Amazon::Associates.cart_create(:items => {"0974514055" => 2})
97
+ filename = Digest::SHA1.hexdigest(resp.url)
98
+ assert !FileTest.exists?(File.join(CACHE_TEST_PATH, filename[0..2], filename))
99
+ end
100
+ end
101
+
102
+ context "getting a cached request" do
103
+ setup do
104
+ set_valid_caching_options(CACHE_TEST_PATH)
105
+ do_request
106
+ end
107
+
108
+ teardown do
109
+ reset_cache
110
+ end
111
+
112
+ should "not do an http request the second time the lookup is performed due a cached copy" do
113
+ Net::HTTP.expects(:get_response).never
114
+ do_request
115
+ end
116
+
117
+ should "return the same response as the original request" do
118
+ original = @resp
119
+ do_request
120
+ assert_equal(original, @resp)
121
+ end
122
+
123
+ should "not include cache parameters in the response" do
124
+ assert_no_match(/CachingOptions/, @resp.url)
125
+ assert_no_match(/caching_options/, @resp.url)
126
+ assert_no_match(/cache_path/, @resp.url)
127
+ assert_no_match(/disk_quota/, @resp.url)
128
+ end
129
+ end
130
+
131
+ context "sweeping cached requests" do
132
+ setup do
133
+ set_valid_caching_options(CACHE_TEST_PATH)
134
+ do_request
135
+ end
136
+
137
+ teardown do
138
+ reset_cache
139
+ end
140
+
141
+ should "not perform the sweep if the timestamp is within the range of the sweep frequency and quota is not exceeded" do
142
+ Amazon::Associates::FilesystemCache.expects(:sweep_time_expired?).returns(false)
143
+ Amazon::Associates::FilesystemCache.expects(:disk_quota_exceeded?).returns(false)
144
+
145
+ Amazon::Associates::FilesystemCache.expects(:perform_sweep).never
146
+
147
+ do_request
148
+ end
149
+
150
+ should "perform a sweep if the quota is exceeded" do
151
+ Amazon::Associates::FilesystemCache.stubs(:sweep_time_expired?).returns(false)
152
+ Amazon::Associates::FilesystemCache.expects(:disk_quota_exceeded?).once.returns(true)
153
+
154
+ Amazon::Associates::FilesystemCache.expects(:perform_sweep).once
155
+
156
+ do_request
157
+ end
158
+
159
+ should "perform a sweep if the sweep time is expired" do
160
+ Amazon::Associates::FilesystemCache.expects(:sweep_time_expired?).once.returns(true)
161
+ Amazon::Associates::FilesystemCache.stubs(:disk_quota_exceeded?).returns(false)
162
+ Amazon::Associates::FilesystemCache.expects(:perform_sweep).once
163
+
164
+ do_request
165
+ end
166
+
167
+ should "create a timestamp file after performing a sweep" do
168
+ Amazon::Associates::FilesystemCache.expects(:sweep_time_expired?).once.returns(true)
169
+
170
+ do_request
171
+ assert FileTest.exists?(File.join(CACHE_TEST_PATH, ".amz_timestamp"))
172
+ end
173
+
174
+ should "purge the cache when performing a sweep" do
175
+ (0..9).each do |n|
176
+ test = File.open(File.join(CACHE_TEST_PATH, "test_file_#{n}"), "w")
177
+ test.puts Time.now
178
+ test.close
179
+ end
180
+
181
+ Amazon::Associates::FilesystemCache.expects(:sweep_time_expired?).once.returns(true)
182
+ do_request
183
+
184
+ (0..9).each do |n|
185
+ assert !FileTest.exists?(File.join(CACHE_TEST_PATH, "test_file_#{n}"))
186
+ end
187
+ end
188
+
189
+ end
190
+
191
+ protected
192
+ def do_request
193
+ @resp = Amazon::Associates.item_lookup("0974514055")
194
+ end
195
+ end
196
+
197
+ end
198
+ end
@@ -0,0 +1,397 @@
1
+ require File.join(File.dirname(__FILE__), '../test_helper')
2
+
3
+ module Amazon
4
+ module Associates
5
+ class ItemTest < Test::Unit::TestCase
6
+ include FilesystemTestHelper
7
+
8
+ ## Test item_search
9
+ def setup
10
+ set_valid_caching_options
11
+ @ruby_search = Amazon::Associates.item_search('ruby')
12
+ end
13
+
14
+ def test_item_search
15
+ assert @ruby_search.request.valid?
16
+ assert @ruby_search.total_results >= 3600
17
+ assert @ruby_search.total_pages >= 360
18
+ end
19
+
20
+ def test_page_should_be_one_for_first_page
21
+ assert_equal 1, @ruby_search.current_page
22
+ end
23
+
24
+ def test_item_search_response_type
25
+ assert_equal ItemSearchResponse, @ruby_search.class
26
+ end
27
+
28
+ def test_argument_hash
29
+ assert_equal Hash, @ruby_search.operation_request.arguments.class
30
+ end
31
+
32
+ def test_item_search_with_paging
33
+ resp = Amazon::Associates.item_search('ruby', :item_page => 2)
34
+ assert resp.request.valid?
35
+ assert 2, resp.current_page
36
+ end
37
+
38
+ def test_item_search_with_response_group_array
39
+ resp = Amazon::Associates.item_search('ruby', :response_group => %w{Small ItemAttributes Images})
40
+ assert resp.request.valid?
41
+ end
42
+
43
+ def test_item_search_with_invalid_request
44
+ assert_raise Amazon::Associates::RequiredParameterMissing do
45
+ Amazon::Associates.item_search(nil)
46
+ end
47
+ end
48
+
49
+ def test_item_search_with_no_result
50
+ assert_raise Amazon::Associates::ItemNotFound, ' We did not find any matches for your request.' do
51
+ Amazon::Associates.item_search('afdsafds')
52
+ end
53
+ end
54
+
55
+ def test_item_search_uk
56
+ resp = Amazon::Associates.item_search('ruby', :country => 'uk')
57
+ assert resp.request.valid?
58
+ end
59
+
60
+ def test_item_search_not_keywords
61
+ resp = Amazon::Associates.item_search(:author => 'rowling')
62
+ assert resp.request.valid?
63
+ end
64
+
65
+ def test_item_search_by_author
66
+ resp = Amazon::Associates.item_search('dave', :type => :author)
67
+ assert resp.request.valid?
68
+ end
69
+
70
+ def test_text_at
71
+ item = Amazon::Associates.item_search("0974514055", :response_group => 'Large').items.first
72
+
73
+ # one item
74
+ assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition",
75
+ item.attributes['Title']
76
+
77
+ # multiple items
78
+ assert_equal ['Dave Thomas', 'Chad Fowler', 'Andy Hunt'],
79
+ item.authors
80
+
81
+ #ordinals
82
+ assert_equal Amazon::Associates::Ordinal.new(2), item.edition
83
+ end
84
+
85
+ def test_item_search_should_handle_string_argument_keys_as_well_as_symbols
86
+ Amazon::Associates.item_search('potter', 'search_index' => 'Books')
87
+ end
88
+
89
+ def test_hash_at_handles_specific_types
90
+ item = Amazon::Associates.item_search('ipod', :search_index => 'All', :response_group => 'Small,Offers,ItemAttributes,VariationSummary,Images,BrowseNodes').items.first
91
+
92
+ # Measurements & Image
93
+ assert_equal(Amazon::Associates::Image.new("http://ecx.images-amazon.com/images/I/41zt-RXYhfL._SL75_.jpg",
94
+ Amazon::Associates::Measurement.new(56, 'pixels'),
95
+ Amazon::Associates::Measurement.new(75, 'pixels')),
96
+ item.small_image)
97
+
98
+ # bools
99
+ assert !item.offers.empty?
100
+ assert_equal true, item.offers.first.is_eligible_for_super_saver_shipping?
101
+ assert_equal false, item.batteries_included?
102
+
103
+ # price
104
+ assert_equal Amazon::Associates::Price.new('$249.99', 24999, 'USD'), item.list_price
105
+
106
+ # integers
107
+ assert_instance_of Fixnum, item.total_new_offers
108
+ assert_instance_of Fixnum, item.total_offers
109
+
110
+ # attributes
111
+ assert item.image_sets['primary'], item.image_sets.inspect
112
+ assert_equal "Mary GrandPré", Amazon::Associates.item_lookup('0545010225').item.creators['Illustrator']
113
+
114
+ # browsenodes
115
+ nodes = item.browse_nodes.detect {|n| n.name == 'MP3 Players' }
116
+ assert_equal 'MP3 Players', nodes.name
117
+ assert_equal 'Audio & Video', nodes.parent.name
118
+ assert_equal 'Apple', nodes.parent.parent.name
119
+ assert_equal 'Custom Brands', nodes.parent.parent.parent.name
120
+
121
+ # ordinals
122
+ # in test_text_at, above
123
+ end
124
+
125
+ def test_price_should_handle_price_too_low_to_display
126
+ assert_equal 'Too low to display', Amazon::Associates.item_lookup('B000W79GQA', :response_group => 'Offers').item.lowest_new_price.to_s
127
+ end
128
+
129
+ def test_hash_at_handles_string_editions
130
+ Amazon::Associates.item_search("potter", :item_page => 3, :response_group => 'Small,Offers,ItemAttributes,VariationSummary,Images').items.each do |item|
131
+ assert item
132
+ end
133
+ end
134
+
135
+ def test_hash_at_makes_arrays_from_lists
136
+ item = Amazon::Associates.item_search("0974514055", :response_group => 'Large').items.first
137
+
138
+ # when <listmanialists> contains a bunch of <listmanialist>s, return an array
139
+ assert_equal(["R35BVGTHX7WEKZ", "R195F9SN6I3YQH", "R14L8RHCLAYQMY", "RCWKKCCVL5FGL", "R2IJ2M3X3ITVAR",
140
+ "R3MGYO2P65FC8J", "R2VY37TQWQM0VJ", "R3DB3MYO22PHZ6", "R192F79G3UXHJ5", "R1L6QNM215M7FB"],
141
+ item.listmania_lists.map(&:id))
142
+
143
+ review = item.editorial_reviews.first
144
+ # when there's a single child, make sure it's parsed rather than returned as a string
145
+ assert_equal "Product Description", review.source
146
+ assert review.content.is_a?(String)
147
+ assert review.content.size > 100
148
+ assert review.content.starts_with?("Ruby is an increasingly popular, fully object-oriented d")
149
+ end
150
+
151
+ ## Test item_lookup
152
+ def test_item_lookup
153
+ resp = Amazon::Associates.item_lookup('0974514055')
154
+ assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition",
155
+ resp.item.attributes['Title']
156
+ end
157
+
158
+ def test_item_lookup_with_invalid_request
159
+ assert_raise Amazon::Associates::RequiredParameterMissing, 'Your request is missing required parameters. Required parameters include ItemId.' do
160
+ Amazon::Associates.item_lookup(nil)
161
+ end
162
+ end
163
+
164
+ def test_item_lookup_with_no_result
165
+ assert_raise Amazon::Associates::InvalidParameterValue, 'ABC is not a valid value for ItemId. Please change this value and retry your request.' do
166
+ resp = Amazon::Associates.item_lookup('abc')
167
+ raise resp.inspect
168
+ end
169
+ end
170
+
171
+ def test_hpricot_extensions
172
+ item = Amazon::Associates.item_lookup('0974514055').item
173
+
174
+ assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition", item.attributes['Title']
175
+ assert item.authors.is_a?(Array)
176
+ assert 3, item.authors.size
177
+ assert_equal "Dave Thomas", item.authors.first
178
+ end
179
+ end
180
+
181
+ class Amazon::Associates::ItemTestsBroughtInFromAssociateGem < Test::Unit::TestCase
182
+ include FilesystemTestHelper
183
+
184
+ def setup
185
+ set_valid_caching_options
186
+ Amazon::Associates.options.merge!(:response_group => "Large")
187
+ end
188
+
189
+ ## Test item_search
190
+ def test_item_search
191
+ resp = Amazon::Associates.item_search("ruby")
192
+ assert(resp.request.valid?, resp.inspect)
193
+ assert(resp.total_results >= 3600)
194
+ assert(resp.total_pages >= 360)
195
+ end
196
+
197
+ def test_item_search_with_paging
198
+ resp = Amazon::Associates.item_search("ruby", :item_page => 2)
199
+ assert resp.request.valid?, resp.inspect
200
+ assert 2, resp.current_page
201
+ end
202
+
203
+ def test_item_search_with_no_result
204
+ assert_raise(Amazon::Associates::ItemNotFound) do
205
+ Amazon::Associates.item_search("afdsafds")
206
+ end
207
+ end
208
+
209
+ def test_item_search_uk
210
+ resp = Amazon::Associates.item_search("ruby", :country => :uk)
211
+ assert resp.request.valid?
212
+ end
213
+
214
+ def test_item_search_by_author
215
+ resp = Amazon::Associates.item_search("dave", :type => :author)
216
+ assert resp.request.valid?
217
+ end
218
+
219
+ def test_item_get
220
+ resp = Amazon::Associates.item_search("0974514055")
221
+ item = resp.items.first
222
+
223
+ # test get
224
+ assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition",
225
+ item.attributes['Title']
226
+
227
+ # test get_array
228
+ assert_equal ['Dave Thomas', 'Chad Fowler', 'Andy Hunt'], item.authors
229
+
230
+ # test get_hash
231
+ small_image = item.image_sets.values.first.small
232
+
233
+ assert small_image.url != nil
234
+ assert_equal 75, small_image.height.value
235
+ assert_equal 59, small_image.width.value
236
+ end
237
+
238
+ ## Test item_lookup
239
+ def test_item_lookup
240
+ resp = Amazon::Associates.item_lookup("0974514055")
241
+ assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition",
242
+ resp.items.first.attributes['Title']
243
+ end
244
+
245
+ def test_item_lookup_with_invalid_request
246
+ assert_raise(Amazon::Associates::RequiredParameterMissing) do
247
+ Amazon::Associates.item_lookup(nil)
248
+ end
249
+ end
250
+
251
+ def test_item_lookup_with_no_result
252
+ assert_raise(Amazon::Associates::InvalidParameterValue) do
253
+ resp = Amazon::Associates.item_lookup("abc")
254
+ end
255
+ end
256
+
257
+ def test_search_and_convert
258
+ resp = Amazon::Associates.item_lookup("0974514055")
259
+ title = resp.items.first.attributes['Title']
260
+ authors = resp.items.first.authors
261
+
262
+ assert_equal "Programming Ruby: The Pragmatic Programmers' Guide, Second Edition", title
263
+ assert authors.is_a?(Array)
264
+ assert 3, authors.size
265
+ assert_equal "Dave Thomas", authors.first
266
+ end
267
+ end
268
+
269
+ class ItemTestBroughtIn < Test::Unit::TestCase
270
+ include FilesystemTestHelper
271
+
272
+ def setup
273
+ set_valid_caching_options
274
+ end
275
+
276
+ def test_find_all_should_return_items
277
+ item = Item.find(:all, :keywords => 'upside').first
278
+ assert item
279
+ assert_kind_of Item, item
280
+ end
281
+
282
+ def test_find_all_and_find_first_should_yield_same_first
283
+ params = {:keywords => 'jelly'}
284
+ assert_equal Item.find(:all, params).first, Item.find(:first, params)
285
+ end
286
+
287
+ def test_find_second_page_returns_different_items_than_first
288
+ params = {:keywords => 'potter'}
289
+ assert_not_equal Item.find(:first, params.merge(:page => 1)),
290
+ Item.find(:first, params.merge(:page => 2))
291
+ end
292
+
293
+ def test_item_creator_should_be_unpacked
294
+ p "Pending: we're losing info from attributes..."
295
+ # asin = '0545010225'
296
+ # item = Item.find(asin)
297
+ # assert_equal("Mary GrandPré",
298
+ # Amazon::Associates.item_lookup(asin).items.first.attributes["Creator"])
299
+ end
300
+
301
+ def test_item_list_price_present
302
+ assert Item.find('0545010225').list_price
303
+ end
304
+
305
+ def test_item_performers_unpacked_to_array
306
+ assert_equal(["Robert Downey Jr.", "Gwyneth Paltrow", "Terrence Howard", "Jeff Bridges", "Leslie Bibb"],
307
+ Item.find('B00005JPS8').attributes['Actor'])
308
+ end
309
+
310
+ def test_image_sets_should_be_unpacked
311
+ item = Item.find(:first, :keywords => 'potter')
312
+ assert !item.image_sets.empty?
313
+ end
314
+
315
+ def test_missing_item_should_throw
316
+ assert_raise Amazon::Associates::InvalidParameterValue do
317
+ Item.find('abc')
318
+ end
319
+ end
320
+
321
+ def test_find_no_page_returns_same_items_as_first
322
+ params = {:keywords => 'potter'}
323
+ assert_equal Item.find(:first, params),
324
+ Item.find(:first, params.merge(:page => 1))
325
+ end
326
+
327
+ def test_find_with_different_sort_returns_different
328
+ params = {:keywords => 'potter'}
329
+ assert_not_equal Item.find(:first, params.merge(:sort => Amazon::Associates::SORT_TYPES['Books'][3])),
330
+ Item.find(:first, params.merge(:sort => Amazon::Associates::SORT_TYPES['Books'][7]))
331
+ assert_equal Item.find(:first, params.merge(:sort => Amazon::Associates::SORT_TYPES['Books'][3])),
332
+ Item.find(:first, params.merge(:sort => Amazon::Associates::SORT_TYPES['Books'][3]))
333
+ end
334
+
335
+ def test_find_too_far_a_page_is_error
336
+ assert_raise Amazon::Associates::ParameterOutOfRange do
337
+ Item.find(:first, :keywords => 'potter', :page => 9999)
338
+ end
339
+ end
340
+
341
+ def test_none_found_is_error
342
+ assert_raise Amazon::Associates::ItemNotFound do
343
+ Item.find(:first, :keywords => 'zjvalk', :page => 400)
344
+ end
345
+ end
346
+
347
+ def test_pagination_basics
348
+ results = Item.find(:all, :keywords => 'potter', :search_index => 'All')
349
+ assert_equal 4000, results.total_entries
350
+ assert_equal 1, results.current_page
351
+ end
352
+
353
+ def test_pagination_sets_current_page
354
+ [3, 7].each do |page|
355
+ assert_equal page, Item.find(:all, :keywords => 'potter', :page => page).current_page
356
+ end
357
+ end
358
+
359
+ def test_should_reject_unknown_args
360
+ assert_raise ArgumentError do
361
+ Item.find(:first, :keywords => 'potter', :itempage => 12)
362
+ end
363
+ end
364
+
365
+ def test_find_should_work_for_blended_merchants_and_all
366
+ assert Item.find(:first, :keywords => 'blackberry', :search_index => 'Blended')
367
+ assert Item.find(:first, :keywords => 'blackberry', :search_index => 'All')
368
+ assert Item.find(:first, :keywords => 'blackberry', :search_index => 'Merchants')
369
+ end
370
+
371
+ def test_find_top_sellers_should_return_items
372
+ assert !Item.find(:top_sellers, :browse_node_id => 520432).empty?
373
+ end
374
+
375
+ def test_should_find_one
376
+ item_asin = '0545010225'
377
+ item = Item.find(item_asin)
378
+ assert item
379
+ assert item.is_a?(Item)
380
+ assert_equal item_asin, item.asin
381
+ end
382
+
383
+ def test_find_one_and_first_should_be_equivalent
384
+ # TODO: or maybe a subset?
385
+ item1 = Item.find(:first, :keywords => 'potter')
386
+ item2 = Item.find(item1.asin)
387
+ assert_equal item1, item2
388
+ end
389
+
390
+ def test_should_raise_on_bad_request
391
+ assert_raise ArgumentError do
392
+ Item.find(20)
393
+ end
394
+ end
395
+ end
396
+ end
397
+ end