search_cop 1.2.3 → 1.3.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.
@@ -1,166 +0,0 @@
1
- require File.expand_path("test_helper", __dir__)
2
-
3
- class SearchCopTest < SearchCop::TestCase
4
- def test_scope_before
5
- expected = create(:product, stock: 1, title: "Title")
6
- rejected = create(:product, stock: 0, title: "Title")
7
-
8
- results = Product.where(stock: 1).search("Title")
9
-
10
- assert_includes results, expected
11
- refute_includes results, rejected
12
- end
13
-
14
- def test_scope_after
15
- expected = create(:product, stock: 1, title: "Title")
16
- rejected = create(:product, stock: 0, title: "Title")
17
-
18
- results = Product.search("Title").where(stock: 1)
19
-
20
- assert_includes results, expected
21
- refute_includes results, rejected
22
- end
23
-
24
- def test_scope
25
- expected = create(:product, stock: 1, title: "Title")
26
- rejected = create(:product, stock: 0, title: "Title")
27
-
28
- results = with_scope(Product.search_scopes[:search], -> { where stock: 1 }) { Product.search("title: Title") }
29
-
30
- assert_includes results, expected
31
- refute_includes results, rejected
32
- end
33
-
34
- def test_multi_associations
35
- product = create(:product, comments: [
36
- create(:comment, title: "Title1", message: "Message1"),
37
- create(:comment, title: "Title2", message: "Message2")
38
- ])
39
-
40
- assert_includes Product.search("comment: Title1 comment: Message1"), product
41
- assert_includes Product.search("comment: Title2 comment: Message2"), product
42
- end
43
-
44
- def test_single_association
45
- expected = create(:comment, user: create(:user, username: "Expected"))
46
- rejected = create(:comment, user: create(:user, username: "Rejected"))
47
-
48
- results = Comment.search("user: Expected")
49
-
50
- assert_includes results, expected
51
- refute_includes results, rejected
52
- end
53
-
54
- def test_deep_associations
55
- expected = create(:product, comments: [create(:comment, user: create(:user, username: "Expected"))])
56
- rejected = create(:product, comments: [create(:comment, user: create(:user, username: "Rejected"))])
57
-
58
- results = Product.search("user: Expected")
59
-
60
- assert_includes results, expected
61
- refute_includes results, rejected
62
- end
63
-
64
- def test_inherited_model
65
- expected = create(:available_product, comments: [create(:comment, user: create(:user, username: "Expected"))])
66
- rejected = create(:available_product, comments: [create(:comment, user: create(:user, username: "Rejected"))])
67
-
68
- results = AvailableProduct.search("user: Expected")
69
- assert_includes results, expected
70
- refute_includes results, rejected
71
- end
72
-
73
- def test_namespaced_model
74
- expected = create(:blog_post, title: "Expected")
75
- rejected = create(:blog_post, title: "Rejected")
76
-
77
- results = Blog::Post.search("Expected")
78
-
79
- assert_includes results, expected
80
- refute_includes results, rejected
81
- end
82
-
83
- def test_namespaced_model_with_associations
84
- expected = create(:blog_post, user: create(:user, username: "Expected"))
85
- rejected = create(:blog_post, user: create(:user, username: "Rejected"))
86
-
87
- results = Blog::Post.search("user:Expected")
88
-
89
- assert_includes results, expected
90
- refute_includes results, rejected
91
- end
92
-
93
- def test_multiple
94
- product = create(:product, comments: [create(:comment, title: "Title", message: "Message")])
95
-
96
- assert_includes Product.search("comment: Title"), product
97
- assert_includes Product.search("comment: Message"), product
98
- end
99
-
100
- def test_default
101
- product1 = create(:product, title: "Expected")
102
- product2 = create(:product, description: "Expected")
103
-
104
- results = Product.search("Expected")
105
-
106
- assert_includes results, product1
107
- assert_includes results, product2
108
- end
109
-
110
- def test_custom_default_enabled
111
- product1 = create(:product, title: "Expected")
112
- product2 = create(:product, description: "Expected")
113
- product3 = create(:product, brand: "Expected")
114
-
115
- results = with_options(Product.search_scopes[:search], :primary, default: true) { Product.search "Expected" }
116
-
117
- assert_includes results, product1
118
- assert_includes results, product2
119
- refute_includes results, product3
120
- end
121
-
122
- def test_custom_default_disabled
123
- product1 = create(:product, brand: "Expected")
124
- product2 = create(:product, notice: "Expected")
125
-
126
- results = with_options(Product.search_scopes[:search], :notice, default: false) { Product.search "Expected" }
127
-
128
- assert_includes results, product1
129
- refute_includes results, product2
130
- end
131
-
132
- def test_count
133
- create_list :product, 2, title: "Expected"
134
-
135
- assert_equal 2, Product.search("Expected").count
136
- end
137
-
138
- def test_default_attributes_true
139
- with_options(Product.search_scopes[:search], :title, default: true) do
140
- with_options(Product.search_scopes[:search], :description, default: true) do
141
- assert_equal ["title", "description"], Product.search_scopes[:search].reflection.default_attributes.keys
142
- end
143
- end
144
- end
145
-
146
- def test_default_attributes_fales
147
- with_options(Product.search_scopes[:search], :title, default: false) do
148
- with_options(Product.search_scopes[:search], :description, default: false) do
149
- assert_equal Product.search_scopes[:search].reflection.attributes.keys - ["title", "description"], Product.search_scopes[:search].reflection.default_attributes.keys
150
- end
151
- end
152
- end
153
-
154
- def test_search_reflection
155
- assert_not_nil Product.search_reflection(:search)
156
- assert_not_nil Product.search_reflection(:user_search)
157
- end
158
-
159
- def test_blank
160
- assert_equal Product.all, Product.search("")
161
- end
162
-
163
- def test_not_adding_search_to_object
164
- refute Object.respond_to?(:search)
165
- end
166
- end
data/test/string_test.rb DELETED
@@ -1,142 +0,0 @@
1
- require File.expand_path("test_helper", __dir__)
2
-
3
- class StringTest < SearchCop::TestCase
4
- def test_anywhere
5
- product = create(:product, title: "Expected title")
6
-
7
- assert_includes Product.search("Expected"), product
8
- refute_includes Product.search("Rejected"), product
9
- end
10
-
11
- def test_anywhere_quoted
12
- product = create(:product, title: "Expected title")
13
-
14
- assert_includes Product.search("'Expected title'"), product
15
- assert_includes Product.search('"Expected title"'), product
16
-
17
- refute_includes Product.search("'Rejected title'"), product
18
- refute_includes Product.search('"Rejected title"'), product
19
- end
20
-
21
- def test_multiple
22
- product = create(:product, comments: [create(:comment, title: "Expected title", message: "Expected message")])
23
-
24
- assert_includes Product.search("Expected"), product
25
- refute_includes Product.search("Rejected"), product
26
- end
27
-
28
- def test_includes
29
- product = create(:product, title: "Expected")
30
-
31
- assert_includes Product.search("title: Expected"), product
32
- refute_includes Product.search("title: Rejected"), product
33
- end
34
-
35
- def test_query_string_wildcards
36
- product1 = create(:product, brand: "First brand")
37
- product2 = create(:product, brand: "Second brand")
38
-
39
- assert_equal Product.search("brand: First*"), [product1]
40
- assert_equal Product.search("brand: br*nd"), []
41
- assert_equal Product.search("brand: brand*"), []
42
- assert_equal Product.search("brand: *brand*").to_set, [product1, product2].to_set
43
- assert_equal Product.search("brand: *brand").to_set, [product1, product2].to_set
44
- end
45
-
46
- def test_query_string_wildcard_escaping
47
- product1 = create(:product, brand: "som% brand")
48
- product2 = create(:product, brand: "som_ brand")
49
- product3 = create(:product, brand: "som\\ brand")
50
- _product4 = create(:product, brand: "some brand")
51
-
52
- assert_equal Product.search("brand: som% brand"), [product1]
53
- assert_equal Product.search("brand: som_ brand"), [product2]
54
- assert_equal Product.search("brand: som\\ brand"), [product3]
55
- end
56
-
57
- def test_query_string_wildcards_with_left_wildcard_false
58
- product = create(:product, brand: "Some brand")
59
-
60
- with_options(Product.search_scopes[:search], :brand, left_wildcard: false) do
61
- refute_includes Product.search("brand: *brand"), product
62
- assert_includes Product.search("brand: Some"), product
63
- end
64
- end
65
-
66
- def test_query_string_wildcards_with_right_wildcard_false
67
- product = create(:product, brand: "Some brand")
68
-
69
- with_options(Product.search_scopes[:search], :brand, right_wildcard: false) do
70
- refute_includes Product.search("brand: Some*"), product
71
- assert_includes Product.search("brand: brand"), product
72
- end
73
- end
74
-
75
- def test_includes_with_left_wildcard
76
- product = create(:product, brand: "Some brand")
77
-
78
- assert_includes Product.search("brand: brand"), product
79
- end
80
-
81
- def test_includes_with_left_wildcard_false
82
- expected = create(:product, brand: "Brand")
83
- rejected = create(:product, brand: "Rejected brand")
84
-
85
- results = with_options(Product.search_scopes[:search], :brand, left_wildcard: false) { Product.search "brand: Brand" }
86
-
87
- assert_includes results, expected
88
- refute_includes results, rejected
89
- end
90
-
91
- def test_includes_with_right_wildcard_false
92
- expected = create(:product, brand: "Brand")
93
- rejected = create(:product, brand: "Brand rejected")
94
-
95
- results = with_options(Product.search_scopes[:search], :brand, right_wildcard: false) { Product.search "brand: Brand" }
96
-
97
- assert_includes results, expected
98
- refute_includes results, rejected
99
- end
100
-
101
- def test_equals
102
- product = create(:product, title: "Expected title")
103
-
104
- assert_includes Product.search("title = 'Expected title'"), product
105
- refute_includes Product.search("title = Expected"), product
106
- end
107
-
108
- def test_equals_not
109
- product = create(:product, title: "Expected")
110
-
111
- assert_includes Product.search("title != Rejected"), product
112
- refute_includes Product.search("title != Expected"), product
113
- end
114
-
115
- def test_greater
116
- product = create(:product, title: "Title B")
117
-
118
- assert_includes Product.search("title > 'Title A'"), product
119
- refute_includes Product.search("title > 'Title B'"), product
120
- end
121
-
122
- def test_greater_equals
123
- product = create(:product, title: "Title A")
124
-
125
- assert_includes Product.search("title >= 'Title A'"), product
126
- refute_includes Product.search("title >= 'Title B'"), product
127
- end
128
-
129
- def test_less
130
- product = create(:product, title: "Title A")
131
-
132
- assert_includes Product.search("title < 'Title B'"), product
133
- refute_includes Product.search("title < 'Title A'"), product
134
- end
135
-
136
- def test_less_or_greater
137
- product = create(:product, title: "Title B")
138
-
139
- assert_includes Product.search("title <= 'Title B'"), product
140
- refute_includes Product.search("title <= 'Title A'"), product
141
- end
142
- end
data/test/test_helper.rb DELETED
@@ -1,205 +0,0 @@
1
- require "search_cop"
2
-
3
- begin
4
- require "minitest"
5
-
6
- class SearchCop::TestCase < MiniTest::Test; end
7
- rescue LoadError
8
- require "minitest/unit"
9
-
10
- class SearchCop::TestCase < MiniTest::Unit::TestCase; end
11
- end
12
-
13
- require "minitest/autorun"
14
- require "active_record"
15
- require "factory_bot"
16
- require "yaml"
17
-
18
- DATABASE = ENV["DATABASE"] || "sqlite"
19
-
20
- ActiveRecord::Base.establish_connection YAML.load_file(File.expand_path("database.yml", __dir__))[DATABASE]
21
-
22
- class User < ActiveRecord::Base; end
23
-
24
- class Comment < ActiveRecord::Base
25
- include SearchCop
26
-
27
- belongs_to :user
28
-
29
- search_scope :search do
30
- attributes user: "user.username"
31
- attributes :title, :message
32
- end
33
- end
34
-
35
- class Product < ActiveRecord::Base
36
- include SearchCop
37
-
38
- search_scope :search do
39
- attributes :title, :description, :brand, :notice, :stock, :price, :created_at, :created_on, :available
40
- attributes comment: ["comments.title", "comments.message"], user: ["users.username", "users_products.username"]
41
- attributes primary: [:title, :description]
42
-
43
- aliases users_products: :user
44
-
45
- if DATABASE != "sqlite"
46
- options :title, type: :fulltext, coalesce: true
47
- options :description, type: :fulltext, coalesce: true
48
- options :comment, type: :fulltext, coalesce: true
49
- end
50
-
51
- if DATABASE == "postgres"
52
- options :title, dictionary: "english"
53
- end
54
-
55
- generator :custom_eq do |column_name, raw_value|
56
- "#{column_name} = #{quote raw_value}"
57
- end
58
- end
59
-
60
- search_scope :user_search do
61
- scope { joins "LEFT OUTER JOIN users users_products ON users_products.id = products.user_id" }
62
-
63
- attributes :title, :description
64
- attributes user: "users_products.username"
65
-
66
- options :title, default: true
67
- aliases users_products: User
68
- end
69
-
70
- search_scope :search_multi_columns do
71
- attributes all: [:title, :description]
72
- end
73
-
74
- has_many :comments
75
- has_many :users, through: :comments
76
-
77
- belongs_to :user
78
- end
79
-
80
- module Blog
81
- class Post < ActiveRecord::Base
82
- include SearchCop
83
-
84
- belongs_to :user
85
-
86
- search_scope :search do
87
- attributes :title, :content
88
- attributes user: ["user.username"]
89
- end
90
- end
91
- end
92
-
93
- class AvailableProduct < Product
94
- default_scope { where(available: true) }
95
- end
96
-
97
- FactoryBot.define do
98
- factory :product do
99
- end
100
-
101
- factory :blog_post, class: Blog::Post do
102
- end
103
-
104
- factory :available_product do
105
- available { true }
106
- end
107
-
108
- factory :comment do
109
- end
110
-
111
- factory :user do
112
- end
113
- end
114
-
115
- ActiveRecord::Base.connection.execute "DROP TABLE IF EXISTS products"
116
- ActiveRecord::Base.connection.execute "DROP TABLE IF EXISTS posts"
117
- ActiveRecord::Base.connection.execute "DROP TABLE IF EXISTS comments"
118
- ActiveRecord::Base.connection.execute "DROP TABLE IF EXISTS users"
119
-
120
- ActiveRecord::Base.connection.create_table :products do |t|
121
- t.references :user
122
- t.string :title
123
- t.text :description
124
- t.integer :stock
125
- t.float :price
126
- t.datetime :created_at
127
- t.date :created_on
128
- t.boolean :available
129
- t.string :brand
130
- t.string :notice
131
- end
132
-
133
- ActiveRecord::Base.connection.create_table :posts do |t|
134
- t.references :user
135
- t.string :title
136
- t.text :content
137
- end
138
-
139
- ActiveRecord::Base.connection.create_table :comments do |t|
140
- t.references :product
141
- t.references :user
142
- t.string :title
143
- t.text :message
144
- end
145
-
146
- ActiveRecord::Base.connection.create_table :users do |t|
147
- t.string :username
148
- end
149
-
150
- if DATABASE == "mysql"
151
- ActiveRecord::Base.connection.execute "ALTER TABLE products ENGINE=MyISAM"
152
- ActiveRecord::Base.connection.execute "ALTER TABLE products ADD FULLTEXT INDEX(title), ADD FULLTEXT INDEX(description), ADD FULLTEXT INDEX(title, description)"
153
-
154
- ActiveRecord::Base.connection.execute "ALTER TABLE comments ENGINE=MyISAM"
155
- ActiveRecord::Base.connection.execute "ALTER TABLE comments ADD FULLTEXT INDEX(title, message)"
156
- end
157
-
158
- class SearchCop::TestCase
159
- include FactoryBot::Syntax::Methods
160
-
161
- def teardown
162
- Product.delete_all
163
- Comment.delete_all
164
- end
165
-
166
- def with_options(scope, key, options = {})
167
- opts = scope.reflection.options[key.to_s] || {}
168
-
169
- scope.reflection.options[key.to_s] = opts.merge(options)
170
-
171
- yield
172
- ensure
173
- scope.reflection.options[key.to_s] = opts
174
- end
175
-
176
- def with_scope(scope, blk)
177
- orig = scope.reflection.scope
178
-
179
- scope.reflection.scope = blk
180
-
181
- yield
182
- ensure
183
- scope.reflection.scope = orig
184
- end
185
-
186
- def assert_not_nil(value)
187
- assert value
188
- end
189
-
190
- def assert_nothing_raised
191
- yield
192
- end
193
-
194
- def quote_table_name(name)
195
- ActiveRecord::Base.connection.quote_table_name name
196
- end
197
-
198
- def quote_column_name(name)
199
- ActiveRecord::Base.connection.quote_column_name name
200
- end
201
-
202
- def quote(object)
203
- ActiveRecord::Base.connection.quote object
204
- end
205
- end
data/test/visitor_test.rb DELETED
@@ -1,108 +0,0 @@
1
- require File.expand_path("test_helper", __dir__)
2
-
3
- class VisitorTest < SearchCop::TestCase
4
- def test_and
5
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").gt(0).and(SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").lt(2))
6
-
7
- assert_equal "(#{quote_table_name "products"}.#{quote_column_name "stock"} > 0 AND #{quote_table_name "products"}.#{quote_column_name "stock"} < 2)", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
8
- end
9
-
10
- def test_or
11
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").gt(0).or(SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").lt(2))
12
-
13
- assert_equal "(#{quote_table_name "products"}.#{quote_column_name "stock"} > 0 OR #{quote_table_name "products"}.#{quote_column_name "stock"} < 2)", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
14
- end
15
-
16
- def test_greater_than
17
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").gt(1)
18
-
19
- assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} > 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
20
- end
21
-
22
- def test_greater_than_or_equal
23
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").gteq(1)
24
-
25
- assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} >= 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
26
- end
27
-
28
- def test_less_than
29
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").lt(1)
30
-
31
- assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} < 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
32
- end
33
-
34
- def test_less_than_or_equal
35
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").lteq(1)
36
-
37
- assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} <= 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
38
- end
39
-
40
- def test_equality
41
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").eq(1)
42
-
43
- assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} = 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
44
- end
45
-
46
- def test_not_equal
47
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").not_eq(1)
48
-
49
- assert_equal "#{quote_table_name "products"}.#{quote_column_name "stock"} != 1", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
50
- end
51
-
52
- def test_matches
53
- node = SearchCopGrammar::Attributes::String.new(Product, "products", "notice").matches("Notice")
54
-
55
- assert_equal("(#{quote_table_name "products"}.#{quote_column_name "notice"} IS NOT NULL AND #{quote_table_name "products"}.#{quote_column_name "notice"} LIKE #{quote "%Notice%"} ESCAPE #{quote "\\"})", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] != "postgres"
56
- assert_equal("(#{quote_table_name "products"}.#{quote_column_name "notice"} IS NOT NULL AND #{quote_table_name "products"}.#{quote_column_name "notice"} ILIKE #{quote "%Notice%"} ESCAPE #{quote "\\"})", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "postgres"
57
- end
58
-
59
- def test_not
60
- node = SearchCopGrammar::Attributes::Integer.new(Product, "products", "stock").eq(1).not
61
-
62
- assert_equal "NOT (#{quote_table_name "products"}.#{quote_column_name "stock"} = 1)", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
63
- end
64
-
65
- def test_attribute
66
- # Already tested
67
- end
68
-
69
- def test_quote
70
- assert_equal quote("Test"), SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit("Test")
71
- end
72
-
73
- def test_fulltext
74
- node = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query").optimize!
75
-
76
- assert_equal("MATCH(`products`.`title`) AGAINST('Query' IN BOOLEAN MODE)", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "mysql"
77
- assert_equal("to_tsvector('english', COALESCE(\"products\".\"title\", '')) @@ to_tsquery('english', '''Query''')", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "postgres"
78
- end
79
-
80
- def test_fulltext_and
81
- query1 = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query1")
82
- query2 = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query2")
83
-
84
- node = query1.and(query2).optimize!
85
-
86
- assert_equal("(MATCH(`products`.`title`) AGAINST('+Query1 +Query2' IN BOOLEAN MODE))", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "mysql"
87
- assert_equal("(to_tsvector('english', COALESCE(\"products\".\"title\", '')) @@ to_tsquery('english', '(''Query1'') & (''Query2'')'))", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "postgres"
88
- end
89
-
90
- def test_fulltext_or
91
- query1 = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query1")
92
- query2 = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").matches("Query2")
93
-
94
- node = query1.or(query2).optimize!
95
-
96
- assert_equal("(MATCH(`products`.`title`) AGAINST('(Query1) (Query2)' IN BOOLEAN MODE))", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "mysql"
97
- assert_equal("(to_tsvector('english', COALESCE(\"products\".\"title\", '')) @@ to_tsquery('english', '(''Query1'') | (''Query2'')'))", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)) if ENV["DATABASE"] == "postgres"
98
- end
99
-
100
- def test_generator
101
- generator = lambda do |column_name, value|
102
- "#{column_name} = #{quote value}"
103
- end
104
- node = SearchCopGrammar::Attributes::Collection.new(SearchCop::QueryInfo.new(Product, Product.search_scopes[:search]), "title").generator(generator, "value").optimize!
105
-
106
- assert_equal "#{quote_table_name "products"}.#{quote_column_name "title"} = 'value'", SearchCop::Visitors::Visitor.new(ActiveRecord::Base.connection).visit(node)
107
- end
108
- end