bento_search 0.8.0 → 0.9.0

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 (44) hide show
  1. data/README.md +16 -2
  2. data/app/helpers/bento_search_helper.rb +4 -10
  3. data/app/item_decorators/bento_search/decorator_base.rb +17 -0
  4. data/app/item_decorators/bento_search/standard_decorator.rb +3 -3
  5. data/app/models/bento_search/link.rb +3 -0
  6. data/app/models/bento_search/result_item.rb +17 -1
  7. data/app/models/bento_search/results.rb +5 -0
  8. data/app/models/bento_search/ris_creator.rb +166 -0
  9. data/app/models/bento_search/search_engine.rb +22 -2
  10. data/app/search_engines/bento_search/ebsco_host_engine.rb +54 -6
  11. data/app/search_engines/bento_search/eds_engine.rb +18 -3
  12. data/app/search_engines/bento_search/google_books_engine.rb +81 -54
  13. data/app/search_engines/bento_search/mock_engine.rb +8 -0
  14. data/app/search_engines/bento_search/primo_engine.rb +6 -2
  15. data/app/search_engines/bento_search/scopus_engine.rb +4 -0
  16. data/app/search_engines/bento_search/summon_engine.rb +26 -4
  17. data/app/search_engines/bento_search/worldcat_sru_dc_engine.rb +15 -0
  18. data/app/views/bento_search/_link.html.erb +3 -2
  19. data/lib/bento_search/version.rb +1 -1
  20. data/test/dummy/app/views/_test_custom_item_partial.html.erb +9 -0
  21. data/test/dummy/log/development.log +1 -0
  22. data/test/dummy/log/test.log +84981 -0
  23. data/test/helper/bento_search_helper_test.rb +11 -1
  24. data/test/unit/ebsco_host_engine_test.rb +59 -0
  25. data/test/unit/eds_engine_test.rb +10 -0
  26. data/test/unit/google_books_engine_test.rb +20 -0
  27. data/test/unit/primo_engine_test.rb +1 -1
  28. data/test/unit/ris_creator_test.rb +159 -0
  29. data/test/unit/scopus_engine_test.rb +2 -0
  30. data/test/unit/search_engine_test.rb +37 -0
  31. data/test/unit/summon_engine_test.rb +21 -0
  32. data/test/unit/worldcat_sru_dc_engine_test.rb +151 -0
  33. data/test/vcr_cassettes/ebscohost/live__get_identifier__round_trip.yml +1324 -0
  34. data/test/vcr_cassettes/ebscohost/live_get_id__on_bad_db_raises.yml +45 -0
  35. data/test/vcr_cassettes/ebscohost/live_get_id__with_no_results_raises.yml +45 -0
  36. data/test/vcr_cassettes/gbs/live_get_id_.yml +415 -0
  37. data/test/vcr_cassettes/gbs/live_get_id__with_not_found_id.yml +41 -0
  38. data/test/vcr_cassettes/summon/live__get_id_.yml +313 -0
  39. data/test/vcr_cassettes/summon/live_get_id__on_non-existing_id.yml +54 -0
  40. data/test/vcr_cassettes/worldcat_sru_dc/live_get_id_.yml +769 -0
  41. data/test/vcr_cassettes/worldcat_sru_dc/live_get_id__for_bad_id.yml +68 -0
  42. data/test/view/link_test.rb +21 -0
  43. metadata +31 -6
  44. data/test/vcr_cassettes/max_out_pagination.yml +0 -155
@@ -24,7 +24,15 @@ class BentoSearchHelperTest < ActionView::TestCase
24
24
  results = MockEngine.new.search(:query => "foo")
25
25
  bento_search(results)
26
26
 
27
- assert_select("div.bento_item", 10)
27
+ assert_select("div.bento_item", 10)
28
+ end
29
+
30
+ def test_custom_partial
31
+ results = MockEngine.new(:for_display => {:item_partial => "test_custom_item_partial"})
32
+
33
+ bento_search(results)
34
+
35
+ assert_select("p.custom_item_partial")
28
36
  end
29
37
 
30
38
  def test_with_failed_search
@@ -81,6 +89,8 @@ class BentoSearchHelperTest < ActionView::TestCase
81
89
  assert_raises(ArgumentError) { bento_search(MockEngine.new, :load => :ajax_auto) }
82
90
  end
83
91
 
92
+
93
+
84
94
  def test_ajax_load
85
95
  BentoSearch.register_engine("test_engine") do |conf|
86
96
  conf.engine = "MockEngine"
@@ -88,6 +88,22 @@ class EbscoHostEngineTest < ActiveSupport::TestCase
88
88
 
89
89
  end
90
90
 
91
+ def test_per_search_databases_construction
92
+ url = @engine.query_url(:query => "cancer", :databases => ["aaa", "bbb"])
93
+
94
+ query_params = CGI.parse( URI.parse(url).query )
95
+
96
+ assert_equal ["aaa", "bbb"].to_set, query_params["db"].to_set
97
+ end
98
+
99
+ def test_lookup_by_accession_number_construction
100
+ url = @engine.query_url(:query => "123456", :search_field => "AN")
101
+
102
+ query_params = CGI.parse( URI.parse(url).query )
103
+
104
+ assert_equal ["(AN 123456)"], query_params["query"]
105
+ end
106
+
91
107
 
92
108
  def test_prepare_query
93
109
  query = @engine.ebsco_query_prepare('one :. ; two "three four" and NOT OR five')
@@ -115,6 +131,13 @@ class EbscoHostEngineTest < ActiveSupport::TestCase
115
131
  assert_equal ['"cancer "'], query_params["query"]
116
132
  end
117
133
 
134
+ def test_has_http_timeout_set
135
+ assert_equal BentoSearch::EbscoHostEngine::HttpTimeout, @engine.http_client.receive_timeout
136
+ assert_equal BentoSearch::EbscoHostEngine::HttpTimeout, @engine.http_client.send_timeout
137
+ assert_equal BentoSearch::EbscoHostEngine::HttpTimeout, @engine.http_client.connect_timeout
138
+ end
139
+
140
+
118
141
  test_with_cassette("live search smoke test", :ebscohost) do
119
142
 
120
143
  results = @engine.search(:query => "cancer")
@@ -133,6 +156,10 @@ class EbscoHostEngineTest < ActiveSupport::TestCase
133
156
 
134
157
  assert_present first.language_code
135
158
  assert_present first.language_str
159
+
160
+ assert_present first.unique_id
161
+ # db name, colon, accession number.
162
+ assert_match /.+\:.+/, first.unique_id
136
163
  end
137
164
 
138
165
  test_with_cassette("get_info", :ebscohost) do
@@ -253,4 +280,36 @@ class EbscoHostEngineTest < ActiveSupport::TestCase
253
280
  assert_equal "Machine gun voices: Bandits, favelas, and utopia in Brazilian funk", result.title
254
281
  end
255
282
 
283
+ test_with_cassette("live #get(identifier) round trip", :ebscohost) do
284
+ results = @engine.search("cancer")
285
+
286
+ assert (! results.failed?)
287
+
288
+ item = @engine.get( results.first.unique_id )
289
+
290
+ assert_not_nil item
291
+ assert_kind_of BentoSearch::ResultItem, item
292
+ end
293
+
294
+ test_with_cassette("live get(id) with no results raises", :ebscohost) do
295
+ assert_raise(BentoSearch::NotFound) do
296
+ results = @engine.get("a9h:bar")
297
+ end
298
+ end
299
+
300
+ test_with_cassette("live get(id) on bad db raises", :ebscohost) do
301
+ assert_raise(Exception) do
302
+ results = @engine.get("badbad:bar")
303
+ end
304
+ end
305
+
306
+
307
+ test("illegal arg for get with id with no colon") do
308
+ assert_raise ArgumentError do
309
+ @engine.get("no_colon_in_here")
310
+ end
311
+ end
312
+
313
+
314
+
256
315
  end
@@ -61,6 +61,12 @@ class EdsEngineTest < ActiveSupport::TestCase
61
61
  assert_include parts, "SourceType:Academic Journals"
62
62
  assert_include parts, "SourceType:Magazines"
63
63
  end
64
+
65
+ def test_has_http_timeout_set
66
+ assert_equal BentoSearch::EdsEngine::HttpTimeout, @engine.http_client.receive_timeout
67
+ assert_equal BentoSearch::EdsEngine::HttpTimeout, @engine.http_client.send_timeout
68
+ assert_equal BentoSearch::EdsEngine::HttpTimeout, @engine.http_client.connect_timeout
69
+ end
64
70
 
65
71
 
66
72
  test_with_cassette("get_auth_token failure", :eds) do
@@ -138,6 +144,10 @@ class EdsEngineTest < ActiveSupport::TestCase
138
144
  assert_present first.custom_data["citation_blob"]
139
145
 
140
146
  assert_present first.format_str
147
+
148
+ assert_present first.unique_id
149
+ # EDS id is db name, colon, accession number
150
+ assert_match /.+\:.+/, first.unique_id
141
151
  end
142
152
 
143
153
 
@@ -27,6 +27,8 @@ class GoogleBooksEngineTest < ActiveSupport::TestCase
27
27
 
28
28
  assert_kind_of BentoSearch::ResultItem, first
29
29
 
30
+ assert_not_empty first.unique_id
31
+
30
32
  assert_not_empty first.title
31
33
  assert_not_empty first.publisher
32
34
  assert_not_empty first.link
@@ -81,6 +83,24 @@ class GoogleBooksEngineTest < ActiveSupport::TestCase
81
83
  assert ! results.failed?
82
84
  assert_equal 0, results.total_items
83
85
  end
86
+
87
+ test_with_cassette("live get(id)", :gbs) do
88
+ results = @engine.search 'cancer'
89
+
90
+ assert_present results
91
+
92
+ item = @engine.get(results.first.unique_id)
93
+
94
+ assert_present item
95
+ assert_kind_of BentoSearch::ResultItem, item
96
+ assert_equal results.first.unique_id, item.unique_id
97
+ end
98
+
99
+ test_with_cassette("live get(id) with not found id", :gbs) do
100
+ assert_raise(BentoSearch::NotFound) do
101
+ @engine.get("NOT EXISTING")
102
+ end
103
+ end
84
104
 
85
105
 
86
106
 
@@ -42,7 +42,7 @@ class PrimoEngineTest < ActiveSupport::TestCase
42
42
  # not every result has every field, but at time we recorded
43
43
  # with VCR, this result for this search did. Sorry, a bit fragile.
44
44
  # publisher
45
- %w{format_str format title authors volume issue start_page end_page journal_title issn doi abstract}.each do |attr|
45
+ %w{format_str format title authors volume issue start_page end_page journal_title issn doi abstract unique_id}.each do |attr|
46
46
  assert_present first.send(attr), "must have #{attr}"
47
47
  end
48
48
 
@@ -0,0 +1,159 @@
1
+ require 'test_helper'
2
+
3
+ class RISCreatorTest < ActiveSupport::TestCase
4
+ RISCreator = BentoSearch::RISCreator
5
+ ResultItem = BentoSearch::ResultItem
6
+ Author = BentoSearch::Author
7
+
8
+ # Parses an RIS file into a simpel data structure easier to test:
9
+ # an array of two element arrays, where each two element array is
10
+ # (tag, field). This method MAY also assert that the thing basically
11
+ # looks like a proper RIS file.
12
+ def ris_parse(str)
13
+ assert_match /\A\r\n/, str, "RIS records begin with \r\n seperator"
14
+ str.gsub!(/\A(\r\n)+/, '') # remove any at the beginning, multiple are fine
15
+
16
+ assert_match /\r\n\Z/, str, "Our RIS records end up with \r\n so they are concat-able with blank lines in between"
17
+ str.gsub!(/(\r\n)+\Z/, '') # remove any at the end, multiple are fine
18
+
19
+ lines = str.split("\r\n", -1)
20
+
21
+ assert_present lines, "RIS files are composed of multiple lines seperated by \r\n"
22
+
23
+ # trim blank lines off beginning or end, they're allowed. Also "ER" tag
24
+ # off the end, make sure it's there then trim it.
25
+ assert_equal "ER - ", lines.last, "RIS records end in `ER - `"
26
+ lines.pop # throw it away now.
27
+
28
+ return lines.collect do |line|
29
+ line =~ /^([A-Z][A-Z0-9]) - (.*)$/
30
+ tag = $1 ; value = $2
31
+ assert (tag.present? && value.present?), "Individual RIS lines are composed of `TG - VALUE`, not `#{line}`"
32
+ [tag, value]
33
+ end
34
+ end
35
+
36
+
37
+ @@article = ResultItem.new(
38
+ :format => "Article",
39
+ :title => "Some Article",
40
+ :source_title => "Some Journal",
41
+ :issn => "12345678",
42
+ :volume => "10",
43
+ :issue => "3",
44
+ :start_page => "100",
45
+ :end_page => "110",
46
+ :doi => '10.1000/182',
47
+ :abstract => "This is an abstract",
48
+ :authors => [
49
+ Author.new(:first => "John", :last => "Smith", :middle => "Q"),
50
+ Author.new(:first => "Maria", :last => "Lopez"),
51
+ Author.new(:display => "Some Guy")
52
+ ]
53
+ )
54
+
55
+ @@article_with_full_date = ResultItem.new(
56
+ :format => "Article",
57
+ :title => "Something",
58
+ :source_title => "Some Magazine",
59
+ :start_page => "123",
60
+ :publication_date => Date.new(2011,9,1)
61
+ )
62
+
63
+ @@book = ResultItem.new(
64
+ :format => "Book",
65
+ :title => "Some Book",
66
+ :isbn => "1234567890",
67
+ :publisher => "Some Publisher",
68
+ :year => "1990",
69
+ :authors => [
70
+ Author.new(:first => "John", :last => "Smith", :middle => "Q")
71
+ ]
72
+ )
73
+
74
+ @@book_chapter = ResultItem.new(
75
+ :format => :book_item,
76
+ :title => 'Some Chapter',
77
+ :source_title => "Book Title",
78
+ :year => '1991',
79
+ :publisher => "Some Pub",
80
+ :start_page => '10',
81
+ :authors => [
82
+ Author.new(:first => "John", :last => "Smith", :middle => "Q")
83
+ ]
84
+ )
85
+
86
+ @@dissertation = ResultItem.new(
87
+ :format => :dissertation,
88
+ :title => "Areoformation and the new science",
89
+ :publisher => "University of Mars",
90
+ :year => "2150",
91
+ :authors => [
92
+ Author.new(:display => "mztlbplk q. frakdf")
93
+ ]
94
+ )
95
+
96
+
97
+ def test_article
98
+ lines = ris_parse RISCreator.new(@@article).export
99
+
100
+ assert_include lines, ['TY', 'JOUR']
101
+ assert_include lines, ['TI', @@article.title]
102
+ assert_include lines, ['T2', @@article.source_title]
103
+ assert_include lines, ['SN', @@article.issn]
104
+ assert_include lines, ['VL', @@article.volume]
105
+ assert_include lines, ['IS', @@article.issue]
106
+ assert_include lines, ['SP', @@article.start_page]
107
+ assert_include lines, ['EP', @@article.end_page]
108
+ assert_include lines, ['DO', @@article.doi]
109
+ assert_include lines, ['AB', @@article.abstract]
110
+
111
+ assert_include lines, ['AU', "Smith, John Q."]
112
+ assert_include lines, ['AU', "Lopez, Maria"]
113
+ assert_include lines, ['AU', "Some Guy"]
114
+ end
115
+
116
+ def test_book
117
+ lines = ris_parse RISCreator.new(@@book).export
118
+
119
+ assert_include lines, ['TY', 'BOOK']
120
+ assert_include lines, ['TI', @@book.title]
121
+ assert_include lines, ['PY', @@book.year]
122
+ assert_include lines, ['PB', @@book.publisher]
123
+ assert_include lines, ['SN', @@book.isbn]
124
+
125
+ assert_include lines, ['AU', "Smith, John Q."]
126
+ end
127
+
128
+ def test_book_chapter
129
+ lines = ris_parse RISCreator.new(@@book_chapter).export
130
+
131
+ assert_include lines, ['TY', 'CHAP']
132
+
133
+ assert_include lines, ['TI', @@book_chapter.title]
134
+ assert_include lines, ['T2', @@book_chapter.source_title]
135
+ assert_include lines, ['PY', @@book_chapter.year]
136
+ assert_include lines, ['PB', @@book_chapter.publisher]
137
+ assert_include lines, ['SP', @@book_chapter.start_page]
138
+ end
139
+
140
+ def test_dissertation
141
+ lines = ris_parse RISCreator.new(@@dissertation).export
142
+
143
+ assert_include lines, ['TY', 'THES']
144
+
145
+ assert_include lines, ['TI', @@dissertation.title]
146
+ assert_include lines, ['PB', @@dissertation.publisher]
147
+ assert_include lines, ['PY', @@dissertation.year]
148
+ end
149
+
150
+ def test_article_with_full_date
151
+ lines = ris_parse RISCreator.new(@@article_with_full_date).export
152
+
153
+ assert_include lines, ['TY', 'JOUR']
154
+
155
+ assert_include lines, ['DA', '2011/09/01']
156
+ end
157
+
158
+
159
+ end
@@ -102,6 +102,8 @@ class ScopusEngineTest < ActiveSupport::TestCase
102
102
 
103
103
  assert_present sample_result.format
104
104
 
105
+ assert_present sample_result.unique_id
106
+
105
107
  end
106
108
 
107
109
  test_with_cassette("zero results search", :scopus) do
@@ -103,6 +103,43 @@ class SearchEngineTest < ActiveSupport::TestCase
103
103
 
104
104
  end
105
105
 
106
+ test "sets metadata on items" do
107
+ engine = MockEngine.new(:id => "foo", :for_display => {:key => "value", :decorator => "Foo"})
108
+ results = engine.search(:query => "cancer")
109
+ record = results.first
110
+
111
+ assert_present record.engine_id
112
+ assert_present record.display_configuration
113
+ assert_present record.decorator
114
+ end
115
+
116
+ test "failed sets metadata on results" do
117
+ engine = MockEngine.new(:id => "fail_engine", :error => {:message => "failed"}, :for_display => {:foo => "foo"})
118
+
119
+ results = engine.search(:query => "cancer", :per_page => 20)
120
+
121
+ assert results.failed?
122
+ assert_present results.error
123
+ assert_equal "fail_engine", results.engine_id
124
+ assert_present results.search_args
125
+ assert_equal( {:foo => "foo"}, results.display_configuration )
126
+ end
127
+
128
+ test "auto rescued exception, with proper metadata" do
129
+ engine = MockEngine.new(:id => "raises", :raise_exception_class => 'TimeoutError', :for_display => {:foo => "foo"})
130
+
131
+ results = engine.search("foo", :per_page => 20)
132
+
133
+ assert results.failed?, "marked failed"
134
+ assert_present results.error
135
+ assert_equal "raises", results.engine_id
136
+ assert_present results.search_args
137
+ assert_equal "foo", results.search_args[:query]
138
+
139
+ assert_equal( {:foo => "foo"}, results.display_configuration )
140
+ end
141
+
142
+
106
143
  test "has empty :for_display config" do
107
144
  engine = MockEngine.new
108
145
 
@@ -158,6 +158,8 @@ class SummonEngineTest < ActiveSupport::TestCase
158
158
 
159
159
  # just smoke test to make sure it's set to something
160
160
  assert_not_nil first.link_is_fulltext?
161
+
162
+ assert_present first.unique_id
161
163
  end
162
164
 
163
165
  test_with_cassette("proper tags for snippets", :summon) do
@@ -174,4 +176,23 @@ class SummonEngineTest < ActiveSupport::TestCase
174
176
 
175
177
  end
176
178
 
179
+ test_with_cassette("live #get(id)", :summon) do
180
+ results = @engine.search("cancer")
181
+
182
+ assert_present results
183
+
184
+ item = @engine.get(results.first.unique_id)
185
+
186
+ assert_not_nil item
187
+ assert_kind_of BentoSearch::ResultItem, item
188
+
189
+ assert_equal results.first.unique_id, item.unique_id
190
+ end
191
+
192
+ test_with_cassette("live get(id) on non-existing id", :summon) do
193
+ assert_raise(BentoSearch::NotFound) do
194
+ item = @engine.get("NONE SUCH")
195
+ end
196
+ end
197
+
177
198
  end
@@ -0,0 +1,151 @@
1
+ require 'test_helper'
2
+
3
+ require 'cgi'
4
+ require 'uri'
5
+
6
+ #
7
+ #
8
+ # Using the MARCXML response is way too much work, but the XML 'DC' response
9
+ # is awfully stunted. We do what we can with it, but resulting metadata
10
+ # is weird.
11
+ #
12
+ class WorldcatSruDcEngineTest < ActiveSupport::TestCase
13
+ extend TestWithCassette
14
+
15
+ @@api_key = ENV["WORLDCAT_API_KEY"] || "DUMMY_API_KEY"
16
+
17
+ VCR.configure do |c|
18
+ c.filter_sensitive_data("DUMMY_API_KEY", :worldcat_sru_dc) { @@api_key }
19
+ end
20
+
21
+
22
+ def setup
23
+ @config = {:api_key => @@api_key}
24
+ @engine = BentoSearch::WorldcatSruDcEngine.new(@config)
25
+ end
26
+
27
+ def test_construct_url
28
+ query = 'cancer\'s "one two"'
29
+ url = @engine.construct_query_url(:query => query, :per_page => 10)
30
+
31
+ query_hash = CGI.parse(URI.parse(url).query)
32
+
33
+ assert_equal [@engine.configuration.api_key], query_hash["wskey"]
34
+ assert_equal ['info:srw/schema/1/dc'], query_hash["recordSchema"]
35
+ assert_equal [@engine.construct_cql_query(:query => query)], query_hash["query"]
36
+ end
37
+
38
+ def test_construct_pagination
39
+ url = @engine.construct_query_url(:query => "cancer", :per_page => 20, :start => 20)
40
+
41
+ query_hash = CGI.parse(URI.parse(url).query)
42
+
43
+ assert_equal ["20"], query_hash["maximumRecords"]
44
+ assert_equal ["21"], query_hash["startRecord"]
45
+ end
46
+
47
+ def test_construct_sort
48
+ url = @engine.construct_query_url(:query => "cancer", :sort => "date_desc")
49
+
50
+ query_hash = CGI.parse(URI.parse(url).query)
51
+
52
+ assert_present query_hash["sortKeys"]
53
+ end
54
+
55
+ def test_construct_fielded_search
56
+ cql = @engine.construct_cql_query(:query => "cancer", :search_field => "srw.ti")
57
+
58
+ assert_equal 'srw.ti = "cancer"', cql
59
+ end
60
+
61
+ def test_construct_servicelevel
62
+ url = @engine.construct_query_url(:query => "cancer")
63
+ query_hash = CGI.parse(URI.parse(url).query)
64
+ assert_not_include query_hash["servicelevel"], "full"
65
+
66
+ url = @engine.construct_query_url(:query => "cancer auth", :auth => true)
67
+ query_hash = CGI.parse(URI.parse(url).query)
68
+ assert_include query_hash["servicelevel"], "full"
69
+
70
+ default_on = BentoSearch::WorldcatSruDcEngine.new(@config.merge(:auth => true))
71
+
72
+ url = default_on.construct_query_url(:query => "cancer")
73
+ query_hash = CGI.parse(URI.parse(url).query)
74
+ assert_include query_hash["servicelevel"], "full"
75
+
76
+ url = default_on.construct_query_url(:query => "cancer", :auth => false)
77
+ query_hash = CGI.parse(URI.parse(url).query)
78
+ assert_not_include query_hash["servicelevel"], "full"
79
+ end
80
+
81
+ def test_construct_cql
82
+ # test proper escaping and such
83
+ cql = @engine.construct_cql_query(:query => "alpha's beta \"one two\" thr\"ee")
84
+
85
+ components = cql.split(" AND ")
86
+
87
+ assert_equal 4, components.length
88
+
89
+ ["srw.kw = \"beta\"",
90
+ "srw.kw = \"alpha's\"",
91
+ "srw.kw = \"one two\"",
92
+ "srw.kw = \"thr\\\"ee\""].each do |clause|
93
+ assert_include components, clause
94
+ end
95
+ end
96
+
97
+ test_with_cassette("max_out_pagination", :worldcat_sru_dc) do
98
+ #worldcat maxes out at start 9999, we silently correct
99
+ results = @engine.search("cancer", :start => 100000, :per_page => 10)
100
+
101
+ assert ! results.failed?
102
+ assert_present results
103
+ assert_equal 9999, results.pagination.start_record
104
+ assert_equal 1000, results.pagination.current_page
105
+ end
106
+
107
+ test_with_cassette("smoke test", :worldcat_sru_dc) do
108
+ results = @engine.search("anarchism")
109
+
110
+ assert_present results
111
+
112
+ assert_present results.total_items
113
+
114
+ first = results.first
115
+
116
+ assert_present first.unique_id
117
+
118
+ assert_present first.title
119
+ assert_present first.authors
120
+ assert_present first.publisher
121
+ assert_present first.oclcnum
122
+
123
+ assert_present first.year
124
+
125
+ assert_present first.abstract
126
+
127
+ assert_present first.link
128
+
129
+ assert_present first.language_code
130
+ end
131
+
132
+ test_with_cassette("live get(id)", :worldcat_sru_dc) do
133
+ results = @engine.search("anarchism")
134
+
135
+ assert_present results
136
+
137
+ item = @engine.get( results.first.unique_id)
138
+
139
+ assert_present item
140
+ assert_kind_of BentoSearch::ResultItem, item
141
+ assert_equal results.first.unique_id, item.unique_id
142
+ end
143
+
144
+ test_with_cassette("live get(id) for bad id", :worldcat_sru_dc) do
145
+ assert_raise(BentoSearch::NotFound) do
146
+ @engine.get("NOT EXISTING")
147
+ end
148
+ end
149
+
150
+
151
+ end