quickie 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -0
- data/Gemfile.lock +1 -1
- data/README.md +66 -28
- data/lib/quickie.rb +1 -0
- data/lib/quickie/core_ext/object.rb +5 -0
- data/lib/quickie/stub.rb +109 -0
- data/lib/quickie/version.rb +1 -1
- data/test/matcher_test.rb +65 -0
- data/test/quickie_test.rb +2 -60
- data/test/stub_test.rb +29 -0
- metadata +10 -4
data/CHANGELOG
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
## Quickie ##
|
2
|
-
Quickie is micro library for quick in-place testing of your Ruby code. It adds
|
3
|
-
methods: <code>Object#should</code> and <code>Object#should\_not</code> for
|
4
|
-
negative assertions
|
5
|
-
|
2
|
+
Quickie is micro library for quick in-place testing of your Ruby code. It adds three
|
3
|
+
useful methods: <code>Object#should</code> and <code>Object#should\_not</code> for
|
4
|
+
positive and negative assertions, and <code>Object#stub</code> for method stubbing.
|
5
|
+
|
6
|
+
With Quickie you can conveniently bundle tests along with your Ruby code, typically
|
7
|
+
within <code>if $0 == \_\_FILE\_\_</code> conditional statement.
|
6
8
|
|
7
9
|
### System Requirements ###
|
8
10
|
Ruby 1.9.2 or later.
|
@@ -14,24 +16,18 @@ Ruby 1.9.2 or later.
|
|
14
16
|
# Cloning the repository
|
15
17
|
$ git clone git://github.com/michaeldv/quickie.git
|
16
18
|
|
17
|
-
### Usage Example ###
|
19
|
+
### Usage Example - Assertions ###
|
18
20
|
|
19
|
-
$ cat >
|
21
|
+
$ cat > 1.rb
|
20
22
|
class Account # Back account class.
|
21
23
|
attr_reader :balance # Current account balance.
|
22
24
|
|
23
|
-
def initialize(amount)
|
24
|
-
@balance = amount
|
25
|
-
end
|
26
|
-
|
27
|
-
def deposit(amount) # Accept account deposit.
|
28
|
-
@balance += amount # Update current balance.
|
25
|
+
def initialize(amount = 0) # Open the account.
|
26
|
+
@balance = amount.abs # Accept initial deposit.
|
29
27
|
end
|
30
28
|
|
31
|
-
def
|
32
|
-
|
33
|
-
@balance -= cash # Update current balance.
|
34
|
-
cash
|
29
|
+
def deposit(amount) # Accept a deposit.
|
30
|
+
@balance += amount.abs # Update current balance.
|
35
31
|
end
|
36
32
|
|
37
33
|
def status # Display account status.
|
@@ -46,30 +42,72 @@ Ruby 1.9.2 or later.
|
|
46
42
|
acc.balance.should == 100 # Initial balance should be $100.
|
47
43
|
acc.deposit(200) # Deposit $200 more.
|
48
44
|
acc.balance.should != 100 # The balance should get updated.
|
49
|
-
acc.balance.should == 300 #
|
45
|
+
acc.balance.should == 300 # $100 + $200 = $300.
|
50
46
|
|
51
47
|
String.should === acc.status # Account#status returns a string.
|
52
48
|
acc.status.should_not =~ /\$$/ # Status string should contain the balance.
|
53
|
-
acc.status.should =~ /\$\d
|
54
|
-
|
55
|
-
acc.withdraw(500).should == 300 # Withdrawal that exeeds the balance is not allowed.
|
56
|
-
acc.balance.should == 0 # Current balance should drop to zero.
|
57
|
-
acc.status.should !~ /\$[1-9]+$/ # Status no longer shows positive number.
|
58
|
-
acc.status.should =~ /\$0$/ # It shows $0.
|
49
|
+
acc.status.should =~ /\$\d+\.*\d*$/ # Balance contains digits with optional separator.
|
59
50
|
end
|
60
51
|
^D
|
61
|
-
$ ruby
|
62
|
-
|
52
|
+
$ ruby 1.rb
|
53
|
+
......
|
54
|
+
|
55
|
+
Passed: 6, not quite: 0, total tests: 6.
|
56
|
+
|
57
|
+
### Usage Example - Method Stubs ###
|
58
|
+
To set up a stub with optional return value use <code>obj.stub(:method, :return => value)</code>.
|
59
|
+
To remove existing stub and restore original method use <code>obj.stub(:method, :remove)</code>.
|
60
|
+
|
61
|
+
$ cat > 2.rb
|
62
|
+
require "net/http"
|
63
|
+
require "json"
|
64
|
+
require "uri"
|
65
|
+
|
66
|
+
class GemStats # Get gems stats from rubygems.org.
|
67
|
+
attr_reader :downloads
|
68
|
+
|
69
|
+
def initialize(gem, version)
|
70
|
+
uri = URI.parse("http://rubygems.org/api/v1/downloads/#{gem}-#{version}.json")
|
71
|
+
response = Net::HTTP.get_response(uri)
|
72
|
+
@downloads = JSON.parse(response.body)
|
73
|
+
end
|
74
|
+
|
75
|
+
def total
|
76
|
+
@downloads["total_downloads"]
|
77
|
+
end
|
78
|
+
|
79
|
+
def version
|
80
|
+
@downloads["version_downloads"]
|
81
|
+
end
|
82
|
+
end
|
63
83
|
|
64
|
-
|
84
|
+
if $0 == __FILE__
|
85
|
+
require "quickie"
|
86
|
+
|
87
|
+
response = { :total_downloads => 999_999, :version_downloads => 999 }.to_json
|
88
|
+
response.stub(:body, :return => response)
|
89
|
+
Net::HTTP.stub(:get_response, :return => response)
|
90
|
+
|
91
|
+
stats = GemStats.new(:awesome_print, '1.0.2')
|
92
|
+
|
93
|
+
Hash.should === stats.downloads # Downloads should ba a hash.
|
94
|
+
stats.downloads.keys.size.should == 2 # It should have two keys.
|
95
|
+
stats.total.should == 999_999 # Total downloads should match test data.
|
96
|
+
stats.version.should == 999 # Ditto for version.
|
97
|
+
end
|
98
|
+
^D
|
99
|
+
$ ruby 2.rb
|
100
|
+
....
|
101
|
+
|
102
|
+
Passed: 4, not quite: 0, total tests: 4.
|
65
103
|
|
66
104
|
### Testing Quickie ###
|
67
105
|
Quickie code is tested by the Quickie itself.
|
68
106
|
|
69
107
|
$ ruby test/quickie_test.rb
|
70
|
-
|
108
|
+
................................
|
71
109
|
|
72
|
-
Passed:
|
110
|
+
Passed: 32, not quite: 0, total tests: 32.
|
73
111
|
|
74
112
|
### Note on Patches/Pull Requests ###
|
75
113
|
* Fork the project on Github.
|
data/lib/quickie.rb
CHANGED
@@ -11,5 +11,6 @@ abort "Quickie requires Ruby 1.9.2 or later" if RUBY_VERSION < "1.9.2"
|
|
11
11
|
|
12
12
|
require File.dirname(__FILE__) + "/quickie/runner"
|
13
13
|
require File.dirname(__FILE__) + "/quickie/matcher"
|
14
|
+
require File.dirname(__FILE__) + "/quickie/stub"
|
14
15
|
require File.dirname(__FILE__) + "/quickie/version"
|
15
16
|
require File.dirname(__FILE__) + "/quickie/core_ext/object"
|
data/lib/quickie/stub.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Copyright (c) 2011-12 Michael Dvorkin
|
2
|
+
#
|
3
|
+
# Quickie is freely distributable under the terms of MIT license.
|
4
|
+
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
module Quickie
|
7
|
+
class Stub
|
8
|
+
#
|
9
|
+
# To set up a stub with optional return value:
|
10
|
+
# obj.stub(:method, :return => something)
|
11
|
+
#
|
12
|
+
# To remove existing stub and restore original method:
|
13
|
+
# obj.stub(:method, :remove)
|
14
|
+
#
|
15
|
+
#--------------------------------------------------------------------------
|
16
|
+
def initialize(object, method, options = {})
|
17
|
+
options = { options => true } if options.is_a?(Symbol)
|
18
|
+
@object, @options = object, options
|
19
|
+
@@stash ||= []
|
20
|
+
#
|
21
|
+
# Create a new stub by intercepting the method or remove existing stub
|
22
|
+
# by restoring the original method.
|
23
|
+
#
|
24
|
+
unless @options[:remove]
|
25
|
+
intercept(method)
|
26
|
+
else
|
27
|
+
restore(method)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Same as class << @object; self; end -- comes with Ruby 1.9.
|
34
|
+
#--------------------------------------------------------------------------
|
35
|
+
def metaclass
|
36
|
+
@object.singleton_class
|
37
|
+
end
|
38
|
+
|
39
|
+
# Unique name the original method gets stashed under when creating a stub.
|
40
|
+
#--------------------------------------------------------------------------
|
41
|
+
def moniker(method)
|
42
|
+
:"__#{method}__#{@object.__id__}"
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return method's visibility, nil if public.
|
46
|
+
#--------------------------------------------------------------------------
|
47
|
+
def visibility(method)
|
48
|
+
if metaclass.private_method_defined?(method)
|
49
|
+
:private
|
50
|
+
elsif metaclass.protected_method_defined?(method)
|
51
|
+
:protected
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Set up a stub by stashing the original method under different name and
|
56
|
+
# then rediefining the method to return the requested value.
|
57
|
+
#--------------------------------------------------------------------------
|
58
|
+
def intercept(method)
|
59
|
+
new_name = moniker(method)
|
60
|
+
unless @object.respond_to? new_name
|
61
|
+
stash(method, new_name)
|
62
|
+
redefine(method)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Preserve original method by creating its alias with the unique name.
|
67
|
+
#--------------------------------------------------------------------------
|
68
|
+
def stash(method, new_name)
|
69
|
+
metaclass.class_eval do
|
70
|
+
if method_defined?(method) || private_method_defined?(method)
|
71
|
+
alias_method new_name, method
|
72
|
+
end
|
73
|
+
end
|
74
|
+
@@stash << new_name
|
75
|
+
end
|
76
|
+
|
77
|
+
# Create a stub that returns requested value.
|
78
|
+
#--------------------------------------------------------------------------
|
79
|
+
def redefine(method)
|
80
|
+
return_value = @options[:return]
|
81
|
+
metaclass.class_eval do
|
82
|
+
define_method method do |*args, &block|
|
83
|
+
return_value
|
84
|
+
end
|
85
|
+
end
|
86
|
+
#
|
87
|
+
# Set visibility attribute if the origial method is not public.
|
88
|
+
#
|
89
|
+
private_or_protected = visibility(method)
|
90
|
+
metaclass.class_eval("#{private_or_protected} :#{method}") if private_or_protected
|
91
|
+
end
|
92
|
+
|
93
|
+
# Remove the stub and restore the original method.
|
94
|
+
#--------------------------------------------------------------------------
|
95
|
+
def restore(method)
|
96
|
+
stashed_name = moniker(method)
|
97
|
+
if @@stash.include? stashed_name # Was it ever stubbed?
|
98
|
+
metaclass.instance_eval do
|
99
|
+
if method_defined?(stashed_name) || private_method_defined?(stashed_name)
|
100
|
+
remove_method method # Remove the stub.
|
101
|
+
alias_method method, stashed_name # Restore the original method from stash.
|
102
|
+
remove_method stashed_name # Remove stashed copy.
|
103
|
+
end
|
104
|
+
end
|
105
|
+
@@stash.delete stashed_name
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/quickie/version.rb
CHANGED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Copyright (c) 2011-12 Michael Dvorkin
|
2
|
+
#
|
3
|
+
# Quickie is freely distributable under the terms of MIT license.
|
4
|
+
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
require "stringio"
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/quickie")
|
8
|
+
|
9
|
+
# Use Quickie to test itself. The methodology is as follows:
|
10
|
+
#
|
11
|
+
# 1. Write regular Quickie test.
|
12
|
+
# 2. Capture the output of the test.
|
13
|
+
# 3. Make sure captured output matches the expectation.
|
14
|
+
#
|
15
|
+
# In addition, we hack the Quickie trace/stats so that failed captured
|
16
|
+
# tests are not shown/counted in the actual results.
|
17
|
+
#--------------------------------------------------------------------------
|
18
|
+
def capture
|
19
|
+
stats = Quickie::Runner.class_variable_get(:@@stats)
|
20
|
+
trace = Quickie::Runner.class_variable_get(:@@trace)
|
21
|
+
|
22
|
+
standard, $stdout = $stdout, StringIO.new
|
23
|
+
yield
|
24
|
+
$stdout.string
|
25
|
+
ensure
|
26
|
+
if $stdout.string == '.'
|
27
|
+
stats[:success] -= 1
|
28
|
+
else
|
29
|
+
stats[:failure] -= 1
|
30
|
+
trace.pop
|
31
|
+
end
|
32
|
+
$stdout = standard
|
33
|
+
end
|
34
|
+
|
35
|
+
# Should - passing specs.
|
36
|
+
#--------------------------------------------------------------------------
|
37
|
+
capture { "abc".should == "abc" }.should == "."
|
38
|
+
capture { "abc".should != "xyz" }.should == "."
|
39
|
+
capture { "abc".should =~ /AB/i }.should == "."
|
40
|
+
capture { "abc".should !~ /XY/i }.should == "."
|
41
|
+
capture { 1234567.should_be > 0 }.should == "."
|
42
|
+
|
43
|
+
# Should Not - passing specs.
|
44
|
+
#--------------------------------------------------------------------------
|
45
|
+
capture { "abc".should_not != "abc" }.should == "."
|
46
|
+
capture { "abc".should_not == "xyz" }.should == "."
|
47
|
+
capture { "abc".should_not !~ /AB/i }.should == "."
|
48
|
+
capture { "abc".should_not =~ /XY/i }.should == "."
|
49
|
+
capture { 1234567.should_not_be < 0 }.should == "."
|
50
|
+
|
51
|
+
# Should - failing specs.
|
52
|
+
#--------------------------------------------------------------------------
|
53
|
+
capture { "abc".should != "abc" }.should == "F"
|
54
|
+
capture { "abc".should == "xyz" }.should == "F"
|
55
|
+
capture { "abc".should !~ /AB/i }.should == "F"
|
56
|
+
capture { "abc".should =~ /XY/i }.should == "F"
|
57
|
+
capture { 1234567.should_be < 0 }.should == "F"
|
58
|
+
|
59
|
+
# Should Not - failing specs.
|
60
|
+
#--------------------------------------------------------------------------
|
61
|
+
capture { "abc".should_not == "abc" }.should == "F"
|
62
|
+
capture { "abc".should_not != "xyz" }.should == "F"
|
63
|
+
capture { "abc".should_not =~ /AB/i }.should == "F"
|
64
|
+
capture { "abc".should_not !~ /XY/i }.should == "F"
|
65
|
+
capture { 1234567.should_not_be > 0 }.should == "F"
|
data/test/quickie_test.rb
CHANGED
@@ -3,63 +3,5 @@
|
|
3
3
|
# Quickie is freely distributable under the terms of MIT license.
|
4
4
|
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
5
|
#------------------------------------------------------------------------------
|
6
|
-
require "
|
7
|
-
require File.expand_path(File.dirname(__FILE__) + "
|
8
|
-
|
9
|
-
# Use Quickie to test itself. The methodology is as follows:
|
10
|
-
#
|
11
|
-
# 1. Write regular Quickie test.
|
12
|
-
# 2. Capture the output of the test.
|
13
|
-
# 3. Make sure captured output matches the expectation.
|
14
|
-
#
|
15
|
-
# In addition, we hack the Quickie trace/stats so that failed captured
|
16
|
-
# tests are not shown/counted in the actual results.
|
17
|
-
#--------------------------------------------------------------------------
|
18
|
-
def capture
|
19
|
-
stats = Quickie::Runner.class_variable_get(:@@stats)
|
20
|
-
trace = Quickie::Runner.class_variable_get(:@@trace)
|
21
|
-
|
22
|
-
standard, $stdout = $stdout, StringIO.new
|
23
|
-
yield
|
24
|
-
$stdout.string
|
25
|
-
ensure
|
26
|
-
if $stdout.string == '.'
|
27
|
-
stats[:success] -= 1
|
28
|
-
else
|
29
|
-
stats[:failure] -= 1
|
30
|
-
trace.pop
|
31
|
-
end
|
32
|
-
$stdout = standard
|
33
|
-
end
|
34
|
-
|
35
|
-
# Should - passing specs.
|
36
|
-
#--------------------------------------------------------------------------
|
37
|
-
capture { "abc".should == "abc" }.should == "."
|
38
|
-
capture { "abc".should != "xyz" }.should == "."
|
39
|
-
capture { "abc".should =~ /AB/i }.should == "."
|
40
|
-
capture { "abc".should !~ /XY/i }.should == "."
|
41
|
-
capture { 1234567.should_be > 0 }.should == "."
|
42
|
-
|
43
|
-
# Should Not - passing specs.
|
44
|
-
#--------------------------------------------------------------------------
|
45
|
-
capture { "abc".should_not != "abc" }.should == "."
|
46
|
-
capture { "abc".should_not == "xyz" }.should == "."
|
47
|
-
capture { "abc".should_not !~ /AB/i }.should == "."
|
48
|
-
capture { "abc".should_not =~ /XY/i }.should == "."
|
49
|
-
capture { 1234567.should_not_be < 0 }.should == "."
|
50
|
-
|
51
|
-
# Should - failing specs.
|
52
|
-
#--------------------------------------------------------------------------
|
53
|
-
capture { "abc".should != "abc" }.should == "F"
|
54
|
-
capture { "abc".should == "xyz" }.should == "F"
|
55
|
-
capture { "abc".should !~ /AB/i }.should == "F"
|
56
|
-
capture { "abc".should =~ /XY/i }.should == "F"
|
57
|
-
capture { 1234567.should_be < 0 }.should == "F"
|
58
|
-
|
59
|
-
# Should Not - failing specs.
|
60
|
-
#--------------------------------------------------------------------------
|
61
|
-
capture { "abc".should_not == "abc" }.should == "F"
|
62
|
-
capture { "abc".should_not != "xyz" }.should == "F"
|
63
|
-
capture { "abc".should_not =~ /AB/i }.should == "F"
|
64
|
-
capture { "abc".should_not !~ /XY/i }.should == "F"
|
65
|
-
capture { 1234567.should_not_be > 0 }.should == "F"
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + "/matcher_test")
|
7
|
+
require File.expand_path(File.dirname(__FILE__) + "/stub_test")
|
data/test/stub_test.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright (c) 2011-12 Michael Dvorkin
|
2
|
+
#
|
3
|
+
# Quickie is freely distributable under the terms of MIT license.
|
4
|
+
# See LICENSE file or http://www.opensource.org/licenses/mit-license.php
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
require File.expand_path(File.dirname(__FILE__) + "/../lib/quickie")
|
7
|
+
|
8
|
+
numbers = [ 1, 2, 3 ]
|
9
|
+
letters = %w(a b c)
|
10
|
+
|
11
|
+
numbers.stub! :join, :return => 42 # Stub numbers#join to return arbitrary value.
|
12
|
+
numbers.join.should == 42 # Test numbers.join().
|
13
|
+
numbers.join(",").should == 42 # Test numbers.join(arg).
|
14
|
+
letters.join.should == "abc" # letters array is unaffected by numbers#join.
|
15
|
+
|
16
|
+
letters.stub! :join, :return => "Hello, world!" # Now stub letters#join.
|
17
|
+
letters.join.should == "Hello, world!" # Test letters.join().
|
18
|
+
letters.join(",").should == "Hello, world!" # Test letters.join(arg).
|
19
|
+
numbers.join.should == 42 # numbers#join stub is unaffected by letters#join stub.
|
20
|
+
numbers.join(",").should == 42 # Ditto.
|
21
|
+
|
22
|
+
numbers.stub :join, :remove # Remove numbers#join stub.
|
23
|
+
numbers.join.should == "123" # numbers.join() should work as expected.
|
24
|
+
numbers.join(",").should == "1,2,3" # numbers.join(arg) should work as expected.
|
25
|
+
letters.join.should == "Hello, world!" # letters#join remains stubbed.
|
26
|
+
|
27
|
+
letters.stub :join, :remove # Now remove letters#join stub.
|
28
|
+
letters.join.should == "abc" # letters.join() should work as expected.
|
29
|
+
letters.join(",").should == "a,b,c" # letters.join(arg) should work as expected.
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quickie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,8 +11,8 @@ bindir: bin
|
|
11
11
|
cert_chain: []
|
12
12
|
date: 2012-01-06 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description: Quickie adds Object#should and Object#
|
15
|
-
of your Ruby code
|
14
|
+
description: Quickie adds Object#should, Object#should_not, and Object#stub methods
|
15
|
+
for quick and easy testing of your Ruby code
|
16
16
|
email: mike@dvorkin.net
|
17
17
|
executables: []
|
18
18
|
extensions: []
|
@@ -27,9 +27,12 @@ files:
|
|
27
27
|
- lib/quickie/core_ext/object.rb
|
28
28
|
- lib/quickie/matcher.rb
|
29
29
|
- lib/quickie/runner.rb
|
30
|
+
- lib/quickie/stub.rb
|
30
31
|
- lib/quickie/version.rb
|
31
32
|
- lib/quickie.rb
|
33
|
+
- test/matcher_test.rb
|
32
34
|
- test/quickie_test.rb
|
35
|
+
- test/stub_test.rb
|
33
36
|
- .gitignore
|
34
37
|
homepage: http://github.com/michaeldv/quickie
|
35
38
|
licenses: []
|
@@ -55,4 +58,7 @@ rubygems_version: 1.8.11
|
|
55
58
|
signing_key:
|
56
59
|
specification_version: 3
|
57
60
|
summary: Micro framework for in-place testing of Ruby code
|
58
|
-
test_files:
|
61
|
+
test_files:
|
62
|
+
- test/matcher_test.rb
|
63
|
+
- test/quickie_test.rb
|
64
|
+
- test/stub_test.rb
|