cordon 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE.txt ADDED
@@ -0,0 +1,13 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ License copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
data/README.markdown ADDED
@@ -0,0 +1,72 @@
1
+ # Cordon Sanitaire
2
+
3
+ From Wikipedia:
4
+
5
+ > Cordon sanitaire -- or quarantine line -- is a French phrase that, literally
6
+ > translated, means "sanitary cordon". Though in French it originally denoted a barrier
7
+ > implemented to stop the spread of disease, it has often been used in English in a
8
+ > metaphorical sense to refer to attempts to prevent the spread of an ideology deemed
9
+ > unwanted or dangerous, such as the containment policy adopted by George F. Kennan
10
+ > against the Soviet Union.
11
+
12
+ I've never been a big fan of the way RSpec adds <code>#should</code> and <code>#should_not</code> to Kernel, but until recently I'd never been able to articulate why. Then I worked on a project that became <a href="https://github.com/geeksam/kookaburra/">Kookaburra</a>, and I found a specific reason to be annoyed.
13
+
14
+ Basically, putting <code>#should</code> on all objects gives you the freedom to <s>shoot yourself in the foot</s> put RSpec expectations *anywhere*, not just inside an <code>#it</code> block. So, I went looking for a way to make <code>#should</code> explode if it was called outside a specific context.
15
+
16
+ After several false starts and horrible ideas, I've got something that actually isn't too bad.
17
+
18
+ Cordon makes specs look like this:
19
+
20
+ <pre><code lang="ruby">describe "a toggle switch" do
21
+ it "should be on when flipped up" do
22
+ toggle = ToggleSwitch.new
23
+ toggle.flip_up
24
+ <em><strong>assert_that</strong></em>(toggle).should be_on
25
+ end
26
+ end</code></pre>
27
+
28
+ Cordon lets you declare certain methods as "off-limits" to casual code. Any calls to blacklisted methods will raise a Cordon::Violation exception -- <em>unless</em> they're called on the object thats passed as the single argument to <code>Object#assert\_that</code>, as shown above. What <code>#assert\_that</code> does is temporarily add its argument to a whitelist. This effectively gives that object permission to call any blacklisted method once (and only once!).
29
+
30
+ ## Quick setup for popular testing frameworks
31
+
32
+ Currently, Cordon ships with shorthand configuration items for RSpec and MiniTest::Spec. You can set these up like so:
33
+
34
+ ### RSpec
35
+ <pre><code lang="ruby">require 'rspec'
36
+ Cordon.embargo :rspec</code></pre>
37
+
38
+ ### MiniTest::Spec
39
+ <pre><code lang="ruby">require 'minitest/autorun'
40
+ Cordon.embargo :minitest_spec</code></pre>
41
+
42
+ In both examples, note that Cordon's <code>.embargo</code> method must be called *after* the test framework has been loaded.
43
+
44
+
45
+ ## TODO
46
+
47
+ - Write integration macros (and tests, obviously) for various spec frameworks:
48
+ - <s>RSpec</s>
49
+ - <s>MiniTest::Spec</s>
50
+ - <s>Yoda</s> <em>(Actually, Yoda appears to abuse Ruby syntax badly enough that it may not work with Cordon.)</em>
51
+ - ?
52
+ - <s>Add a declarative API to customize the name of the function that wraps assertions</s>
53
+ - probably some other stuff I can't think of at the moment
54
+
55
+
56
+
57
+ ## Contributing to Cordon
58
+
59
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
60
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
61
+ * Fork the project.
62
+ * Start a feature/bugfix branch.
63
+ * Commit and push until you are happy with your contribution.
64
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
65
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
66
+
67
+
68
+
69
+ ## Copyright
70
+
71
+ Copyright (c) 2012 Sam Livingston-Gray. See LICENSE.txt for
72
+ further details.
data/Rakefile ADDED
@@ -0,0 +1,92 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+
15
+
16
+ require 'jeweler'
17
+ Jeweler::Tasks.new do |gem|
18
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
19
+ gem.name = "cordon"
20
+ gem.homepage = "http://github.com/geeksam/cordon"
21
+ gem.license = "WTFPL"
22
+ gem.summary = %Q{Cordon Sanitaire: hygienic handling of infectious methods}
23
+ gem.description = %Q{A bit of an experiment, really}
24
+ gem.email = "geeksam@gmail.com"
25
+ gem.authors = ["Sam Livingston-Gray"]
26
+ # dependencies defined in Gemfile
27
+
28
+ gem.files.exclude *%w[ .document .rvmrc Gemfile Gemfile.lock]
29
+ end
30
+ Jeweler::RubygemsDotOrgTasks.new
31
+
32
+
33
+
34
+ require 'rake/testtask'
35
+ require 'rspec/core/rake_task'
36
+ namespace :test do
37
+ desc 'Run all tests'
38
+ task :all => ['test:integration', 'test:framework_integration']
39
+
40
+ desc 'Run integration tests'
41
+ Rake::TestTask.new(:integration) do |t|
42
+ t.pattern = 'test/integration/*_test.rb'
43
+ t.verbose = true
44
+ end
45
+
46
+ desc 'Run all framework integration tests'
47
+ task :framework_integration => ['test:framework:rspec', 'test:framework:minitest_spec']
48
+
49
+ namespace :framework do
50
+ RSpec::Core::RakeTask.new(:rspec) do |t|
51
+ t.pattern = 'test/framework_integration/rspec_spec.rb'
52
+ t.verbose = true
53
+ end
54
+
55
+ Rake::TestTask.new(:minitest_spec) do |t|
56
+ t.pattern = 'test/framework_integration/minitest_spec_spec.rb'
57
+ t.verbose = true
58
+ end
59
+ end
60
+
61
+ end
62
+ task :default => ['test:all']
63
+
64
+
65
+ require 'rdoc/task'
66
+ Rake::RDocTask.new do |rdoc|
67
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
68
+
69
+ rdoc.rdoc_dir = 'rdoc'
70
+ rdoc.title = "cordon #{version}"
71
+ rdoc.rdoc_files.include('README*')
72
+ rdoc.rdoc_files.include('lib/**/*.rb')
73
+ end
74
+
75
+
76
+ desc 'Quick and dirty SLOC counts'
77
+ task :stats do
78
+ sloc_count = lambda do |glob_expression|
79
+ glob_expression = File.join(File.dirname(__FILE__), glob_expression)
80
+ lines_in_file = lambda { |filename| File.open(filename, 'r').readlines.reject { |line| line =~ /^\s*(#|$)/ }.length }
81
+ n = Dir.glob(glob_expression).inject(0) { |n, f| n + lines_in_file[f] }
82
+ n.to_f
83
+ end
84
+ lib = sloc_count['lib/**/*.rb']
85
+ test = sloc_count['test/**/*_{test,spec}.rb']
86
+ puts <<-EOF
87
+ Cordon code stats
88
+ Lib LOC: #{ '%3d' % lib }
89
+ Test LOC: #{ '%3d' % test }
90
+ Lib/test: #{ '%.1f' % (lib/test) }
91
+ EOF
92
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.2
data/cordon.gemspec ADDED
@@ -0,0 +1,76 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{cordon}
8
+ s.version = "0.2.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Sam Livingston-Gray}]
12
+ s.date = %q{2012-03-09}
13
+ s.description = %q{A bit of an experiment, really}
14
+ s.email = %q{geeksam@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.markdown"
18
+ ]
19
+ s.files = [
20
+ "LICENSE.txt",
21
+ "README.markdown",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "cordon.gemspec",
25
+ "lib/cordon.rb",
26
+ "lib/cordon/blacklist.rb",
27
+ "lib/cordon/sanitaire.rb",
28
+ "lib/cordon/violation.rb",
29
+ "lib/cordon/whitelist.rb",
30
+ "test/framework_integration/minitest_spec_spec.rb",
31
+ "test/framework_integration/rspec_spec.rb",
32
+ "test/helper.rb",
33
+ "test/integration/backtrace_cleaning_test.rb",
34
+ "test/integration/cordon_basic_examples_test.rb",
35
+ "test/integration/cordon_customization_test.rb",
36
+ "test/integration/cordon_default_behavior_test.rb",
37
+ "test/integration/cordon_edge_cases_test.rb",
38
+ "test/integration/integration_test_helper.rb"
39
+ ]
40
+ s.homepage = %q{http://github.com/geeksam/cordon}
41
+ s.licenses = [%q{WTFPL}]
42
+ s.require_paths = [%q{lib}]
43
+ s.rubygems_version = %q{1.8.6}
44
+ s.summary = %q{Cordon Sanitaire: hygienic handling of infectious methods}
45
+
46
+ if s.respond_to? :specification_version then
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
51
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
52
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
53
+ s.add_development_dependency(%q<mocha>, ["~> 0.10.3"])
54
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
55
+ s.add_development_dependency(%q<rspec>, [">= 0"])
56
+ s.add_development_dependency(%q<minitest>, [">= 0"])
57
+ else
58
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
59
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
60
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
61
+ s.add_dependency(%q<mocha>, ["~> 0.10.3"])
62
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
63
+ s.add_dependency(%q<rspec>, [">= 0"])
64
+ s.add_dependency(%q<minitest>, [">= 0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<rdoc>, ["~> 3.12"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
70
+ s.add_dependency(%q<mocha>, ["~> 0.10.3"])
71
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
72
+ s.add_dependency(%q<rspec>, [">= 0"])
73
+ s.add_dependency(%q<minitest>, [">= 0"])
74
+ end
75
+ end
76
+
data/lib/cordon.rb ADDED
@@ -0,0 +1,52 @@
1
+ # Require ALL the sources!
2
+ Dir.glob(File.join(File.dirname(__FILE__), 'cordon/*.rb')).each { |f| require f }
3
+
4
+
5
+ # Protect ALL the objects!
6
+ class Object
7
+ include Cordon::Sanitaire
8
+ end
9
+
10
+
11
+ # Patch ALL the monkeys!
12
+ module Kernel
13
+ # This bit of metaprogramming replaces a blacklisted method with a hook that calls back
14
+ # into the #__cordon__call_method__ defined in Cordon::Sanitaire (and, therefore, mixed in to Object)
15
+ def __cordon__wrap_method__(method)
16
+ # Take advantage of the fact that the block passed to define_method is a closure,
17
+ # so we can find the blacklisted method quickly.
18
+ # Use a name unlikely to collide in the object's own binding.
19
+ __cordon__receiver__ = self
20
+ define_method(method) do |*args, &b|
21
+ subject = __cordon__receiver__
22
+ __cordon__call_method__(subject, method, *args, &b)
23
+ end
24
+ end
25
+ end
26
+
27
+
28
+ module Cordon
29
+ # Declare specific methods as off-limits
30
+ def self.blacklist(subject, methods)
31
+ methods.each do |method|
32
+ Blacklist.blacklist_method(subject, method.to_sym)
33
+ end
34
+ end
35
+
36
+ # Shorthand for blacklisting the undesirable methods in specific frameworks
37
+ def self.embargo(framework)
38
+ case framework
39
+ when :rspec
40
+ blacklist Kernel, [:should, :should_not]
41
+ when :minitest_spec
42
+ must_and_wont = MiniTest::Expectations.instance_methods.map(&:to_s).select {|e| e =~ /^(must|wont)_/}
43
+ blacklist MiniTest::Expectations, must_and_wont
44
+ else
45
+ raise "I don't know how to embargo #{framework}!"
46
+ end
47
+ end
48
+
49
+ def self.wrap_assertions_with(custom_method_name)
50
+ Sanitaire.wrap_assertions_with(custom_method_name)
51
+ end
52
+ end
@@ -0,0 +1,30 @@
1
+ module Cordon
2
+ module Blacklist
3
+ TheList = {}
4
+
5
+ def self.blacklist_method(subject, method)
6
+ return if unbound_method(subject, method) # be idempotent
7
+
8
+ # Unbind the original method, and replace it with a wrapper that
9
+ # checks for permission before binding and calling the original
10
+ Blacklist.unbind_method(subject, method)
11
+ subject.__cordon__wrap_method__(method)
12
+ end
13
+
14
+ def self.invoke_method(instance, subject, method, *args, &b)
15
+ um = unbound_method(subject, method)
16
+ um.bind(instance).call(*args, &b)
17
+ end
18
+
19
+ protected
20
+
21
+ def self.unbind_method(subject, method)
22
+ um = subject.instance_method(method) # will raise NameError if the method doesn't exist
23
+ TheList[[subject, method]] = um
24
+ end
25
+
26
+ def self.unbound_method(subject, method)
27
+ TheList[[subject, method]]
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ module Cordon
2
+ module Sanitaire
3
+
4
+ def __cordon__assertion_wrapper__(predicate)
5
+ ::Cordon::Whitelist.admit_one(predicate)
6
+ return predicate
7
+ end
8
+
9
+ def self.wrap_assertions_with(custom_method_name)
10
+ alias_method custom_method_name, :__cordon__assertion_wrapper__
11
+ end
12
+ wrap_assertions_with :assert_that
13
+
14
+ protected
15
+
16
+ def __cordon__call_method__(subject, method, *args, &b)
17
+ ::Cordon::Whitelist.check_permissions(self, subject, method, *args)
18
+ ::Cordon::Blacklist.invoke_method(self, subject, method, *args, &b)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,9 @@
1
+ module Cordon
2
+ class Violation < Exception
3
+ def backtrace
4
+ bt = super
5
+ bt.shift while bt && bt.first =~ /cordon\.rb\:\d+\:in/
6
+ bt
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ module Cordon
2
+ module Whitelist
3
+ TheList = []
4
+
5
+ def self.admit_one(object)
6
+ TheList << object
7
+ end
8
+
9
+ def self.check_permissions(instance, subject, method, *args)
10
+ allowed = !! TheList.delete(instance)
11
+ return if allowed
12
+ message = '%s#%s(%s)' % [subject, method, args.map(&:inspect).join(', ')]
13
+ raise ::Cordon::Violation, message
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. helper]))
2
+ require 'minitest/autorun'
3
+
4
+ Cordon.embargo :minitest_spec
5
+
6
+ describe "MiniTest::Spec integration" do
7
+ it 'works just fine if you adhere to the rules' do
8
+ assert_that(42).must_equal 42
9
+ end
10
+
11
+ it 'explodes if you use standard^H^H evil MiniTest::Spec idiom' do
12
+ begin
13
+ 42.must_equal 6*9
14
+ flunk "This line should not be executed"
15
+ rescue Cordon::Violation
16
+ # all is well; carry on
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), *%w[.. helper]))
2
+ require 'rspec'
3
+
4
+ Cordon.embargo :rspec
5
+
6
+ describe "RSpec integration" do
7
+ it 'works just fine if you adhere to the rules' do
8
+ assert_that(42).should == 42
9
+ end
10
+
11
+ it 'explodes if you use standard^H^H evil RSpec idiom' do
12
+ begin
13
+ 42.should == 6*9
14
+ raise "This line should not be executed"
15
+ rescue Cordon::Violation
16
+ # all is well; carry on
17
+ end
18
+ end
19
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+
11
+ require 'ruby-debug'
12
+
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
+ require 'cordon'
@@ -0,0 +1,20 @@
1
+ require File.join(File.dirname(__FILE__), 'integration_test_helper')
2
+
3
+ module Kernel
4
+ def verboten_method_for_backtrace
5
+ raise VerbotenMethodCallReachedKernel
6
+ end
7
+ end
8
+
9
+ Cordon.blacklist Kernel, [:verboten_method_for_backtrace]
10
+
11
+ # Cordon will remove its own method calls from the backtrace; hopefully this will reduce confusion somewhat
12
+ class BacktraceCleaningUnitTest < CordonUnitTest
13
+ def test_cordon_lines_are_removed_from_violation_backtrace
14
+ foo.verboten_method_for_backtrace
15
+ rescue Cordon::Violation => e
16
+ failure_message = "cordon.rb appears in first line of backtrace:\n"
17
+ failure_message << (e.backtrace[0..3] + ['(rest of backtrace omitted)']).map { |e| ' ' + e }.join("\n")
18
+ refute e.backtrace.first.include?('cordon.rb:'), failure_message
19
+ end
20
+ end
@@ -0,0 +1,39 @@
1
+ require File.join(File.dirname(__FILE__), 'integration_test_helper')
2
+
3
+ module Kernel
4
+ def verboten_method
5
+ raise VerbotenMethodCallReachedKernel
6
+ end
7
+ end
8
+
9
+ # You can tell Cordon to blacklist certain methods on all objects.
10
+ Cordon.blacklist Kernel, [:verboten_method]
11
+
12
+ class CordonBasicExamples < CordonUnitTest
13
+ # Calling #verboten_method on an object will raise an exception...
14
+ def test_raises_exception_when_calling__verboten_method
15
+ assert_raise(Cordon::Violation) do
16
+ foo.verboten_method
17
+ end
18
+ end
19
+
20
+ # ...unless you explicitly wrap that object in an #assert_that call
21
+ def test_allows_explicit_calls_to__verboten_method
22
+ assert_raises(VerbotenMethodCallReachedKernel) do
23
+ assert_that(foo).verboten_method
24
+ end
25
+ end
26
+
27
+ # ...every time!
28
+ def test_permission_provided_by_assert_that_only_works_once
29
+ assert_raise(Cordon::Violation) do
30
+ begin
31
+ assert_that(foo).verboten_method
32
+ rescue VerbotenMethodCallReachedKernel
33
+ # carry on
34
+ end
35
+ foo.verboten_method
36
+ end
37
+ end
38
+ end
39
+
@@ -0,0 +1,29 @@
1
+ require File.join(File.dirname(__FILE__), 'integration_test_helper')
2
+
3
+ module Kernel
4
+ def should_probably(*_)
5
+ raise VerbotenMethodCallReachedKernel
6
+ end
7
+ end
8
+
9
+ Cordon.blacklist Kernel, [:should_probably]
10
+
11
+
12
+ # You can specify a different method than #assert_that as your custom assertion wrapper
13
+ Cordon.wrap_assertions_with :if_you_would_be_so_kind
14
+
15
+ class CordonCustomizationExamples < CordonUnitTest
16
+ def test_raises_exception_when_calling__verboten_method
17
+ assert_raise(Cordon::Violation) do
18
+ foo.should_probably :explode
19
+ end
20
+ end
21
+
22
+ # ...unless you explicitly wrap that object in an #assert_that call
23
+ def test_allows_explicit_calls_to__verboten_method
24
+ assert_raises(VerbotenMethodCallReachedKernel) do
25
+ if_you_would_be_so_kind(foo).should_probably :work # but only if you feel like it
26
+ end
27
+ end
28
+ end
29
+
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), 'integration_test_helper')
2
+
3
+ module Kernel
4
+ def verboten_method_not_on_cordon_watch_list
5
+ raise VerbotenMethodCallReachedKernel
6
+ end
7
+ end
8
+
9
+ # By default, Cordon does nothing!
10
+ class CordonDefaultBehaviorUnitTest < CordonUnitTest
11
+ def test_allows_calls_to__verboten_method_not_on_cordon_watch_list
12
+ assert_raises(VerbotenMethodCallReachedKernel) { foo.verboten_method_not_on_cordon_watch_list }
13
+ end
14
+ end
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(__FILE__), 'integration_test_helper')
2
+
3
+ module Kernel
4
+ def verboten_method_with_args(*args)
5
+ raise "No args given!" if args.empty?
6
+ raise VerbotenMethodCallReachedKernel, args.inspect
7
+ end
8
+
9
+ def verboten_method_with_block(*_)
10
+ raise "Block expected!" unless block_given?
11
+ yield
12
+ raise VerbotenMethodCallReachedKernel
13
+ end
14
+
15
+ def verboten_method_with_args_and_block_with_args(options = {})
16
+ raise "No args given!" if options.empty?
17
+ raise "Block expected!" unless block_given?
18
+ arg_for_block = options.fetch(:arg_for_block)
19
+ yield arg_for_block
20
+ raise VerbotenMethodCallReachedKernel, options.inspect
21
+ end
22
+ end
23
+
24
+ Cordon.blacklist Kernel, [:verboten_method, :verboten_method_with_args, :verboten_method_with_block]
25
+
26
+ class CordonEdgeCaseTests < CordonUnitTest
27
+ # Arguments to verboten methods are passed along as one might expect
28
+ def test_raises_exception_when_calling__verboten_method_with_args
29
+ args = [:foo, :bar, :baz]
30
+ begin
31
+ line = __LINE__; foo.verboten_method_with_args(*args)
32
+ rescue Cordon::Violation => e
33
+ expected = "Kernel#verboten_method_with_args(#{args.map(&:inspect).join(', ')})"
34
+ assert_equal expected, e.message
35
+ rescue VerbotenMethodCallReachedKernel
36
+ flunk "foo.verboten_method_with_args(#{args.map(&:inspect).join(', ')}) should not be allowed! (See line #{line})"
37
+ end
38
+ end
39
+
40
+ def test_allows_explicit_calls_to__verboten_method_with_args
41
+ assert_raises(VerbotenMethodCallReachedKernel) do
42
+ assert_that(foo).verboten_method_with_args(:foo, :bar, :baz)
43
+ end
44
+ end
45
+
46
+ # And blocks given to verboten methods are yielded to as one might expect
47
+ # Calling #verboten_method_with_block should raise an exception
48
+ def test_raises_exception_when_calling__verboten_method_with_block
49
+ block_was_called = false
50
+ begin
51
+ line = __LINE__; foo.verboten_method_with_block() { block_was_called = true }
52
+ rescue Cordon::Violation => e
53
+ expected = "Kernel#verboten_method_with_block()"
54
+ assert_equal expected, e.message
55
+ assert_equal false, block_was_called, "Block was called, but it shouldn't have been!"
56
+ rescue VerbotenMethodCallReachedKernel
57
+ flunk "foo.verboten_method_with_block(&b) should not be allowed! (See line #{line})"
58
+ end
59
+ end
60
+
61
+ def test_allows_explicit_calls_to__verboten_method_with_block
62
+ block_was_called = false
63
+ assert_raises(VerbotenMethodCallReachedKernel) do
64
+ assert_that(foo).verboten_method_with_block() { block_was_called = true }
65
+ end
66
+ assert block_was_called, "Block wasn't called when it should have been!"
67
+ end
68
+
69
+ # Blocks with args get passed the args they expect.
70
+ def test_allows_explicit_calls_to__verboten_method_with_args_and_block_with_args
71
+ block_was_called = false
72
+ arg_passed_to_block = nil
73
+ assert_raises(VerbotenMethodCallReachedKernel) do
74
+ assert_that(foo).verboten_method_with_args_and_block_with_args(:arg_for_block => 42) do |x|
75
+ block_was_called = true
76
+ arg_passed_to_block = x
77
+ end
78
+ end
79
+ assert block_was_called, "Block wasn't called when it should have been!"
80
+ assert_equal 42, arg_passed_to_block
81
+ end
82
+ end
@@ -0,0 +1,16 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. helper])
2
+ require 'test/unit'
3
+
4
+ module Kernel
5
+ VerbotenMethodCallReachedKernel = Class.new(Exception)
6
+ end
7
+
8
+ class CordonUnitTest < Test::Unit::TestCase
9
+ def foo
10
+ @foo ||= Object.new
11
+ end
12
+
13
+ def refute(predicate, *other_args)
14
+ assert !predicate, *other_args
15
+ end
16
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cordon
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sam Livingston-Gray
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-09 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rdoc
16
+ requirement: &2156968780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.12'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2156968780
25
+ - !ruby/object:Gem::Dependency
26
+ name: bundler
27
+ requirement: &2156967060 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2156967060
36
+ - !ruby/object:Gem::Dependency
37
+ name: jeweler
38
+ requirement: &2156964940 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 1.8.3
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2156964940
47
+ - !ruby/object:Gem::Dependency
48
+ name: mocha
49
+ requirement: &2156962400 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.10.3
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2156962400
58
+ - !ruby/object:Gem::Dependency
59
+ name: ruby-debug19
60
+ requirement: &2156960720 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2156960720
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: &2156958500 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2156958500
80
+ - !ruby/object:Gem::Dependency
81
+ name: minitest
82
+ requirement: &2156956460 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *2156956460
91
+ description: A bit of an experiment, really
92
+ email: geeksam@gmail.com
93
+ executables: []
94
+ extensions: []
95
+ extra_rdoc_files:
96
+ - LICENSE.txt
97
+ - README.markdown
98
+ files:
99
+ - LICENSE.txt
100
+ - README.markdown
101
+ - Rakefile
102
+ - VERSION
103
+ - cordon.gemspec
104
+ - lib/cordon.rb
105
+ - lib/cordon/blacklist.rb
106
+ - lib/cordon/sanitaire.rb
107
+ - lib/cordon/violation.rb
108
+ - lib/cordon/whitelist.rb
109
+ - test/framework_integration/minitest_spec_spec.rb
110
+ - test/framework_integration/rspec_spec.rb
111
+ - test/helper.rb
112
+ - test/integration/backtrace_cleaning_test.rb
113
+ - test/integration/cordon_basic_examples_test.rb
114
+ - test/integration/cordon_customization_test.rb
115
+ - test/integration/cordon_default_behavior_test.rb
116
+ - test/integration/cordon_edge_cases_test.rb
117
+ - test/integration/integration_test_helper.rb
118
+ homepage: http://github.com/geeksam/cordon
119
+ licenses:
120
+ - WTFPL
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ none: false
127
+ requirements:
128
+ - - ! '>='
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ segments:
132
+ - 0
133
+ hash: 2252535489042103113
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ! '>='
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ requirements: []
141
+ rubyforge_project:
142
+ rubygems_version: 1.8.6
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: ! 'Cordon Sanitaire: hygienic handling of infectious methods'
146
+ test_files: []