expect_query 0.1.5

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d3b8b4ed6d2b74521cc8ba8b8c3d916cccb41270c4c41823bc24ece67d51e2ba
4
+ data.tar.gz: 9dad000453c5308bde228f74313820d502efcc8ddab0ea4d64012d1c2cfb8a9d
5
+ SHA512:
6
+ metadata.gz: 74308e0df458e741d4cb8af5b079b164858ab846bfca7d4253fb4c1b5018c8f5aa254b1085d23ec92f44a06fc019b75d20e75837f2df52af7e688d95f9955f5d
7
+ data.tar.gz: bb3009cbc2d35194b6dc4e30aa1807ed70b313d56c8767303eec51e44757224e767f88d171824ad244a2ffb859ec2d3f86c6617ec0d2ce2ca6b739384ec4a94b
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require spec_helper
2
+ --format documentation
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 4.0.1
data/.whitesource ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "scanSettings": {
3
+ "baseBranches": []
4
+ },
5
+ "checkRunSettings": {
6
+ "vulnerableCheckRunConclusionLevel": "failure",
7
+ "displayMode": "diff",
8
+ "useMendCheckNames": true
9
+ },
10
+ "issueSettings": {
11
+ "minSeverityLevel": "LOW",
12
+ "issueType": "DEPENDENCY"
13
+ }
14
+ }
data/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # ExpectQuery
2
+
3
+ `expect_query` provides Rails 8.0+ compatible assertions and matchers for counting SQL queries and Cache operations. It supports both RSpec and Minitest.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'expect_query', group: :test
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### RSpec
16
+
17
+ Add this to your `spec_helper.rb`:
18
+
19
+ ```ruby
20
+ require "expect_query/rspec"
21
+ ```
22
+
23
+ #### SQL Assertions
24
+
25
+ ```ruby
26
+ expect {
27
+ User.first
28
+ }.to make_sql_queries(1)
29
+
30
+ expect {
31
+ User.create(name: "Foo")
32
+ }.to make_sql_queries(1, matching: /INSERT/)
33
+
34
+ expect {
35
+ # ...
36
+ }.to make_sql_queries(at_most: 3)
37
+ ```
38
+
39
+ #### Cache Assertions
40
+
41
+ ```ruby
42
+ expect {
43
+ Rails.cache.read("foo")
44
+ Rails.cache.write("bar", 1)
45
+ }.to perform_cache_operations(read: 1, write: 1)
46
+
47
+ expect {
48
+ Rails.cache.fetch("foo") { 1 }
49
+ }.to perform_cache_operations(total: 2) # read + write (if miss)
50
+ ```
51
+
52
+ ### Multiple Cache Stores
53
+
54
+ By default, assertions use `Rails.cache` (if available). You can specify a different store or multiple stores using `store` or `stores` options.
55
+
56
+ ```ruby
57
+ # RSpec
58
+ expect {
59
+ my_cache.write("foo", 1)
60
+ }.to perform_cache_operations(write: 1, store: my_cache)
61
+
62
+ expect {
63
+ cache1.write("a", 1)
64
+ cache2.write("b", 1)
65
+ }.to perform_cache_operations(total: 2, stores: [cache1, cache2])
66
+ ```
67
+
68
+ ```ruby
69
+ # Minitest
70
+ assert_cache_operations(write: 1, store: my_cache) do
71
+ my_cache.write("foo", 1)
72
+ end
73
+ ```
74
+
75
+ ```ruby
76
+ require "expect_query/minitest"
77
+ ```
78
+
79
+ #### SQL Assertions
80
+
81
+ ```ruby
82
+ assert_sql_queries(1) do
83
+ User.first
84
+ end
85
+ ```
86
+
87
+ #### Cache Assertions
88
+
89
+ ```ruby
90
+ assert_cache_operations(read: 1, write: 1) do
91
+ Rails.cache.read("foo")
92
+ Rails.cache.write("bar", 1)
93
+ end
94
+ ```
95
+
96
+ ## Failure Messages
97
+
98
+ ExpectQuery provides detailed failure messages to help you debug.
99
+
100
+ ### SQL Failure Example
101
+
102
+ ```
103
+ expected to make 1 SQL queries, but made 2
104
+ Queries run:
105
+ 1. SELECT * FROM users
106
+ 2. UPDATE users SET name = 'foo'
107
+ ```
108
+
109
+ ### Cache Failure Example
110
+
111
+ ```
112
+ expected to perform cache operations: total 10,
113
+ but got: total 2
114
+ Cache operations performed:
115
+ 1. read: foo
116
+ 2. write: bar
117
+ ```
118
+
119
+ ## Development
120
+
121
+ To run tests:
122
+
123
+ ```bash
124
+ bundle exec rake
125
+ ```
126
+
127
+ This runs both RSpec and Minitest suites.
128
+
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+ require "rake/testtask"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << "test"
9
+ t.libs << "lib"
10
+ t.pattern = "test/**/*_test.rb"
11
+ end
12
+
13
+ task default: %i[spec test]
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/expect_query/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "expect_query"
7
+ spec.version = ExpectQuery::VERSION
8
+ spec.authors = ["Jade Ornelas"]
9
+ spec.email = ["jade@ornelas.io"]
10
+
11
+ spec.summary = "A gem to assert SQL queries and Cache operations count."
12
+ spec.description = "Provides RSpec matchers and Minitest assertions to count SQL queries and Cache operations, supporting Rails 8.0+."
13
+ spec.homepage = "https://github.com/yknx4/expect_query"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 3.2.0"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/yknx4/expect_query"
19
+ spec.metadata["changelog_uri"] = "https://github.com/yknx4/expect_query/blob/main/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject do |f|
25
+ (File.expand_path(f) == __FILE__) ||
26
+ f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
27
+ end
28
+ end
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
+
33
+ # Rails 8.0+ requirement
34
+ spec.add_dependency "activesupport", ">= 8.0"
35
+ spec.add_dependency "activerecord", ">= 8.0"
36
+
37
+ # Development dependencies
38
+ spec.add_development_dependency "bundler"
39
+ spec.add_development_dependency "rake"
40
+ spec.add_development_dependency "rspec", "~> 3.0"
41
+ spec.add_development_dependency "minitest"
42
+ spec.add_development_dependency "sqlite3"
43
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExpectQuery
4
+ class CacheCounter
5
+ attr_reader :counts, :log
6
+
7
+ VALID_EVENTS = %w[
8
+ cache_read.active_support
9
+ cache_write.active_support
10
+ cache_fetch_multi.active_support
11
+ cache_read_multi.active_support
12
+ cache_write_multi.active_support
13
+ cache_delete.active_support
14
+ cache_delete_multi.active_support
15
+ cache_exist?.active_support
16
+ cache_increment.active_support
17
+ cache_decrement.active_support
18
+ ].freeze
19
+
20
+ def initialize(matching: nil, store_ids: nil)
21
+ @matching = matching
22
+ @store_ids = store_ids
23
+ @counts = Hash.new(0)
24
+ @log = []
25
+ end
26
+
27
+ def call(name, _start, _finish, _message_id, payload)
28
+ if @store_ids
29
+ # If we are filtering by store, we must have a matching ID
30
+ return unless @store_ids.include?(payload[:expect_query_store_id])
31
+ end
32
+
33
+ # name is like "cache_read.active_support"
34
+ # We want to extract "read", "write", etc.
35
+ operation = name.split(".").first.sub(/^cache_/, "")
36
+
37
+ key = payload[:key]
38
+
39
+ if @matching
40
+ # Key can be a string or an array of strings (for multi operations)
41
+ if key.is_a?(Array)
42
+ return unless key.any? { |k| @matching.match?(k.to_s) }
43
+ else
44
+ return unless @matching.match?(key.to_s)
45
+ end
46
+ end
47
+
48
+ @counts[operation.to_sym] += 1
49
+ @counts[:total] += 1
50
+ @log << { operation: operation, key: key }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExpectQuery
4
+ module MinitestAssertions
5
+ def assert_sql_queries(count = nil, matching: nil, at_most: nil, &block)
6
+ counter = ExpectQuery::SqlCounter.new(matching: matching)
7
+ ActiveSupport::Notifications.subscribed(counter, "sql.active_record") do
8
+ block.call
9
+ end
10
+
11
+ actual = counter.count
12
+
13
+ debug_info = ""
14
+ if counter.log.any?
15
+ debug_info = "\nQueries run:\n" + counter.log.map.with_index(1) { |sql, i| "#{i}. #{sql}" }.join("\n")
16
+ end
17
+
18
+ if at_most
19
+ assert actual <= at_most, "Expected at most #{at_most} SQL queries, but made #{actual}#{debug_info}"
20
+ elsif count
21
+ assert_equal count, actual, "Expected #{count} SQL queries, but made #{actual}#{debug_info}"
22
+ else
23
+ assert actual > 0, "Expected some SQL queries, but made none#{debug_info}"
24
+ end
25
+ end
26
+
27
+ def assert_cache_operations(count = nil, matching: nil, store: nil, stores: nil, **specific_counts, &block)
28
+
29
+ target_stores = Array(stores || store)
30
+ if target_stores.empty? && defined?(::Rails) && ::Rails.respond_to?(:cache)
31
+ target_stores = [::Rails.cache]
32
+ end
33
+
34
+ store_ids = []
35
+ target_stores.each do |s|
36
+ unless s.singleton_class < ExpectQuery::StorePatch
37
+ s.singleton_class.prepend(ExpectQuery::StorePatch)
38
+ end
39
+ store_ids << s.object_id
40
+ end
41
+
42
+ pass_ids = store_ids.empty? ? nil : store_ids
43
+
44
+ counter = ExpectQuery::CacheCounter.new(matching: matching, store_ids: pass_ids)
45
+
46
+ subscriber = ActiveSupport::Notifications.subscribe(/cache_.*\.active_support/, counter)
47
+ begin
48
+ block.call
49
+ ensure
50
+ ActiveSupport::Notifications.unsubscribe(subscriber)
51
+ end
52
+
53
+ actual_counts = counter.counts
54
+
55
+ debug_info = ""
56
+ if counter.log.any?
57
+ debug_info = "\nCache operations performed:\n" + counter.log.map.with_index(1) { |entry, i| "#{i}. #{entry[:operation]}: #{entry[:key]}" }.join("\n")
58
+ end
59
+
60
+ if count
61
+ assert_equal count, actual_counts[:total].to_i, "Expected #{count} total cache operations, but got #{actual_counts[:total].to_i}#{debug_info}"
62
+ end
63
+
64
+ specific_counts.each do |op, expected|
65
+ actual = actual_counts[op].to_i
66
+ assert_equal expected, actual, "Expected #{expected} #{op} cache operations, but got #{actual}#{debug_info}"
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ if defined?(Minitest::Test)
73
+ Minitest::Test.include ExpectQuery::MinitestAssertions
74
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/expectations"
4
+
5
+ module ExpectQuery
6
+ module RSpecMatchers
7
+ def make_sql_queries(count = nil, matching: nil, at_most: nil)
8
+ MakeSqlQueries.new(count, matching: matching, at_most: at_most)
9
+ end
10
+
11
+ def perform_cache_operations(count = nil, matching: nil, store: nil, stores: nil, **counts)
12
+ PerformCacheOperations.new(count, matching: matching, store: store, stores: stores, **counts)
13
+ end
14
+
15
+ class MakeSqlQueries
16
+ include RSpec::Matchers::Composable
17
+
18
+ def initialize(expected, matching: nil, at_most: nil)
19
+ @expected = expected
20
+ @matching = matching
21
+ @at_most = at_most
22
+ end
23
+
24
+ def supports_block_expectations?
25
+ true
26
+ end
27
+
28
+ def matches?(block)
29
+ @counter = ExpectQuery::SqlCounter.new(matching: @matching)
30
+ ActiveSupport::Notifications.subscribed(@counter, "sql.active_record") do
31
+ block.call
32
+ end
33
+
34
+ @actual = @counter.count
35
+
36
+ if @at_most
37
+ @actual <= @at_most
38
+ elsif @expected
39
+ @actual == @expected
40
+ else
41
+ @actual > 0 # generic "makes queries"
42
+ end
43
+ end
44
+
45
+ def failure_message
46
+ msg = "expected to make "
47
+ msg += "#{@expected} " if @expected
48
+ msg += "at most #{@at_most} " if @at_most
49
+ msg += "SQL queries"
50
+ msg += " matching #{@matching.inspect}" if @matching
51
+ msg += ", but made #{@actual}"
52
+
53
+ if @counter.log.any?
54
+ msg += "\nQueries run:\n"
55
+ msg += @counter.log.map.with_index(1) { |sql, i| "#{i}. #{sql}" }.join("\n")
56
+ end
57
+ msg
58
+ end
59
+ end
60
+
61
+ class PerformCacheOperations
62
+ include RSpec::Matchers::Composable
63
+
64
+ def initialize(total = nil, matching: nil, store: nil, stores: nil, **specific_counts)
65
+ @total = total
66
+ @matching = matching
67
+ @specific_counts = specific_counts
68
+ @stores = Array(stores || store)
69
+
70
+ if @stores.empty? && defined?(::Rails) && ::Rails.respond_to?(:cache)
71
+ @stores = [::Rails.cache]
72
+ end
73
+ end
74
+
75
+ def supports_block_expectations?
76
+ true
77
+ end
78
+
79
+ def matches?(block)
80
+ # Patch stores
81
+ store_ids = []
82
+ @stores.each do |store|
83
+ unless store.singleton_class < ExpectQuery::StorePatch
84
+ store.singleton_class.prepend(ExpectQuery::StorePatch)
85
+ end
86
+ store_ids << store.object_id
87
+ end
88
+
89
+ # If no stores are defined (e.g. no Rails.cache and no store passed), we can't strict filter by ID.
90
+ # But we probably should pass empty array if we intended to track but found nothing?
91
+ # Or if store_ids is empty, maybe we track ALL?
92
+ # User said: "By default use Rails.cache". If Rails.cache is missing, maybe we should warn or track nothing?
93
+ # Let's pass nil if we want to track ALL, but if we defaulted to Rails.cache and it's there, we pass it.
94
+ # If user explicitly passed empty list?
95
+ pass_ids = store_ids.empty? ? nil : store_ids
96
+
97
+ @counter = ExpectQuery::CacheCounter.new(matching: @matching, store_ids: pass_ids)
98
+
99
+ subscriber = ActiveSupport::Notifications.subscribe(/cache_.*\.active_support/, @counter)
100
+ begin
101
+ block.call
102
+ ensure
103
+ ActiveSupport::Notifications.unsubscribe(subscriber)
104
+ end
105
+
106
+ @actual_counts = @counter.counts
107
+
108
+ result = true
109
+
110
+ if @total
111
+ result &&= (@actual_counts[:total].to_i == @total)
112
+ end
113
+
114
+ @specific_counts.each do |op, count|
115
+ # op could be :read, :write
116
+ result &&= (@actual_counts[op].to_i == count)
117
+ end
118
+
119
+ result
120
+ end
121
+
122
+ def failure_message
123
+ msg = "expected to perform cache operations: "
124
+ msg += "total #{@total}, " if @total
125
+ @specific_counts.each { |k, v| msg += "#{k}: #{v}, " }
126
+ msg += "matching #{@matching.inspect}" if @matching
127
+ msg += "\nbut got: "
128
+ msg += "total #{@actual_counts[:total].to_i}, "
129
+ @specific_counts.each { |k, _| msg += "#{k}: #{@actual_counts[k].to_i}, " }
130
+
131
+ if @counter.log.any?
132
+ msg += "\nCache operations performed:\n"
133
+ msg += @counter.log.map.with_index(1) { |entry, i| "#{i}. #{entry[:operation]}: #{entry[:key]}" }.join("\n")
134
+ end
135
+ msg
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ RSpec.configure do |config|
142
+ config.include ExpectQuery::RSpecMatchers
143
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExpectQuery
4
+ class SqlCounter
5
+ attr_reader :count, :log
6
+
7
+ def initialize(matching: nil)
8
+ @matching = matching
9
+ @count = 0
10
+ @log = []
11
+ end
12
+
13
+ def call(_name, _start, _finish, _message_id, payload)
14
+ return if payload[:cached]
15
+
16
+ sql = payload[:sql]
17
+
18
+ # Ignore schema queries, transactions, etc if needed.
19
+ # For now, we only care about user queries, but let's keep it simple and filter later if requested.
20
+ # Common ignores: SCHEMA, TRANSACTION, EXPLAIN
21
+ return if %w[SCHEMA TRANSACTION EXPLAIN].include?(payload[:name])
22
+
23
+ if @matching
24
+ return unless @matching.match?(sql)
25
+ end
26
+
27
+ @count += 1
28
+ @log << sql
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExpectQuery
4
+ module StorePatch
5
+ def instrument(name, key, options = nil, &block)
6
+ options ||= {}
7
+ options = options.dup unless options.frozen? # dup if possible to avoid mutation issues, though usually safe
8
+ options = options.merge(expect_query_store_id: object_id)
9
+ super(name, key, options, &block)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExpectQuery
4
+ VERSION = "0.1.5"
5
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "expect_query/version"
4
+ require_relative "expect_query/store_patch"
5
+ require_relative "expect_query/sql_counter"
6
+ require_relative "expect_query/cache_counter"
7
+ require "active_support"
8
+ require "active_support/notifications"
9
+
10
+ module ExpectQuery
11
+ class Error < StandardError; end
12
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: expect_query
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Jade Ornelas
8
+ bindir: exe
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activesupport
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '8.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '8.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: activerecord
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '8.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '8.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: bundler
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: rake
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ - !ruby/object:Gem::Dependency
69
+ name: rspec
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '3.0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3.0'
82
+ - !ruby/object:Gem::Dependency
83
+ name: minitest
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ type: :development
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: sqlite3
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Provides RSpec matchers and Minitest assertions to count SQL queries
111
+ and Cache operations, supporting Rails 8.0+.
112
+ email:
113
+ - jade@ornelas.io
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".rspec"
119
+ - ".tool-versions"
120
+ - ".whitesource"
121
+ - README.md
122
+ - Rakefile
123
+ - expect_query.gemspec
124
+ - lib/expect_query.rb
125
+ - lib/expect_query/cache_counter.rb
126
+ - lib/expect_query/minitest.rb
127
+ - lib/expect_query/rspec.rb
128
+ - lib/expect_query/sql_counter.rb
129
+ - lib/expect_query/store_patch.rb
130
+ - lib/expect_query/version.rb
131
+ homepage: https://github.com/yknx4/expect_query
132
+ licenses:
133
+ - MIT
134
+ metadata:
135
+ homepage_uri: https://github.com/yknx4/expect_query
136
+ source_code_uri: https://github.com/yknx4/expect_query
137
+ changelog_uri: https://github.com/yknx4/expect_query/blob/main/CHANGELOG.md
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 3.2.0
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubygems_version: 4.0.3
153
+ specification_version: 4
154
+ summary: A gem to assert SQL queries and Cache operations count.
155
+ test_files: []