quickie 0.2.0 → 0.3.0
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/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
|