mcmire-context 0.5.6
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.
- data/.gitignore +1 -0
- data/History.txt +10 -0
- data/License.txt +20 -0
- data/README.rdoc +158 -0
- data/Rakefile +55 -0
- data/countloc.rb +65 -0
- data/coverage/-Library-Ruby-Gems-1_8-gems-rcov-0_8_1_2_0-lib-rcov_rb.html +1598 -0
- data/coverage/index.html +441 -0
- data/coverage/lib-context-context_rb.html +669 -0
- data/coverage/lib-context-core_ext-string_rb.html +627 -0
- data/coverage/lib-context-lifecycle_rb.html +683 -0
- data/coverage/lib-context-shared_behavior_rb.html +708 -0
- data/coverage/lib-context-suite_rb.html +649 -0
- data/coverage/lib-context-test_rb.html +637 -0
- data/coverage/lib-context-version_rb.html +619 -0
- data/coverage/lib-context_rb.html +623 -0
- data/lib/context.rb +6 -0
- data/lib/context/core.rb +102 -0
- data/lib/context/core_ext/rails_hacks.rb +8 -0
- data/lib/context/core_ext/string.rb +29 -0
- data/lib/context/lifecycle.rb +115 -0
- data/lib/context/shared_behavior.rb +96 -0
- data/lib/context/suite.rb +35 -0
- data/lib/context/test.rb +34 -0
- data/lib/context/version.rb +9 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/test/test_context.rb +62 -0
- data/test/test_core_ext.rb +25 -0
- data/test/test_helper.rb +2 -0
- data/test/test_lifecycle.rb +224 -0
- data/test/test_nested_lifecycle.rb +44 -0
- data/test/test_shared.rb +116 -0
- data/test/test_test.rb +23 -0
- metadata +94 -0
data/lib/context.rb
ADDED
data/lib/context/core.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
module Context
|
4
|
+
class << self
|
5
|
+
attr_accessor :core_class
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.setup(test_case)
|
9
|
+
if core_class
|
10
|
+
if core_class == test_case
|
11
|
+
return
|
12
|
+
else
|
13
|
+
raise ArgumentError, "Currently, you're not allowed to run Context.setup again and clobber '#{core_class.name}'. Require 'context/core' and pick ONE class."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
self.core_class = test_case
|
18
|
+
test_case.class_eval do
|
19
|
+
include TestCase
|
20
|
+
extend TestCase::ClassMethods
|
21
|
+
|
22
|
+
# for some reason, Test::Unit::TestCase won't let me cleanly override
|
23
|
+
# #suite with an extended module :(
|
24
|
+
def self.suite
|
25
|
+
context_suite
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module TestCase
|
31
|
+
module ClassMethods
|
32
|
+
# Test::Unit uses ObjectSpace to figure out what Test::Unit:TestCase instances are running
|
33
|
+
# Contexts are not named and therefore sometimes get garbage collected.
|
34
|
+
# Think of #context_list as the shelter for nameless contexts
|
35
|
+
attr_accessor :context_list
|
36
|
+
|
37
|
+
def context_name #:nodoc:
|
38
|
+
@context_name ||= ""
|
39
|
+
if superclass.respond_to?(:context_name)
|
40
|
+
return "#{superclass.context_name} #{@context_name}".gsub(/^\s+/, "")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def context_name=(val) #:nodoc:
|
45
|
+
@context_name = val
|
46
|
+
end
|
47
|
+
|
48
|
+
# Add a context to a set of tests.
|
49
|
+
#
|
50
|
+
# context "A new account" do
|
51
|
+
# it "should not have users"
|
52
|
+
# assert Account.new.users.empty?
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# The context name is prepended to the test name, so failures look like this:
|
57
|
+
#
|
58
|
+
# 1) Failure:
|
59
|
+
# test_a_new_account_should_not_have_users() [./test/test_accounts.rb:4]:
|
60
|
+
# <false> is not true.
|
61
|
+
#
|
62
|
+
# Contexts can also be nested like so:
|
63
|
+
#
|
64
|
+
# context "A new account" do
|
65
|
+
# context "created by the web application" do
|
66
|
+
# it "should have web as its vendor" do
|
67
|
+
# assert_equal "web", users(:web_user).vendor
|
68
|
+
# end
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# Since contexts create a singleton instance of a class, each one must have its own before/after blocks. This
|
73
|
+
# will be tweaked in future releases to allow you to chain these blocks from its parent contexts.
|
74
|
+
#
|
75
|
+
def context(name, &block)
|
76
|
+
cls = Class.new(self)
|
77
|
+
cls.context_name = name
|
78
|
+
|
79
|
+
# Care about Rails tests in nested contexts
|
80
|
+
cls.tests($1.constantize) if defined?(Rails) &&
|
81
|
+
self.name =~ /^(.*(Controller|Helper|Mailer))Test/ &&
|
82
|
+
self < ActiveSupport::TestCase
|
83
|
+
|
84
|
+
cls.class_eval(&block)
|
85
|
+
(self.context_list ||= []) << cls
|
86
|
+
const_set("Test#{name.to_class_name}#{cls.object_id.abs}", cls)
|
87
|
+
cls
|
88
|
+
end
|
89
|
+
|
90
|
+
%w(contexts describe describes group specify specifies).each {|m| alias_method m, :context}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
require 'context/core_ext/string'
|
96
|
+
require 'context/core_ext/rails_hacks'
|
97
|
+
|
98
|
+
require 'context/version'
|
99
|
+
require 'context/suite'
|
100
|
+
require 'context/test'
|
101
|
+
require 'context/lifecycle'
|
102
|
+
require 'context/shared_behavior'
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Context::String
|
2
|
+
# Replaces spaces and tabs with _ so we can use the string as a method name
|
3
|
+
# Also replace dangerous punctuation
|
4
|
+
def to_method_name
|
5
|
+
downcased = self.downcase
|
6
|
+
downcased.gsub!(/[\s:',\.~;!#=\-\(\)\?]+/,'_')
|
7
|
+
downcased
|
8
|
+
end
|
9
|
+
|
10
|
+
# Borrowed from +camelize+ in ActiveSupport
|
11
|
+
def to_module_name
|
12
|
+
meth_name = self.to_method_name
|
13
|
+
meth_name.gsub!(/\/(.?)/) { "::#{$1.upcase}" }
|
14
|
+
meth_name.gsub!(/(?:^|_)(.)/) { $1.upcase }
|
15
|
+
meth_name
|
16
|
+
end
|
17
|
+
|
18
|
+
# Borrowed from +camelize+ in ActiveSupport
|
19
|
+
def to_class_name
|
20
|
+
meth_name = self.to_method_name
|
21
|
+
meth_name.gsub!(/\/(.?)/) { "#{$1.upcase}" }
|
22
|
+
meth_name.gsub!(/(?:^|_)(.)/) { $1.upcase }
|
23
|
+
meth_name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class String
|
28
|
+
include Context::String
|
29
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Context
|
2
|
+
module TestCase::ClassMethods
|
3
|
+
attr_accessor :before_each_callbacks, :before_all_callbacks, :after_each_callbacks, :after_all_callbacks, :before_should_callbacks
|
4
|
+
|
5
|
+
def self.extended(test_case)
|
6
|
+
test_case.before_all_callbacks = []
|
7
|
+
test_case.before_each_callbacks = []
|
8
|
+
test_case.after_each_callbacks = []
|
9
|
+
test_case.after_all_callbacks = []
|
10
|
+
test_case.before_should_callbacks = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# Add logic to run before the tests (i.e., a +setup+ method)
|
14
|
+
#
|
15
|
+
# before do
|
16
|
+
# @user = User.first
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
def before(period = :each, &block)
|
20
|
+
unless block_given?
|
21
|
+
block = period
|
22
|
+
period = :each
|
23
|
+
end
|
24
|
+
|
25
|
+
send("before_#{period}_callbacks") << block
|
26
|
+
end
|
27
|
+
|
28
|
+
alias :setup :before
|
29
|
+
|
30
|
+
# Add logic to run after the tests (i.e., a +teardown+ method)
|
31
|
+
#
|
32
|
+
# after do
|
33
|
+
# User.delete_all
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
def after(period = :each, &block)
|
37
|
+
unless block_given?
|
38
|
+
block = period
|
39
|
+
period = :each
|
40
|
+
end
|
41
|
+
|
42
|
+
send("after_#{period}_callbacks") << block
|
43
|
+
end
|
44
|
+
|
45
|
+
alias :teardown :after
|
46
|
+
|
47
|
+
def gather_callbacks(callback_type, period) # :nodoc:
|
48
|
+
callbacks = superclass.respond_to?(:gather_callbacks) ? superclass.gather_callbacks(callback_type, period) : []
|
49
|
+
callbacks.push(*send("#{callback_type}_#{period}_callbacks"))
|
50
|
+
end
|
51
|
+
|
52
|
+
def inherited(child) # :nodoc:
|
53
|
+
super
|
54
|
+
child.before_all_callbacks = []
|
55
|
+
child.before_each_callbacks = []
|
56
|
+
child.after_each_callbacks = []
|
57
|
+
child.after_all_callbacks = []
|
58
|
+
child.before_should_callbacks = {}
|
59
|
+
|
60
|
+
child.class_eval do
|
61
|
+
def setup(&block)
|
62
|
+
super
|
63
|
+
run_context_before_callbacks
|
64
|
+
end
|
65
|
+
|
66
|
+
def teardown
|
67
|
+
super
|
68
|
+
run_context_after_callbacks
|
69
|
+
end
|
70
|
+
end if self == ::Context.core_class
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
module TestCase
|
75
|
+
def run_each_callbacks(callback_type) # :nodoc:
|
76
|
+
self.class.gather_callbacks(callback_type, :each).each do |c|
|
77
|
+
next if !c
|
78
|
+
c.is_a?(Proc) ? instance_eval(&c) : send(c)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def run_all_callbacks(callback_type) # :nodoc:
|
83
|
+
previous_ivars = instance_variables
|
84
|
+
self.class.gather_callbacks(callback_type, :all).each { |c| instance_eval(&c) if c }
|
85
|
+
(instance_variables - previous_ivars).inject({}) do |hash, ivar|
|
86
|
+
hash.update ivar => instance_variable_get(ivar)
|
87
|
+
end
|
88
|
+
rescue Object => exception
|
89
|
+
raise <<-BANG
|
90
|
+
Error running the #{callback_type}(:all) callback for #{name}
|
91
|
+
#{exception.class.name}: #{exception.message}
|
92
|
+
#{exception.backtrace.join("\n")}
|
93
|
+
BANG
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_values_from_callbacks(values) # :nodoc:
|
97
|
+
values.each do |name, value|
|
98
|
+
instance_variable_set name, value
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def run_context_before_callbacks
|
104
|
+
unless self.class.before_should_callbacks[method_name].nil?
|
105
|
+
instance_eval(&self.class.before_should_callbacks[method_name])
|
106
|
+
end
|
107
|
+
|
108
|
+
run_each_callbacks :before
|
109
|
+
end
|
110
|
+
|
111
|
+
def run_context_after_callbacks
|
112
|
+
run_each_callbacks :after
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Context
|
2
|
+
class SharedBehavior < Module
|
3
|
+
def self.create_from_behavior(beh) # :nodoc:
|
4
|
+
mod = self.new
|
5
|
+
mod._behavior = beh
|
6
|
+
|
7
|
+
mod
|
8
|
+
end
|
9
|
+
|
10
|
+
def _behavior=(beh) # :nodoc:
|
11
|
+
@_behavior = beh
|
12
|
+
end
|
13
|
+
|
14
|
+
def included(arg) # :nodoc:
|
15
|
+
arg.instance_eval(&@_behavior)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Context::TestCase::ClassMethods
|
21
|
+
# Share behavior among different contexts. This creates a module (actually, a Module subclass)
|
22
|
+
# that is included using the +use+ method (or one of its aliases) provided by context or +include+
|
23
|
+
# if you know the module's constant name.
|
24
|
+
#
|
25
|
+
# ==== Examples
|
26
|
+
#
|
27
|
+
# shared "other things" do
|
28
|
+
# it "should do things but not some things" do
|
29
|
+
# # behavior is fun
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# use "other things"
|
34
|
+
# # or...
|
35
|
+
# it_should_behave_like "other things"
|
36
|
+
#
|
37
|
+
# shared :client do
|
38
|
+
# it "should be a client to our server" do
|
39
|
+
# # TODO: client behavior here
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# use :client
|
44
|
+
# # or...
|
45
|
+
# uses "client"
|
46
|
+
# behaves_like "client"
|
47
|
+
#
|
48
|
+
def shared(name, &block)
|
49
|
+
case name.class.name
|
50
|
+
when "String"
|
51
|
+
name = name.to_module_name
|
52
|
+
when "Symbol"
|
53
|
+
name = name.to_s.to_module_name
|
54
|
+
else
|
55
|
+
raise ArgumentError, "Provide a String or Symbol as the name of the shared behavior group"
|
56
|
+
end
|
57
|
+
|
58
|
+
Object.const_set(name, Context::SharedBehavior.create_from_behavior(block))
|
59
|
+
end
|
60
|
+
|
61
|
+
%w(shared_behavior share_as share_behavior_as shared_examples_for).each {|m| alias_method m, :shared}
|
62
|
+
|
63
|
+
# Pull in behavior shared by +shared+ or a module.
|
64
|
+
#
|
65
|
+
# ==== Examples
|
66
|
+
#
|
67
|
+
# shared "other things" do
|
68
|
+
# it "should do things but not some things" do
|
69
|
+
# # behavior is fun
|
70
|
+
# end
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# use "other things"
|
74
|
+
# # or...
|
75
|
+
# it_should_behave_like "other things"
|
76
|
+
#
|
77
|
+
# module Things
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# uses Things
|
81
|
+
#
|
82
|
+
def use(shared_name)
|
83
|
+
case shared_name.class.name
|
84
|
+
when "Context::SharedBehavior", "Module"
|
85
|
+
include shared_name
|
86
|
+
when "String"
|
87
|
+
include Object.const_get(shared_name.to_module_name)
|
88
|
+
when "Symbol"
|
89
|
+
include Object.const_get(shared_name.to_s.to_module_name)
|
90
|
+
else
|
91
|
+
raise ArgumentError, "Provide a String or Symbol as the name of the shared behavior group or the module name"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
%w(uses it_should_behave_like behaves_like uses_examples_from).each {|m| alias_method m, :use}
|
96
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Context
|
2
|
+
module TestCase::ClassMethods
|
3
|
+
# Tweaks to standard method so we don't get superclass methods and we don't
|
4
|
+
# get weird default tests
|
5
|
+
def context_suite # :nodoc:
|
6
|
+
method_names = public_instance_methods - superclass.public_instance_methods
|
7
|
+
|
8
|
+
tests = method_names.delete_if {|method_name| method_name !~ /^test./}
|
9
|
+
suite = TestSuite.new(name)
|
10
|
+
|
11
|
+
tests.sort.each do |test|
|
12
|
+
catch(:invalid_test) do
|
13
|
+
suite << new(test)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
suite
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class TestSuite < Test::Unit::TestSuite
|
22
|
+
# Runs the tests and/or suites contained in this
|
23
|
+
# TestSuite.
|
24
|
+
def run(result, &progress_block) # :nodoc:
|
25
|
+
yield(STARTED, name)
|
26
|
+
ivars_from_callback = @tests.first.run_all_callbacks(:before) if @tests.first.is_a?(Context.core_class)
|
27
|
+
@tests.each do |test|
|
28
|
+
test.set_values_from_callbacks(ivars_from_callback) if ivars_from_callback
|
29
|
+
test.run(result, &progress_block)
|
30
|
+
end
|
31
|
+
ivars_from_callback = @tests.first.run_all_callbacks(:after) if ivars_from_callback
|
32
|
+
yield(FINISHED, name)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/context/test.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Context::TestCase::ClassMethods
|
2
|
+
# Create a test method. +name+ is a native-language string to describe the test
|
3
|
+
# (e.g., no more +test_this_crazy_thing_with_underscores+).
|
4
|
+
#
|
5
|
+
# test "A user should not be able to delete another user" do
|
6
|
+
# assert_false @user.can?(:delete, @other_user)
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
def test(name, opts={}, &block)
|
10
|
+
test_name = ["test:", context_name, name].reject { |n| n == "" }.join(' ')
|
11
|
+
defined = instance_method(test_name) rescue false
|
12
|
+
raise "#{test_name} is already defined in #{self}" if defined
|
13
|
+
|
14
|
+
unless opts[:before].nil?
|
15
|
+
before_should_callbacks[test_name] = opts[:before]
|
16
|
+
end
|
17
|
+
|
18
|
+
if block_given?
|
19
|
+
define_method(test_name, &block)
|
20
|
+
else
|
21
|
+
define_method(test_name) do
|
22
|
+
flunk "No implementation provided for #{name}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
%w(it should tests).each {|m| alias_method m, :test}
|
28
|
+
|
29
|
+
def before_test(name, &block)
|
30
|
+
test(name, :before => block) {}
|
31
|
+
end
|
32
|
+
|
33
|
+
%w(before_it before_should before_tests).each {|m| alias_method m, :before_test}
|
34
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
desc 'Release the website and new gem version'
|
2
|
+
task :deploy => [:check_version, :website, :release] do
|
3
|
+
puts "Remember to create SVN tag:"
|
4
|
+
puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
5
|
+
"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
|
6
|
+
puts "Suggested comment:"
|
7
|
+
puts "Tagging release #{CHANGES}"
|
8
|
+
end
|
9
|
+
|
10
|
+
desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
|
11
|
+
task :local_deploy => [:website_generate, :install_gem]
|
12
|
+
|
13
|
+
task :check_version do
|
14
|
+
unless ENV['VERSION']
|
15
|
+
puts 'Must pass a VERSION=x.y.z release version'
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
unless ENV['VERSION'] == VERS
|
19
|
+
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
|
25
|
+
task :install_gem_no_doc => [:clean, :package] do
|
26
|
+
sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :manifest do
|
30
|
+
desc 'Recreate Manifest.txt to include ALL files'
|
31
|
+
task :refresh do
|
32
|
+
`rake check_manifest | patch -p0 > Manifest.txt`
|
33
|
+
end
|
34
|
+
end
|