mcmire-context 0.5.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|