textacular 3.2.0 → 3.2.1

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.
@@ -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