textacular 3.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,102 +1,183 @@
1
- require 'spec_helper'
2
- require 'textacular/searchable'
1
+ require 'support/web_comic_with_searchable'
2
+ require 'support/web_comic_with_searchable_name'
3
+ require 'support/web_comic_with_searchable_name_and_author'
4
+ require 'support/character'
3
5
 
4
- class SearchableTest < Test::Unit::TestCase
6
+ RSpec.describe "Searchable" do
5
7
  context "when extending an ActiveRecord::Base subclass" do
6
8
  context "with no parameters" do
7
- setup do
8
- @qcont = WebComicWithSearchable.create :name => "Questionable Content", :author => "Jeph Jaques"
9
- @jhony = WebComicWithSearchable.create :name => "Johnny Wander", :author => "Ananth & Yuko"
10
- @ddeeg = WebComicWithSearchable.create :name => "Dominic Deegan", :author => "Mookie"
11
- @penny = WebComicWithSearchable.create :name => "Penny Arcade", :author => "Tycho & Gabe"
12
- @null = WebComicWithSearchable.create :author => 'Foo'
9
+ let!(:questionable_content) do
10
+ WebComicWithSearchable.create(
11
+ name: 'Questionable Content',
12
+ author: 'Jeph Jaques',
13
+ )
13
14
  end
14
15
 
15
- teardown do
16
- WebComicWithSearchable.delete_all
16
+ let!(:johnny_wander) do
17
+ WebComicWithSearchable.create(
18
+ name: 'Johnny Wander',
19
+ author: 'Ananth & Yuko',
20
+ )
17
21
  end
18
22
 
19
- should "search across all columns" do
20
- assert_equal [@penny], WebComicWithSearchable.advanced_search("Penny")
21
- assert_equal [@ddeeg], WebComicWithSearchable.advanced_search("Dominic")
23
+ let!(:dominic_deegan) do
24
+ WebComicWithSearchable.create(
25
+ name: 'Dominic Deegan',
26
+ author: 'Mookie',
27
+ )
22
28
  end
23
29
 
24
- should "still rank with NULL columns" do
30
+ let!(:penny_arcade) do
31
+ WebComicWithSearchable.create(
32
+ name: 'Penny Arcade',
33
+ author: 'Tycho & Gabe',
34
+ )
35
+ end
36
+
37
+ let!(:null) do
38
+ WebComicWithSearchable.create(
39
+ author: 'Foo',
40
+ )
41
+ end
42
+
43
+ it "searches across all columns" do
44
+ expect(
45
+ WebComicWithSearchable.advanced_search("Penny")
46
+ ).to eq([penny_arcade])
47
+ expect(
48
+ WebComicWithSearchable.advanced_search("Dominic")
49
+ ).to eq([dominic_deegan])
50
+ end
51
+
52
+ it "ranks results, egen with NULL columns" do
25
53
  comic = WebComicWithSearchable.basic_search('Foo').first
26
54
  rank = comic.attributes.find { |key, value| key.to_s =~ /\Arank\d+\z/ }.last
27
55
 
28
- assert rank
56
+ expect(rank).to be_present
29
57
  end
30
58
  end
31
59
 
32
- context "with one column as parameter" do
33
- setup do
34
- @qcont = WebComicWithSearchableName.create :name => "Questionable Content", :author => "Jeph Jaques"
35
- @jhony = WebComicWithSearchableName.create :name => "Johnny Wander", :author => "Ananth & Yuko"
36
- @ddeeg = WebComicWithSearchableName.create :name => "Dominic Deegan", :author => "Mookie"
37
- @penny = WebComicWithSearchableName.create :name => "Penny Arcade", :author => "Tycho & Gabe"
60
+ context "with one column as a parameter" do
61
+ let!(:questionable_content) do
62
+ WebComicWithSearchableName.create(
63
+ name: 'Questionable Content',
64
+ author: 'Jeph Jaques',
65
+ )
38
66
  end
39
67
 
40
- teardown do
41
- WebComicWithSearchableName.delete_all
68
+ let!(:johnny_wander) do
69
+ WebComicWithSearchableName.create(
70
+ name: 'Johnny Wander',
71
+ author: 'Ananth & Yuko',
72
+ )
42
73
  end
43
74
 
44
- should "only search across the given column" do
45
- assert_equal [@penny], WebComicWithSearchableName.advanced_search("Penny")
46
- assert_empty WebComicWithSearchableName.advanced_search("Tycho")
75
+ let!(:dominic_deegan) do
76
+ WebComicWithSearchableName.create(
77
+ name: 'Dominic Deegan',
78
+ author: 'Mookie',
79
+ )
80
+ end
81
+
82
+ let!(:penny_arcade) do
83
+ WebComicWithSearchableName.create(
84
+ name: 'Penny Arcade',
85
+ author: 'Tycho & Gabe',
86
+ )
87
+ end
88
+
89
+ it "only searches across the given column" do
90
+ expect(WebComicWithSearchableName.advanced_search("Penny")).to eq([penny_arcade])
91
+
92
+ expect(WebComicWithSearchableName.advanced_search("Tycho")).to be_empty
47
93
  end
48
94
 
49
- ["hello \\", "tebow!" , "food &"].each do |search_term|
50
- should "be fine with searching for crazy character #{search_term} with plain search" do
51
- # Uses plainto_tsquery
52
- assert_equal [], WebComicWithSearchableName.basic_search(search_term)
95
+ describe "basic search" do # Uses plainto_tsquery
96
+ ["hello \\", "tebow!" , "food &"].each do |search_term|
97
+ it "works with interesting term \"#{search_term}\"" do
98
+ expect(WebComicWithSearchableName.basic_search(search_term)).to be_empty
99
+ end
53
100
  end
101
+ end
54
102
 
55
- should "be not fine with searching for crazy character #{search_term} with advanced search" do
56
- # Uses to_tsquery
57
- assert_raise(ActiveRecord::StatementInvalid) do
58
- WebComicWithSearchableName.advanced_search(search_term).first
103
+ describe "advanced_search" do # Uses to_tsquery
104
+ ["hello \\", "tebow!" , "food &"].each do |search_term|
105
+ it "fails with interesting term \"#{search_term}\"" do
106
+ expect {
107
+ WebComicWithSearchableName.advanced_search(search_term).first
108
+ }.to raise_error(ActiveRecord::StatementInvalid)
59
109
  end
60
110
  end
61
111
  end
62
112
 
63
- should "fuzzy search stuff" do
64
- assert_equal [@qcont], WebComicWithSearchableName.fuzzy_search('Questio')
113
+ it "does fuzzy searching" do
114
+ expect(
115
+ WebComicWithSearchableName.fuzzy_search('Questio')
116
+ ).to eq([questionable_content])
65
117
  end
66
118
 
67
- should "define :searchable_columns as private" do
68
- assert_raise(NoMethodError) { WebComicWithSearchableName.searchable_columns }
119
+ it "defines :searchable_columns as private" do
120
+ expect { WebComicWithSearchableName.searchable_columns }.to raise_error(NoMethodError)
121
+
69
122
  begin
70
123
  WebComicWithSearchableName.searchable_columns
71
124
  rescue NoMethodError => error
72
- assert_match /private method/, error.message
125
+ expect(error.message).to match(/private method/)
73
126
  end
74
127
  end
75
128
 
76
- should "define #indexable_columns which returns a write-proof Enumerable" do
77
- assert_equal(Enumerator, WebComicWithSearchableName.indexable_columns.class)
78
- assert_raise(NoMethodError) { WebComicWithSearchableName.indexable_columns[0] = 'foo' }
129
+ it "defines #indexable_columns which returns a write-proof Enumerable" do
130
+ expect(WebComicWithSearchableName.indexable_columns).to be_an(Enumerator)
131
+
132
+ expect {
133
+ WebComicWithSearchableName.indexable_columns[0] = 'foo'
134
+ }.to raise_error(NoMethodError)
79
135
  end
80
136
  end
81
137
 
82
138
  context "with two columns as parameters" do
83
- setup do
84
- @qcont = WebComicWithSearchableNameAndAuthor.create :name => "Questionable Content", :author => "Jeph Jaques"
85
- @jhony = WebComicWithSearchableNameAndAuthor.create :name => "Johnny Wander", :author => "Ananth & Yuko"
86
- @ddeeg = WebComicWithSearchableNameAndAuthor.create :name => "Dominic Deegan", :author => "Mookie"
87
- @penny = WebComicWithSearchableNameAndAuthor.create :name => "Penny Arcade", :author => "Tycho & Gabe"
139
+ let!(:questionable_content) do
140
+ WebComicWithSearchableNameAndAuthor.create(
141
+ name: 'Questionable Content',
142
+ author: 'Jeph Jaques',
143
+ )
144
+ end
145
+
146
+ let!(:johnny_wander) do
147
+ WebComicWithSearchableNameAndAuthor.create(
148
+ name: 'Johnny Wander',
149
+ author: 'Ananth & Yuko',
150
+ )
88
151
  end
89
152
 
90
- teardown do
91
- WebComicWithSearchableNameAndAuthor.delete_all
153
+ let!(:dominic_deegan) do
154
+ WebComicWithSearchableNameAndAuthor.create(
155
+ name: 'Dominic Deegan',
156
+ author: 'Mookie',
157
+ )
92
158
  end
93
159
 
94
- should "only search across the given column" do
95
- assert_equal [@penny], WebComicWithSearchableNameAndAuthor.advanced_search("Penny")
96
- assert_equal [@penny], WebComicWithSearchableNameAndAuthor.advanced_search("Tycho")
160
+ let!(:penny_arcade) do
161
+ WebComicWithSearchableNameAndAuthor.create(
162
+ name: 'Penny Arcade',
163
+ author: 'Tycho & Gabe',
164
+ )
97
165
  end
98
- should "allow includes" do
99
- assert_equal [@penny], WebComicWithSearchableNameAndAuthor.includes(:characters).advanced_search("Penny")
166
+
167
+ it "only searches across the given columns" do
168
+ expect(
169
+ WebComicWithSearchableNameAndAuthor.advanced_search("Penny")
170
+ ).to eq([penny_arcade])
171
+
172
+ expect(
173
+ WebComicWithSearchableNameAndAuthor.advanced_search("Tycho")
174
+ ).to eq([penny_arcade])
175
+ end
176
+
177
+ it "allows includes" do
178
+ expect(
179
+ WebComicWithSearchableNameAndAuthor.includes(:characters).advanced_search("Penny")
180
+ ).to eq([penny_arcade])
100
181
  end
101
182
  end
102
183
  end
@@ -0,0 +1,24 @@
1
+ RSpec.describe "Textacular::TrigramInstaller" do
2
+ let(:content) do
3
+ <<-MIGRATION
4
+ class InstallTrigram < ActiveRecord::Migration
5
+ def self.up
6
+ ActiveRecord::Base.connection.execute("CREATE EXTENSION pg_trgm;")
7
+ end
8
+
9
+ def self.down
10
+ ActiveRecord::Base.connection.execute("DROP EXTENSION pg_trgm;")
11
+ end
12
+ end
13
+ MIGRATION
14
+ end
15
+
16
+ it "generates a migration" do
17
+ generator = double(:migration_generator)
18
+
19
+ expect(Textacular::MigrationGenerator).to receive(:new).with('install_trigram', content).and_return(generator)
20
+ expect(generator).to receive(:generate_migration)
21
+
22
+ Textacular::TrigramInstaller.new.generate_migration
23
+ end
24
+ end
@@ -1,215 +1,357 @@
1
1
  # coding: utf-8
2
- require 'spec_helper'
2
+ # Above for Ruby 1.9 tests
3
3
 
4
- class TextacularTest < Test::Unit::TestCase
4
+ require 'support/ar_stand_in'
5
+ require 'support/not_there'
6
+ require 'support/textacular_web_comic'
7
+ require 'support/game_extended_with_textacular'
8
+ require 'support/game_extended_with_textacular_and_custom_language'
9
+ require 'support/game_fail_extended_with_textacular'
10
+
11
+ RSpec.describe Textacular do
5
12
  context "after extending ActiveRecord::Base" do
6
- should "not break #respond_to?" do
7
- assert_nothing_raised do
8
- ARStandIn.respond_to? :abstract_class?
9
- end
13
+ it "doesn't break #respond_to?" do
14
+ expect{ ARStandIn.respond_to?(:abstract_class?) }.to_not raise_error
10
15
  end
11
16
 
12
- should "not break #respond_to? for table-less classes" do
13
- assert !NotThere.table_exists?
14
- assert_nothing_raised do
15
- NotThere.respond_to? :system
16
- end
17
+ it "doesn't break #respond_to? for table-less classes" do
18
+ expect(NotThere.table_exists?).to be_falsey
19
+ expect { NotThere.respond_to? :system }.to_not raise_error
17
20
  end
18
21
 
19
- should "not break #method_missing" do
20
- assert_raise(NoMethodError) { ARStandIn.random }
22
+ it "doesn't break #method_missing" do
23
+ expect { ARStandIn.random }.to raise_error(NoMethodError)
24
+
21
25
  begin
22
26
  ARStandIn.random
23
27
  rescue NoMethodError => error
24
- assert_match /undefined method `random'/, error.message
28
+ expect(error.message).to match(/undefined method `random'/)
25
29
  end
26
30
  end
27
31
 
28
- should "not break #method_missing for table-less classes" do
29
- assert !NotThere.table_exists?
30
- assert_raise(NoMethodError) { NotThere.random }
32
+ it "doesn't break #method_missing for table-less classes" do
33
+ expect(NotThere.table_exists?).to be_falsey
34
+
35
+ expect { NotThere.random }.to raise_error(NoMethodError)
36
+
31
37
  begin
32
38
  NotThere.random
33
39
  rescue NoMethodError => error
34
- assert_match /undefined method `random'/, error.message
40
+ expect(error.message).to match(/undefined method `random'/)
35
41
  end
36
42
  end
37
43
 
38
44
  context "when finding models based on searching a related model" do
39
- setup do
40
- @qc = TextacularWebComic.create :name => "Questionable Content", :author => "Jeph Jaques"
41
- @jw = TextacularWebComic.create :name => "Johnny Wander", :author => "Ananth & Yuko"
42
- @pa = TextacularWebComic.create :name => "Penny Arcade", :author => "Tycho & Gabe"
43
-
44
- @gabe = @pa.characters.create :name => 'Gabe', :description => 'the simple one'
45
- @tycho = @pa.characters.create :name => 'Tycho', :description => 'the wordy one'
46
- @div = @pa.characters.create :name => 'Div', :description => 'a crude divx player with anger management issues'
47
-
48
- @martin = @qc.characters.create :name => 'Martin', :description => 'the insecure protagonist'
49
- @faye = @qc.characters.create :name => 'Faye', :description => 'a sarcastic barrista with anger management issues'
50
- @pintsize = @qc.characters.create :name => 'Pintsize', :description => 'a crude AnthroPC'
51
-
52
- @ananth = @jw.characters.create :name => 'Ananth', :description => 'Stubble! What is under that hat?!?'
53
- @yuko = @jw.characters.create :name => 'Yuko', :description => 'So... small. Carl Sagan haircut.'
54
- @john = @jw.characters.create :name => 'John', :description => 'Tall. Anger issues?'
55
- @cricket = @jw.characters.create :name => 'Cricket', :description => 'Chirrup!'
45
+ let(:webcomics_with_tall_characters) do
46
+ [johnny_wander]
56
47
  end
57
48
 
58
- teardown do
59
- TextacularWebComic.delete_all
60
- Character.delete_all
49
+ let(:webcomics_with_angry_characters) do
50
+ [johnny_wander, penny_arcade, questionable_content]
61
51
  end
62
52
 
63
- should "look in the related model with nested searching syntax" do
64
- assert_equal [@jw], TextacularWebComic.joins(:characters).advanced_search(:characters => {:description => 'tall'})
65
- assert_equal [@pa, @jw, @qc].sort, TextacularWebComic.joins(:characters).advanced_search(:characters => {:description => 'anger'}).sort
66
- assert_equal [@pa, @qc].sort, TextacularWebComic.joins(:characters).advanced_search(:characters => {:description => 'crude'}).sort
53
+ let(:webcomics_with_crude_characters) do
54
+ [penny_arcade, questionable_content]
67
55
  end
68
- end
69
- end
70
56
 
71
- context "after extending an ActiveRecord::Base subclass" do
72
- setup do
73
- @zelda = GameExtendedWithTextacular.create :system => "NES", :title => "Legend of Zelda", :description => "A Link to the Past."
74
- @mario = GameExtendedWithTextacular.create :system => "NES", :title => "Super Mario Bros.", :description => "The original platformer."
75
- @sonic = GameExtendedWithTextacular.create :system => "Genesis", :title => "Sonic the Hedgehog", :description => "Spiky."
76
- @dkong = GameExtendedWithTextacular.create :system => "SNES", :title => "Diddy's Kong Quest", :description => "Donkey Kong Country 2"
77
- @megam = GameExtendedWithTextacular.create :system => nil, :title => "Mega Man", :description => "Beware Dr. Brain"
78
- @sfnes = GameExtendedWithTextacular.create :system => "SNES", :title => "Street Fighter 2", :description => "Yoga Flame!"
79
- @sfgen = GameExtendedWithTextacular.create :system => "Genesis", :title => "Street Fighter 2", :description => "Yoga Flame!"
80
- @takun = GameExtendedWithTextacular.create :system => "Saturn", :title => "Magical Tarurūto-kun", :description => "カッコイイ!"
81
- end
82
-
83
- teardown do
84
- GameExtendedWithTextacular.delete_all
85
- end
86
-
87
- should "not break respond_to? when connection is unavailable" do
88
- GameFailExtendedWithTextacular.establish_connection({:adapter => :postgresql, :database =>'unavailable', :username=>'bad', :pool=>5, :timeout=>5000}) rescue nil
89
-
90
- assert_nothing_raised do
91
- GameFailExtendedWithTextacular.respond_to?(:advanced_search)
92
- end
93
- end
94
-
95
- should "define a #search method" do
96
- assert GameExtendedWithTextacular.respond_to?(:search)
97
- end
98
-
99
- context "when searching with a String argument" do
100
- should "search across all :string columns if no indexes have been specified" do
101
- assert_equal [@mario], GameExtendedWithTextacular.advanced_search("Mario")
102
- assert_equal Set.new([@mario, @zelda]), GameExtendedWithTextacular.advanced_search("NES").to_set
57
+ let!(:johnny_wander) do
58
+ TextacularWebComic.create(:name => "Johnny Wander", :author => "Ananth & Yuko").tap do |comic|
59
+ comic.characters.create :name => 'Ananth', :description => 'Stubble! What is under that hat?!?'
60
+ comic.characters.create :name => 'Yuko', :description => 'So... small. Carl Sagan haircut.'
61
+ comic.characters.create :name => 'John', :description => 'Tall. Anger issues?'
62
+ comic.characters.create :name => 'Cricket', :description => 'Chirrup!'
63
+ end
103
64
  end
104
65
 
105
- should "work if the query contains an apostrophe" do
106
- assert_equal [@dkong], GameExtendedWithTextacular.advanced_search("Diddy's")
66
+ let!(:questionable_content) do
67
+ TextacularWebComic.create(:name => "Questionable Content", :author => "Jeph Jaques").tap do |comic|
68
+ comic.characters.create :name => 'Martin', :description => 'the insecure protagonist'
69
+ comic.characters.create :name => 'Faye', :description => 'a sarcastic barrista with anger management issues'
70
+ comic.characters.create :name => 'Pintsize', :description => 'a crude AnthroPC'
71
+ end
107
72
  end
108
73
 
109
- should "work if the query contains whitespace" do
110
- assert_equal [@megam], GameExtendedWithTextacular.advanced_search("Mega Man")
74
+ let!(:penny_arcade) do
75
+ TextacularWebComic.create(:name => "Penny Arcade", :author => "Tycho & Gabe").tap do |comic|
76
+ comic.characters.create :name => 'Gabe', :description => 'the simple one'
77
+ comic.characters.create :name => 'Tycho', :description => 'the wordy one'
78
+ comic.characters.create :name => 'Div', :description => 'a crude divx player with anger management issues'
79
+ end
111
80
  end
112
81
 
113
- should "work if the query contains an accent" do
114
- assert_equal [@takun], GameExtendedWithTextacular.advanced_search("Tarurūto-kun")
82
+ it "looks in the related model with nested searching syntax" do
83
+ expect(
84
+ TextacularWebComic.joins(:characters).advanced_search(
85
+ :characters => {:description => 'tall'}
86
+ )
87
+ ).to eq(webcomics_with_tall_characters)
88
+
89
+ expect(
90
+ TextacularWebComic.joins(:characters).advanced_search(
91
+ :characters => {:description => 'anger'}
92
+ ).sort
93
+ ).to eq(webcomics_with_angry_characters.sort)
94
+
95
+ expect(
96
+ TextacularWebComic.joins(:characters).advanced_search(
97
+ :characters => {:description => 'crude'}
98
+ ).sort
99
+ ).to eq(webcomics_with_crude_characters.sort)
115
100
  end
101
+ end
102
+ end
116
103
 
117
- should "search across records with NULL values" do
118
- assert_equal [@megam], GameExtendedWithTextacular.advanced_search("Mega")
104
+ context "after extending an ActiveRecord::Base subclass" do
105
+ context "when the DB connection is unavailable" do
106
+ before do
107
+ GameFailExtendedWithTextacular.establish_connection({:adapter => :postgresql, :database =>'unavailable', :username=>'bad', :pool=>5, :timeout=>5000}) rescue nil
119
108
  end
120
109
 
121
- should "scope consecutively" do
122
- assert_equal [@sfgen], GameExtendedWithTextacular.advanced_search("Genesis").advanced_search("Street Fighter")
110
+ it "doesn't break respond_to?" do
111
+ expect { GameFailExtendedWithTextacular.respond_to?(:advanced_search) }.to_not raise_error
123
112
  end
124
113
  end
125
114
 
126
- context "when searching with a Hash argument" do
127
- should "search across the given columns" do
128
- assert_empty GameExtendedWithTextacular.advanced_search(:title => "NES")
129
- assert_empty GameExtendedWithTextacular.advanced_search(:system => "Mario")
130
- assert_empty GameExtendedWithTextacular.advanced_search(:system => "NES", :title => "Sonic")
131
-
132
- assert_equal [@mario], GameExtendedWithTextacular.advanced_search(:title => "Mario")
133
-
134
- assert_equal 2, GameExtendedWithTextacular.advanced_search(:system => "NES").count
135
-
136
- assert_equal [@zelda], GameExtendedWithTextacular.advanced_search(:system => "NES", :title => "Zelda")
137
- assert_equal [@megam], GameExtendedWithTextacular.advanced_search(:title => "Mega")
115
+ context "when the DB connection is available" do
116
+ let!(:zelda) do
117
+ GameExtendedWithTextacular.create(
118
+ :system => "NES",
119
+ :title => "Legend of Zelda",
120
+ :description => "A Link to the Past."
121
+ )
138
122
  end
139
123
 
140
- should "scope consecutively" do
141
- assert_equal [@sfgen], GameExtendedWithTextacular.advanced_search(:system => "Genesis").advanced_search(:title => "Street Fighter")
124
+ let!(:mario) do
125
+ GameExtendedWithTextacular.create(
126
+ :system => "NES",
127
+ :title => "Super Mario Bros.",
128
+ :description => "The original platformer."
129
+ )
142
130
  end
143
131
 
144
- should "cast non-:string columns as text" do
145
- assert_equal [@mario], GameExtendedWithTextacular.advanced_search(:id => @mario.id)
146
- end
147
- end
148
-
149
- context "when using dynamic search methods" do
150
- should "generate methods for each :string column" do
151
- assert_equal [@mario], GameExtendedWithTextacular.advanced_search_by_title("Mario")
152
- assert_equal [@takun], GameExtendedWithTextacular.advanced_search_by_system("Saturn")
132
+ let!(:sonic) do
133
+ GameExtendedWithTextacular.create(
134
+ :system => "Genesis",
135
+ :title => "Sonic the Hedgehog",
136
+ :description => "Spiky."
137
+ )
153
138
  end
154
139
 
155
- should "generate methods for each :text column" do
156
- assert_equal [@mario], GameExtendedWithTextacular.advanced_search_by_description("platform")
140
+ let!(:donkey_kong) do
141
+ GameExtendedWithTextacular.create(
142
+ :system => "SNES",
143
+ :title => "Diddy's Kong Quest",
144
+ :description => "Donkey Kong Country 2"
145
+ )
157
146
  end
158
147
 
159
- should "generate methods for any combination of :string and :text columns" do
160
- assert_equal [@mario], GameExtendedWithTextacular.advanced_search_by_title_and_system("Mario", "NES")
161
- assert_equal [@sonic], GameExtendedWithTextacular.advanced_search_by_system_and_title("Genesis", "Sonic")
162
- assert_equal [@mario], GameExtendedWithTextacular.advanced_search_by_title_and_title("Mario", "Mario")
163
- assert_equal [@megam], GameExtendedWithTextacular.advanced_search_by_title_and_description("Man", "Brain")
148
+ let!(:mega_man) do
149
+ GameExtendedWithTextacular.create(
150
+ :system => nil,
151
+ :title => "Mega Man",
152
+ :description => "Beware Dr. Brain"
153
+ )
164
154
  end
165
155
 
166
- should "generate methods for inclusive searches" do
167
- assert_equal Set.new([@megam, @takun]), GameExtendedWithTextacular.advanced_search_by_system_or_title("Saturn", "Mega Man").to_set
156
+ let!(:sf_nes) do
157
+ GameExtendedWithTextacular.create(
158
+ :system => "SNES",
159
+ :title => "Street Fighter 2",
160
+ :description => "Yoga Flame!"
161
+ )
168
162
  end
169
163
 
170
- should "scope consecutively" do
171
- assert_equal [@sfgen], GameExtendedWithTextacular.advanced_search_by_system("Genesis").advanced_search_by_title("Street Fighter")
164
+ let!(:sf_genesis) do
165
+ GameExtendedWithTextacular.create(
166
+ :system => "Genesis",
167
+ :title => "Street Fighter 2",
168
+ :description => "Yoga Flame!"
169
+ )
172
170
  end
173
171
 
174
- should "generate methods for non-:string columns" do
175
- assert_equal [@mario], GameExtendedWithTextacular.advanced_search_by_id(@mario.id)
172
+ let!(:takun) do
173
+ GameExtendedWithTextacular.create(
174
+ :system => "Saturn",
175
+ :title => "Magical Tarurūto-kun",
176
+ :description => "カッコイイ!"
177
+ )
176
178
  end
177
179
 
178
- should "work with #respond_to?" do
179
- assert GameExtendedWithTextacular.respond_to?(:advanced_search_by_system)
180
- assert GameExtendedWithTextacular.respond_to?(:advanced_search_by_title)
181
- assert GameExtendedWithTextacular.respond_to?(:advanced_search_by_system_and_title)
182
- assert GameExtendedWithTextacular.respond_to?(:advanced_search_by_system_or_title)
183
- assert GameExtendedWithTextacular.respond_to?(:advanced_search_by_title_and_title_and_title)
184
- assert GameExtendedWithTextacular.respond_to?(:advanced_search_by_id)
185
-
186
- assert !GameExtendedWithTextacular.respond_to?(:advanced_search_by_title_and_title_or_title)
180
+ it "defines a #search method" do
181
+ expect(GameExtendedWithTextacular).to respond_to(:search)
187
182
  end
188
183
 
189
- should "allow for 2 arguments to #respond_to?" do
190
- assert GameExtendedWithTextacular.respond_to?(:searchable_language, true)
191
- end
192
- end
184
+ describe "#advanced_search" do
185
+ context "with a String argument" do
186
+ it "searches across all :string columns (if not indexes have been specified)" do
187
+ expect(
188
+ GameExtendedWithTextacular.advanced_search("Mario")
189
+ ).to eq([mario])
190
+
191
+ expect(
192
+ GameExtendedWithTextacular.advanced_search("NES").to_set
193
+ ).to eq(Set.new([mario, zelda]))
194
+ end
195
+
196
+ it "works if a query has an apostrophe" do
197
+ expect(GameExtendedWithTextacular.advanced_search("Diddy's")).to eq([donkey_kong])
198
+ end
199
+
200
+ it "works if the query contains whitespace" do
201
+ expect(GameExtendedWithTextacular.advanced_search("Mega Man")).to eq([mega_man])
202
+ end
203
+
204
+ it "works if the query contains an accent" do
205
+ expect(GameExtendedWithTextacular.advanced_search("Tarurūto-kun")).to eq([takun])
206
+ end
207
+
208
+ it "searches across records with NULL values" do
209
+ expect(GameExtendedWithTextacular.advanced_search("Mega")).to eq([mega_man])
210
+ end
211
+
212
+ it "scopes consecutively" do
213
+ expect(
214
+ GameExtendedWithTextacular.advanced_search("Genesis").advanced_search("Street Fighter")
215
+ ).to eq([sf_genesis])
216
+ end
217
+ end
193
218
 
194
- context "when searching after selecting columns to return" do
195
- should "not fetch extra columns" do
196
- assert_raise(ActiveModel::MissingAttributeError) do
197
- GameExtendedWithTextacular.select(:title).advanced_search("Mario").first.system
219
+ context "with a Hash argument" do
220
+ it "searches across the given columns" do
221
+ expect(
222
+ GameExtendedWithTextacular.advanced_search(:title => 'NES')
223
+ ).to be_empty
224
+ expect(
225
+ GameExtendedWithTextacular.advanced_search(:system => "Mario")
226
+ ).to be_empty
227
+ expect(
228
+ GameExtendedWithTextacular.advanced_search(:system => "NES", :title => "Sonic")
229
+ ).to be_empty
230
+
231
+ expect(
232
+ GameExtendedWithTextacular.advanced_search(:title => "Mario")
233
+ ).to eq([mario])
234
+
235
+ expect(
236
+ GameExtendedWithTextacular.advanced_search(:system => "NES").size
237
+ ).to eq(2)
238
+
239
+ expect(
240
+ GameExtendedWithTextacular.advanced_search(:system => "NES", :title => "Zelda")
241
+ ).to eq([zelda])
242
+ expect(
243
+ GameExtendedWithTextacular.advanced_search(:title => "Mega")
244
+ ).to eq([mega_man])
245
+ end
246
+
247
+ it "scopes consecutively" do
248
+ expect(
249
+ GameExtendedWithTextacular
250
+ .advanced_search(:system => "Genesis")
251
+ .advanced_search(:title => "Street Fighter")
252
+ ).to eq([sf_genesis])
253
+ end
254
+
255
+ it "casts non-string columns as text" do
256
+ expect(
257
+ GameExtendedWithTextacular.advanced_search(:id => mario.id)
258
+ ).to eq([mario])
259
+ end
198
260
  end
199
- end
200
- end
201
261
 
202
- context "when setting a custom search language" do
203
- setup do
204
- GameExtendedWithTextacularAndCustomLanguage.create :system => "PS3", :title => "Harry Potter & the Deathly Hallows"
205
- end
262
+ context "via dynamic method names" do
263
+ it "only exists prior to 4.0.0" do
264
+ current_version = Gem::Version.new(Textacular.version)
265
+
266
+ expect(current_version).to be < Gem::Version.new("4.0.0")
267
+ end
268
+
269
+ it "generates methods for each string column" do
270
+ expect(
271
+ GameExtendedWithTextacular.advanced_search_by_title("Mario")
272
+ ).to eq([mario])
273
+ expect(
274
+ GameExtendedWithTextacular.advanced_search_by_system("Saturn")
275
+ ).to eq([takun])
276
+ end
277
+
278
+ it "generates methods for each text column" do
279
+ expect(
280
+ GameExtendedWithTextacular.advanced_search_by_description("platform")
281
+ ).to eq([mario])
282
+ end
283
+
284
+ it "generates methods for any combination of string and text columns" do
285
+ expect(
286
+ GameExtendedWithTextacular.advanced_search_by_title_and_system("Mario", "NES")
287
+ ).to eq([mario])
288
+ expect(
289
+ GameExtendedWithTextacular.advanced_search_by_system_and_title("Genesis", "Sonic")
290
+ ).to eq([sonic])
291
+ expect(
292
+ GameExtendedWithTextacular.advanced_search_by_title_and_title("Mario", "Mario")
293
+ ).to eq([mario])
294
+ expect(
295
+ GameExtendedWithTextacular.advanced_search_by_title_and_description("Man", "Brain")
296
+ ).to eq([mega_man])
297
+ end
298
+
299
+ it "generates methods for inclusive searches" do
300
+ expect(
301
+ GameExtendedWithTextacular.advanced_search_by_system_or_title("Saturn", "Mega Man").to_set
302
+ ).to eq(Set.new([mega_man, takun]))
303
+ end
304
+
305
+ it "scopes consecutively" do
306
+ expect(
307
+ GameExtendedWithTextacular.advanced_search_by_system("Genesis").advanced_search_by_title("Street Fighter")
308
+ ).to eq([sf_genesis])
309
+ end
310
+
311
+ it "generates methods for non-string columns" do
312
+ expect(
313
+ GameExtendedWithTextacular.advanced_search_by_id(mario.id)
314
+ ).to eq([mario])
315
+ end
316
+
317
+ it "works with #respond_to?" do
318
+ expect(GameExtendedWithTextacular).to respond_to(:advanced_search_by_system)
319
+ expect(GameExtendedWithTextacular).to respond_to(:advanced_search_by_title)
320
+ expect(GameExtendedWithTextacular).to respond_to(:advanced_search_by_system_and_title)
321
+ expect(GameExtendedWithTextacular).to respond_to(:advanced_search_by_system_or_title)
322
+ expect(GameExtendedWithTextacular).to respond_to(:advanced_search_by_title_and_title_and_title)
323
+ expect(GameExtendedWithTextacular).to respond_to(:advanced_search_by_id)
324
+
325
+ expect(GameExtendedWithTextacular).to_not respond_to(:advanced_search_by_title_and_title_or_title)
326
+ end
327
+
328
+ it "allows for 2 arguments to #respond_to?" do
329
+ expect(GameExtendedWithTextacular.respond_to?(:searchable_language, true)).to be_truthy
330
+ end
331
+ end
206
332
 
207
- teardown do
208
- GameExtendedWithTextacularAndCustomLanguage.delete_all
209
- end
333
+ context "after selecting columns to return" do
334
+ it "doesn't fetch extra columns" do
335
+ expect {
336
+ GameExtendedWithTextacular.select(:title).advanced_search("Mario").first.system
337
+ }.to raise_error(ActiveModel::MissingAttributeError)
338
+ end
339
+ end
210
340
 
211
- should "still find results" do
212
- assert_not_empty GameExtendedWithTextacularAndCustomLanguage.advanced_search_by_title("harry")
341
+ context "after setting a custom language" do
342
+ let!(:harry_potter_7) do
343
+ GameExtendedWithTextacularAndCustomLanguage.create(
344
+ :system => "PS3",
345
+ :title => "Harry Potter & the Deathly Hallows"
346
+ )
347
+ end
348
+
349
+ it "finds results" do
350
+ expect(
351
+ GameExtendedWithTextacularAndCustomLanguage.advanced_search_by_title("harry")
352
+ ).to eq([harry_potter_7])
353
+ end
354
+ end
213
355
  end
214
356
  end
215
357
  end