bento_search 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +6 -5
- data/app/assets/javascripts/bento_search/ajax_load.js +42 -16
- data/app/assets/stylesheets/bento_search/suggested_styles.css +9 -0
- data/app/controllers/bento_search/search_controller.rb +15 -6
- data/app/helpers/bento_search_helper.rb +24 -8
- data/app/item_decorators/bento_search/no_links.rb +13 -0
- data/app/models/bento_search/openurl_creator.rb +18 -8
- data/app/models/bento_search/registrar.rb +2 -6
- data/app/models/bento_search/result_item.rb +43 -3
- data/app/models/bento_search/results.rb +4 -0
- data/app/models/bento_search/search_engine.rb +25 -23
- data/app/search_engines/bento_search/ebsco_host_engine.rb +42 -17
- data/app/search_engines/bento_search/google_books_engine.rb +2 -0
- data/app/search_engines/bento_search/google_site_search_engine.rb +177 -0
- data/app/search_engines/bento_search/mock_engine.rb +5 -0
- data/app/search_engines/bento_search/primo_engine.rb +23 -2
- data/app/search_engines/bento_search/scopus_engine.rb +4 -1
- data/app/search_engines/bento_search/summon_engine.rb +4 -14
- data/app/search_engines/bento_search/worldcat_sru_dc_engine.rb +293 -0
- data/app/views/bento_search/_std_item.html.erb +4 -5
- data/app/views/bento_search/_wrap_with_count.html.erb +20 -0
- data/app/views/bento_search/search/search.html.erb +15 -1
- data/config/locales/en.yml +6 -4
- data/lib/bento_search/util.rb +13 -0
- data/lib/bento_search/version.rb +1 -1
- data/test/dummy/log/development.log +1 -0
- data/test/dummy/log/test.log +24357 -0
- data/test/functional/bento_search/search_controller_test.rb +39 -0
- data/test/helper/bento_search_helper_test.rb +47 -5
- data/test/unit/ebsco_host_engine_test.rb +15 -0
- data/test/unit/google_books_engine_test.rb +1 -0
- data/test/unit/google_site_search_test.rb +122 -0
- data/test/unit/item_decorators_test.rb +12 -1
- data/test/unit/openurl_creator_test.rb +19 -3
- data/test/unit/primo_engine_test.rb +5 -3
- data/test/unit/result_item_test.rb +36 -1
- data/test/unit/search_engine_test.rb +27 -4
- data/test/unit/worldcat_sru_dc_engine_test.rb +120 -0
- data/test/vcr_cassettes/google_site/basic_smoke_test.yml +254 -0
- data/test/vcr_cassettes/google_site/empty_result_set.yml +53 -0
- data/test/vcr_cassettes/google_site/pagination_object_is_correct_for_actual_page_when_you_ask_for_too_far.yml +260 -0
- data/test/vcr_cassettes/google_site/with_highlighting.yml +265 -0
- data/test/vcr_cassettes/google_site/without_highlighting.yml +267 -0
- data/test/vcr_cassettes/primo/proper_tags_for_snippets.yml +517 -502
- data/test/vcr_cassettes/primo/search_smoke_test.yml +1 -1
- data/test/vcr_cassettes/worldcat_sru_dc/smoke_test.yml +628 -0
- 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("&", "&")) # 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 =
|
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
|
@@ -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
|
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
|
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 "
|
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
|
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
|
-
|
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("
|
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
|