bento_search 0.5.0 → 0.6.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 (47) hide show
  1. data/README.md +6 -5
  2. data/app/assets/javascripts/bento_search/ajax_load.js +42 -16
  3. data/app/assets/stylesheets/bento_search/suggested_styles.css +9 -0
  4. data/app/controllers/bento_search/search_controller.rb +15 -6
  5. data/app/helpers/bento_search_helper.rb +24 -8
  6. data/app/item_decorators/bento_search/no_links.rb +13 -0
  7. data/app/models/bento_search/openurl_creator.rb +18 -8
  8. data/app/models/bento_search/registrar.rb +2 -6
  9. data/app/models/bento_search/result_item.rb +43 -3
  10. data/app/models/bento_search/results.rb +4 -0
  11. data/app/models/bento_search/search_engine.rb +25 -23
  12. data/app/search_engines/bento_search/ebsco_host_engine.rb +42 -17
  13. data/app/search_engines/bento_search/google_books_engine.rb +2 -0
  14. data/app/search_engines/bento_search/google_site_search_engine.rb +177 -0
  15. data/app/search_engines/bento_search/mock_engine.rb +5 -0
  16. data/app/search_engines/bento_search/primo_engine.rb +23 -2
  17. data/app/search_engines/bento_search/scopus_engine.rb +4 -1
  18. data/app/search_engines/bento_search/summon_engine.rb +4 -14
  19. data/app/search_engines/bento_search/worldcat_sru_dc_engine.rb +293 -0
  20. data/app/views/bento_search/_std_item.html.erb +4 -5
  21. data/app/views/bento_search/_wrap_with_count.html.erb +20 -0
  22. data/app/views/bento_search/search/search.html.erb +15 -1
  23. data/config/locales/en.yml +6 -4
  24. data/lib/bento_search/util.rb +13 -0
  25. data/lib/bento_search/version.rb +1 -1
  26. data/test/dummy/log/development.log +1 -0
  27. data/test/dummy/log/test.log +24357 -0
  28. data/test/functional/bento_search/search_controller_test.rb +39 -0
  29. data/test/helper/bento_search_helper_test.rb +47 -5
  30. data/test/unit/ebsco_host_engine_test.rb +15 -0
  31. data/test/unit/google_books_engine_test.rb +1 -0
  32. data/test/unit/google_site_search_test.rb +122 -0
  33. data/test/unit/item_decorators_test.rb +12 -1
  34. data/test/unit/openurl_creator_test.rb +19 -3
  35. data/test/unit/primo_engine_test.rb +5 -3
  36. data/test/unit/result_item_test.rb +36 -1
  37. data/test/unit/search_engine_test.rb +27 -4
  38. data/test/unit/worldcat_sru_dc_engine_test.rb +120 -0
  39. data/test/vcr_cassettes/google_site/basic_smoke_test.yml +254 -0
  40. data/test/vcr_cassettes/google_site/empty_result_set.yml +53 -0
  41. data/test/vcr_cassettes/google_site/pagination_object_is_correct_for_actual_page_when_you_ask_for_too_far.yml +260 -0
  42. data/test/vcr_cassettes/google_site/with_highlighting.yml +265 -0
  43. data/test/vcr_cassettes/google_site/without_highlighting.yml +267 -0
  44. data/test/vcr_cassettes/primo/proper_tags_for_snippets.yml +517 -502
  45. data/test/vcr_cassettes/primo/search_smoke_test.yml +1 -1
  46. data/test/vcr_cassettes/worldcat_sru_dc/smoke_test.yml +628 -0
  47. metadata +40 -4
@@ -13,6 +13,17 @@ module BentoSearch
13
13
  # no allow_routable_results
14
14
  end
15
15
 
16
+ BentoSearch.register_engine("with_layout_config") do |config|
17
+ config.engine = "MockEngine"
18
+
19
+ config.allow_routable_results = true
20
+
21
+ config.for_display do |display|
22
+ display.ajax do |ajax|
23
+ ajax.wrapper_template = "bento_search/wrap_with_count"
24
+ end
25
+ end
26
+ end
16
27
  end
17
28
 
18
29
  def teardown
@@ -28,6 +39,17 @@ module BentoSearch
28
39
  assert_template "bento_search/search"
29
40
  end
30
41
 
42
+ test "custom layout config" do
43
+ get :search, {:engine_id => "with_layout_config", :query => "my search"}
44
+
45
+ assert_response :success
46
+
47
+ assert_not_nil assigns(:partial_wrapper)
48
+
49
+ assert_template "bento_search/_wrap_with_count"
50
+ assert_template "bento_search/search"
51
+ end
52
+
31
53
  test "non-routable engine" do
32
54
  get :search, {:engine_id => "not_routable", :query => "my search"}
33
55
 
@@ -40,6 +62,22 @@ module BentoSearch
40
62
  assert_response 404
41
63
  end
42
64
 
65
+
66
+ test "respects public_settable_search_args" do
67
+ get :search, {:engine_id => "mock",
68
+ 'query' => "query", 'sort' => "sort", 'per_page' => "15",
69
+ 'page' => "6", 'search_field' => "title", 'not_allowed' => "not allowed"}
70
+
71
+
72
+ search_args = assigns[:engine].last_args
73
+
74
+ [:query, :sort, :per_page, :page, :search_field].each do |allowed_key|
75
+ assert search_args.has_key?(allowed_key)
76
+ end
77
+ assert ! search_args.has_key?(:not_allowed)
78
+ assert ! search_args.has_key?("not_allowed")
79
+ end
80
+
43
81
  test "custom before filter" do
44
82
  # Okay, we're going to do a weird thing with a custom controller subclass
45
83
  # we can add a custom before filter like a local app might.
@@ -74,6 +112,7 @@ module BentoSearch
74
112
 
75
113
  end
76
114
 
115
+
77
116
 
78
117
 
79
118
 
@@ -1,5 +1,8 @@
1
1
  require 'test_helper'
2
2
 
3
+ # this seems to work? Rails view testing is a mess.
4
+ require 'sprockets/helpers/rails_helper'
5
+
3
6
  class BentoSearchHelperTest < ActionView::TestCase
4
7
  include BentoSearchHelper
5
8
 
@@ -8,13 +11,11 @@ class BentoSearchHelperTest < ActionView::TestCase
8
11
  def teardown
9
12
  BentoSearch.reset_engine_registrations!
10
13
  end
11
-
12
-
13
-
14
14
 
15
15
  def setup
16
16
  # Make routing work
17
- @routes = Rails.application.routes
17
+ @routes = Rails.application.routes
18
+
18
19
  end
19
20
 
20
21
  def test_with_results_arg
@@ -89,6 +90,8 @@ class BentoSearchHelperTest < ActionView::TestCase
89
90
 
90
91
  div = results.find(:attributes => {:class => "bento_search_ajax_wait"})
91
92
  assert div, "produces div.bento_search_ajax_wait"
93
+ assert_equal "ajax_auto", div["data-bento-search-load"], "has data-bento-search-load attribute"
94
+
92
95
 
93
96
  assert_present div.attributes["data-bento-ajax-url"]
94
97
  url = URI.parse(div.attributes["data-bento-ajax-url"])
@@ -97,12 +100,35 @@ class BentoSearchHelperTest < ActionView::TestCase
97
100
  query = CGI.parse(url.query.gsub("&amp;", "&")) # gsub weirdness of HTML::Tag
98
101
  assert_equal ["QUERY"], query["query"]
99
102
  assert_empty query["load"]
103
+
104
+ # hidden loading msg
105
+ loading_msg = div.find(:attributes => {:class => "bento_search_ajax_loading"})
106
+ assert_present loading_msg, "bento_search_ajax_loading present"
107
+ assert_match /display\:none/, loading_msg["style"], "loading has CSS style hidden"
100
108
 
101
109
  assert div.find(:tag => "noscript"), "has <noscript> tag"
102
110
 
103
- assert (img = div.find(:tag => "img")), "Has spinner gif"
111
+ assert (img = loading_msg.find(:tag => "img")), "Has spinner gif"
104
112
  assert_equal I18n.translate("bento_search.ajax_loading"), img.attributes["alt"]
105
113
  end
114
+
115
+ def test_ajax_triggered_load
116
+ BentoSearch.register_engine("test_engine") do |conf|
117
+ conf.engine = "MockEngine"
118
+ end
119
+
120
+ results = bento_search("test_engine", :query => "QUERY", :load => :ajax_triggered)
121
+ results = HTML::Document.new(results)
122
+
123
+ div = results.find(:attributes => {:class => "bento_search_ajax_wait"})
124
+ assert div, "produces div.bento_search_ajax_wait"
125
+ assert_equal "ajax_triggered", div["data-bento-search-load"], "has data-bento-search-load attribute"
126
+
127
+ # hidden loading msg
128
+ loading_msg = div.find(:attributes => {:class => "bento_search_ajax_loading"})
129
+ assert_present loading_msg, "bento_search_ajax_loading present"
130
+ assert_match /display\:none/, loading_msg["style"], "loading has CSS style hidden"
131
+ end
106
132
 
107
133
 
108
134
  def test_sort_hash_for
@@ -121,6 +147,22 @@ class BentoSearchHelperTest < ActionView::TestCase
121
147
  assert_equal key, hash[ I18n.translate(key, :scope => "bento_search.sort_keys") ]
122
148
  end
123
149
  end
150
+
151
+ def test_sort_hash_for_no_i18n
152
+ # If there's no 18n key available, use reasonable humanized approximation
153
+
154
+ engine = MockEngine.new(:sort_definitions => {"no_key_test" => {}})
155
+
156
+ hash = bento_sort_hash_for(engine)
157
+
158
+ assert_present hash
159
+
160
+ key = hash.key("no_key_test")
161
+
162
+ assert_no_match /translation missing/, key
163
+
164
+ assert_equal "No Key Test", key
165
+ end
124
166
 
125
167
 
126
168
  end
@@ -80,6 +80,18 @@ class EbscoHostEngineTest < ActiveSupport::TestCase
80
80
  assert_equal ["cancer "], query_params["query"]
81
81
  end
82
82
 
83
+ def test_removes_question_marks
84
+ # who knows why, ebsco doesn't like question marks even inside
85
+ # quoted phrases, some special char to ebsco.
86
+ url = @engine.query_url(:query => "cancer?", :sort => "date_desc")
87
+ query_params = CGI.parse( URI.parse(url).query )
88
+ assert_equal ["cancer "], query_params["query"]
89
+
90
+ url = @engine.query_url(:query => '"cancer?"', :sort => "date_desc")
91
+ query_params = CGI.parse( URI.parse(url).query )
92
+ assert_equal ['"cancer "'], query_params["query"]
93
+ end
94
+
83
95
  test_with_cassette("live search smoke test", :ebscohost) do
84
96
 
85
97
  results = @engine.search(:query => "cancer")
@@ -95,6 +107,9 @@ class EbscoHostEngineTest < ActiveSupport::TestCase
95
107
 
96
108
  assert_present first.format
97
109
  assert_present first.format_str
110
+
111
+ assert_present first.language_code
112
+ assert_present first.language_str
98
113
  end
99
114
 
100
115
  test_with_cassette("get_info", :ebscohost) do
@@ -35,6 +35,7 @@ class GoogleBooksEngineTest < ActiveSupport::TestCase
35
35
  assert_not_empty first.abstract
36
36
  assert first.abstract.html_safe?
37
37
 
38
+ assert_present first.language_code
38
39
 
39
40
  assert_not_empty first.authors
40
41
  assert_not_empty first.authors.first.display
@@ -0,0 +1,122 @@
1
+ require 'test_helper'
2
+
3
+ require 'uri'
4
+ require 'cgi'
5
+
6
+ # To run these tests without VCR cassettes, need
7
+ # ENV GOOGLE_SITE_SEARCH_KEY and GOOGLE_SITE_SEARCH_CX
8
+ class GoogleSiteSearchTest < ActiveSupport::TestCase
9
+ extend TestWithCassette
10
+
11
+ @@api_key = ENV["GOOGLE_SITE_SEARCH_KEY"] || "DUMMY_API_KEY"
12
+ @@cx = ENV["GOOGLE_SITE_SEARCH_CX"] || "DUMMY_CX"
13
+
14
+ VCR.configure do |c|
15
+ c.filter_sensitive_data("DUMMY_API_KEY", :google_site) { @@api_key }
16
+ c.filter_sensitive_data("DUMMY_CX", :google_site) { @@cx }
17
+ end
18
+
19
+ setup do
20
+ @config = {:api_key => @@api_key, :cx => @@cx}
21
+ @engine = BentoSearch::GoogleSiteSearchEngine.new(@config)
22
+ end
23
+
24
+ test("basic query construction") do
25
+ url = @engine.send(:construct_query, {:query => "hours policies"})
26
+
27
+ query_params = CGI.parse( URI.parse(url).query )
28
+
29
+ assert_equal ["hours policies"], query_params["q"]
30
+ end
31
+
32
+ test("pagination construction") do
33
+ url = @engine.send(:construct_query, {:query => "books", :per_page => 5, :start => 10})
34
+
35
+ query_params = CGI.parse( URI.parse(url).query )
36
+
37
+ assert_equal ["5"], query_params["num"]
38
+ assert_equal ["11"], query_params["start"]
39
+ end
40
+
41
+ test("silently refuses to paginate too far") do
42
+ # google won't let you paginate past ~10 pages, (101 - num). We silently
43
+ # refuse
44
+
45
+ url = @engine.send(:construct_query, {:query => "books", :start => 110})
46
+
47
+ query_params = CGI.parse( URI.parse(url).query )
48
+
49
+ assert_equal ["91"], query_params["start"]
50
+ end
51
+
52
+ test_with_cassette("pagination object is correct for actual page when you ask for too far", :google_site) do
53
+ results = @engine.search("books", :start => 1000)
54
+
55
+ pagination = results.pagination
56
+
57
+ assert_equal 10, pagination.current_page
58
+ assert_equal 91, pagination.start_record
59
+ end
60
+
61
+ test("sort query construction") do
62
+ url = @engine.send(:construct_query, {:query => "books", :sort => "date_desc"})
63
+
64
+ query_params = CGI.parse( URI.parse(url).query )
65
+
66
+ assert_equal ["date"], query_params["sort"]
67
+ end
68
+
69
+ test_with_cassette("basic smoke test", :google_site) do
70
+ results = @engine.search("books")
71
+
72
+ assert_present results
73
+ assert_present results.total_items
74
+ assert_kind_of Fixnum, results.total_items
75
+
76
+ first = results.first
77
+
78
+ assert_present first.title
79
+ assert_present first.link
80
+ assert_present first.abstract
81
+ assert_present first.journal_title # used as source_title for display url
82
+
83
+ # no openurls for google, we decided
84
+ assert_nil first.to_openurl
85
+ end
86
+
87
+ test_with_cassette("with highlighting", :google_site) do
88
+ engine = BentoSearch::GoogleSiteSearchEngine.new(@config.merge(:highlighting => true))
89
+
90
+ results = engine.search("books")
91
+
92
+ first = results.first
93
+
94
+ assert first.title.html_safe?
95
+ assert first.abstract.html_safe?
96
+ assert first.journal_title.html_safe?
97
+
98
+ assert first.published_in.html_safe?
99
+ end
100
+
101
+ test_with_cassette("without highlighting", :google_site) do
102
+ engine = BentoSearch::GoogleSiteSearchEngine.new(@config.merge(:highlighting => false))
103
+
104
+ results = engine.search("books")
105
+
106
+ first = results.first
107
+
108
+ assert ! first.title.html_safe?
109
+ assert ! first.abstract.html_safe?
110
+ assert ! first.journal_title.html_safe?
111
+ end
112
+
113
+ test_with_cassette("empty result set", :google_site) do
114
+ results = nil
115
+ assert_nothing_raised { results = @engine.search('"adfa lakjdr xavier aldkfj 92323kjadf"') }
116
+
117
+ assert ! results.failed?
118
+
119
+ assert results.empty?
120
+ end
121
+
122
+ end
@@ -1,6 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
- class LinkDecoratorsTest < ActiveSupport::TestCase
3
+ class ItemDecoratorsTest < ActiveSupport::TestCase
4
4
  MockEngine = BentoSearch::MockEngine
5
5
 
6
6
  # simple decorator that replaces main link
@@ -35,6 +35,17 @@ class LinkDecoratorsTest < ActiveSupport::TestCase
35
35
  end
36
36
  end
37
37
 
38
+ test "decorator as string" do
39
+ @engine = MockEngine.new(:item_decorators => ["::ItemDecoratorsTest::Decorator"])
40
+
41
+ results = @engine.search(:query => "Query")
42
+
43
+ results.each do |result|
44
+ assert_kind_of Decorator, result
45
+ end
46
+
47
+ end
48
+
38
49
  # Is it a good idea to have a decorator that mutates on 'extend'?
39
50
  # I'm not sure, I think probably not, but it is possible.
40
51
  # Here we'll use it to move an original link to other links
@@ -1,3 +1,5 @@
1
+ require 'test_helper'
2
+
1
3
  class OpenurlCreatorTest < ActiveSupport::TestCase
2
4
 
3
5
  def test_create_article
@@ -80,7 +82,7 @@ class OpenurlCreatorTest < ActiveSupport::TestCase
80
82
 
81
83
  end
82
84
 
83
- def create_hardcoded_kev
85
+ def test_create_hardcoded_kev
84
86
  item = BentoSearch::ResultItem.new(
85
87
  :format => "Book",
86
88
  :title => "Something",
@@ -89,13 +91,13 @@ class OpenurlCreatorTest < ActiveSupport::TestCase
89
91
 
90
92
  r = BentoSearch::OpenurlCreator.new(item).to_openurl.referent
91
93
 
92
- assert_equal "article", r.format
94
+ assert_equal "journal", r.format
93
95
  assert_equal "Foo Bar", r.metadata["title"]
94
96
  assert_equal "Smith", r.metadata["au"]
95
97
 
96
98
  end
97
99
 
98
- def result_item_to_openurl
100
+ def test_result_item_to_openurl
99
101
  item = BentoSearch::ResultItem.new(
100
102
  :format => "Book",
101
103
  :title => "Something",
@@ -107,5 +109,19 @@ class OpenurlCreatorTest < ActiveSupport::TestCase
107
109
  assert_kind_of OpenURL::ContextObject, openurl
108
110
  end
109
111
 
112
+ def test_strip_tags
113
+ item = BentoSearch::ResultItem.new(
114
+ :title => "<b>My Title</b>".html_safe,
115
+ :year => 2012,
116
+ :isbn => "XXXX",
117
+ )
118
+
119
+ openurl = item.to_openurl
120
+
121
+ assert_equal "My Title", openurl.referent.metadata["title"]
122
+ end
123
+
124
+
125
+
110
126
 
111
127
  end
@@ -2,12 +2,14 @@ require 'test_helper'
2
2
 
3
3
  class PrimoEngineTest < ActiveSupport::TestCase
4
4
  extend TestWithCassette
5
-
6
- @@host_port = (ENV['PRIMO_HOST_PORT'] || 'EXAMPLE.ORG:80' )
5
+
6
+ # dummy host needs to be in all lowercase, and not explicitly
7
+ # say '80' to work right with VCR
8
+ @@host_port = (ENV['PRIMO_HOST_PORT'] || 'example.org' )
7
9
  @@institution = (ENV['PRIMO_INSTITUTION'] || 'DUMMY_INSTITUTION')
8
10
 
9
11
  VCR.configure do |c|
10
- c.filter_sensitive_data("EXAMPLE.ORG:80", :primo) { @@host_port }
12
+ c.filter_sensitive_data("example.org", :primo) { @@host_port }
11
13
  c.filter_sensitive_data("DUMMY_INSTITUTION", :primo) { @@institution }
12
14
  end
13
15
 
@@ -27,10 +27,45 @@ class ResultItemTest < ActiveSupport::TestCase
27
27
  assert_equal "new", dup.title
28
28
  assert_equal "original", r.title
29
29
 
30
- assert_not_same dup, r
30
+ assert_not_same dup, r
31
+ end
32
+
33
+ def test_openurl_disabled
34
+ r = ResultItem.new(:title => "original")
35
+
36
+ assert_present r.to_openurl
37
+
38
+ r.openurl_disabled = true
39
+
40
+ assert_nil r.to_openurl
41
+ end
42
+
43
+ def test_language
44
+ r = ResultItem.new(:title => "something", :language_code => "en")
45
+ assert_equal "en", r.language_code
46
+ assert_equal "English", r.language_str
47
+
48
+ r = ResultItem.new(:title => "something", :language_code => "eng")
49
+ assert_equal "eng", r.language_code
50
+ assert_equal "English", r.language_str
31
51
 
52
+ # language_str override
53
+ r = ResultItem.new(:title => "something", :language_code => "en", :language_str => "Weird English")
54
+ assert_equal "en", r.language_code
55
+ assert_equal "Weird English", r.language_str
56
+
57
+ # language_str only
58
+ r = ResultItem.new(:title => "something", :language_str => "English")
59
+ assert_nil r.language_code
60
+ assert_equal "English", r.language_str
32
61
 
33
62
  end
34
63
 
64
+ def test_bad_language_code
65
+ r = ResultItem.new(:title => "something", :language_code => "not_valid")
66
+
67
+ assert_equal "not_valid", r.language_code
68
+ assert_nil r.language_str
69
+ end
35
70
 
36
71
  end