Skip to content

Commit fb6a4ba

Browse files
committed
Initial commit
0 parents  commit fb6a4ba

File tree

12 files changed

+262
-0
lines changed

12 files changed

+262
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*.gem
2+
.bundle
3+
Gemfile.lock
4+
pkg/*

Gemfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
source "http://rubygems.org"
2+
3+
# Specify your gem's dependencies in rspec_caching_test.gemspec
4+
gemspec

Rakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require "bundler/gem_tasks"

lib/rspec-rails-caching.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
require 'rspec-rails-caching/version'
2+
require 'rspec-rails-caching/matchers'
3+
require 'rspec-rails-caching/test_store'
4+
require 'rspec-rails-caching/extensions/action_controller'
5+
6+
module RSpecRailsCaching
7+
RSpec::Rails::ControllerExampleGroup.class_eval do
8+
include Matchers
9+
end
10+
11+
RSpec.configure do |config|
12+
config.alias_it_should_behave_like_to :with_configuration, "with"
13+
config.before(:all, :type => :controller, :caching => true) do |example|
14+
silence_warnings do
15+
@_orig_cache_store = RAILS_CACHE
16+
Object.const_set "RAILS_CACHE", TestStore.new
17+
end
18+
19+
ActionController::Base.cache_store = RAILS_CACHE
20+
ActionController::Base.perform_caching = true
21+
22+
# The controller needs to be reloaded to metaprogram the caches_page
23+
# callback with the perform_caching option turned on. There is no
24+
# reloading if the example controller isn't in the load paths, likely
25+
# because it was defined inline in the spec.
26+
if ctrl_class_file =
27+
ActiveSupport::Dependencies.search_for_file(example.class.controller_class.to_s.underscore)
28+
then
29+
ActiveSupport::Dependencies.load(ctrl_class_file)
30+
end
31+
32+
example.class.controller_class.class_eval do
33+
self.perform_caching = true
34+
extend Extensions::ActionController::ClassMethods
35+
end
36+
end
37+
38+
config.after(:all) do |example|
39+
silence_warnings do
40+
Object.const_set "RAILS_CACHE", @_orig_cache_store
41+
end
42+
ActionController::Base.cache_store = RAILS_CACHE
43+
ActionController::Base.perform_caching = false
44+
end
45+
46+
config.around(:each, :type => :controller, :caching => true) do |example|
47+
# This block does some voodoo to ensure the controller class gets
48+
# reloaded in the right context. I don't understand why it's necessary.
49+
end
50+
end
51+
52+
end

lib/rspec-rails-caching/extensions.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require 'rspec-rails-caching/extensions/action_controller/base'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module RSpecRailsCaching::Extensions
2+
module ActionController
3+
4+
module ClassMethods
5+
def cache_page(content, path, extension = nil, *)
6+
instrument_page_cache :write_page, path do
7+
cache_store.cached_pages << path
8+
end
9+
end
10+
11+
def expire_page(path)
12+
instrument_page_cache :expire_page, path do
13+
cache_store.cached_pages.delete path
14+
cache_store.expired_pages << path
15+
end
16+
end
17+
end
18+
19+
end
20+
end

lib/rspec-rails-caching/matchers.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module RSpecRailsCaching
2+
module Matchers
3+
end
4+
end
5+
6+
require 'rspec-rails-caching/matchers/cache_page'
7+
require 'rspec-rails-caching/matchers/expire_page'
8+
require 'rspec-rails-caching/matchers/test_cache_caches'
9+
require 'rspec-rails-caching/matchers/test_cache_expires'
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module RSpecRailsCaching::Matchers
2+
extend RSpec::Matchers::DSL
3+
4+
matcher :cache_page do |*expected|
5+
match do |actual|
6+
actual = actual.call if actual.respond_to?(:call)
7+
unless actual.is_a? ActionController::TestResponse
8+
raise ArgumentError("cache_page matcher expects a callable Proc or a TestResponse")
9+
end
10+
11+
Array(expected).all? { |e| cache_store.page_cached?(e) }
12+
end
13+
14+
failure_message_for_should do |actual|
15+
"expected #{controller.class} to cache: #{expected.inspect} but got #{cache_results.inspect}"
16+
end
17+
18+
failure_message_for_should_not do |actual|
19+
"expected #{controller.class} not to cache: #{expected.inspect} but got #{cache_results.inspect}"
20+
end
21+
22+
description do
23+
"cache page #{expected.inspect}"
24+
end
25+
26+
def controller
27+
matcher_execution_context.controller
28+
end
29+
30+
def cache_store
31+
controller.cache_store
32+
end
33+
34+
def cache_results
35+
cache_store.cached_pages
36+
end
37+
end
38+
end
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module RSpecRailsCaching::Matchers
2+
extend RSpec::Matchers::DSL
3+
4+
matcher :expire_page do |*expected|
5+
match do |actual|
6+
actual = actual.call if actual.respond_to?(:call)
7+
unless actual.is_a? ActionController::TestResponse
8+
raise ArgumentError("cache_page matcher expects a callable Proc or a TestResponse")
9+
end
10+
11+
Array(expected).all? { |e| cache_store.page_expired?(e) }
12+
end
13+
14+
failure_message_for_should do |actual|
15+
"expected #{controller.class} to expire: #{expected.inspect} but got #{cache_results.inspect}"
16+
end
17+
18+
failure_message_for_should_not do |actual|
19+
"expected #{controller.class} not to expire: #{expected.inspect} but got #{cache_results.inspect}"
20+
end
21+
22+
description do
23+
"expire page #{expected.inspect}"
24+
end
25+
26+
def controller
27+
matcher_execution_context.controller
28+
end
29+
30+
def cache_store
31+
controller.cache_store
32+
end
33+
34+
def cache_results
35+
cache_store.expired_pages
36+
end
37+
end
38+
end

lib/rspec-rails-caching/test_store.rb

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
module RSpecRailsCaching
2+
class TestStore < ActiveSupport::Cache::Store
3+
4+
attr_reader :cached
5+
attr_reader :expired
6+
attr_reader :expiration_patterns
7+
attr_reader :data
8+
attr_accessor :read_cache
9+
attr_reader :cached_pages
10+
attr_reader :expired_pages
11+
12+
attr_accessor :context
13+
14+
def initialize(do_read_cache = false)
15+
@data = {}
16+
@cached = []
17+
@expired = []
18+
@expiration_patterns = []
19+
@read_cache = do_read_cache
20+
@cached_pages = []
21+
@expired_pages = []
22+
end
23+
24+
def reset
25+
@data.clear
26+
@cached.clear
27+
@expired.clear
28+
@expiration_patterns.clear
29+
end
30+
31+
def read_entry(name, options = nil)
32+
read_cache ? @data[name] : nil
33+
end
34+
35+
def write_entry(name, value, options = nil)
36+
@data[name] = value if read_cache
37+
@cached << name
38+
end
39+
40+
def delete_entry(name, options = nil)
41+
@expired << name
42+
end
43+
44+
def delete_matched(matcher, options = nil)
45+
@expiration_patterns << matcher
46+
end
47+
48+
def cached?(name)
49+
@cached.include?(name)
50+
end
51+
52+
def expired?(name)
53+
@expired.include?(name) || @expiration_patterns.detect { |matcher| name =~ matcher }
54+
end
55+
56+
def page_cached?(options = {})
57+
@cached_pages.include?(test_cache_url(options))
58+
end
59+
60+
def page_expired?(options = {})
61+
@expired_pages.include?(test_cache_url(options))
62+
end
63+
64+
private
65+
def test_cache_url(options)
66+
return options if options.is_a?(String)
67+
url_for(options.merge({ :only_path => true, :skip_relative_url_root => true }))
68+
end
69+
end
70+
end

lib/rspec-rails-caching/version.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module RSpecRailsCaching
2+
VERSION = "0.1.0"
3+
end

rspec-caching.gemspec

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# -*- encoding: utf-8 -*-
2+
$:.push File.expand_path("../lib", __FILE__)
3+
require "rspec-rails-caching/version"
4+
5+
Gem::Specification.new do |s|
6+
s.name = "rspec-rails-caching"
7+
s.version = RSpecRailsCaching::VERSION
8+
s.authors = ["Andrew Vit"]
9+
s.email = ["andrew@avit.ca"]
10+
s.homepage = "https://github.com/avit/rspec-rails-caching"
11+
s.summary = %q{RSpec Rails Caching}
12+
s.description = %q{RSpec helper for testing page and action caching in Rails}
13+
14+
s.rubyforge_project = "rspec-rails-caching"
15+
s.add_dependency "rails", ">=3.0.0"
16+
s.add_dependency "rspec", ">=2.8.0"
17+
18+
s.files = `git ls-files`.split("\n")
19+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21+
s.require_paths = ["lib"]
22+
end

0 commit comments

Comments
 (0)