orangutan 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README +58 -58
- data/Rakefile +34 -34
- data/VERSION.yml +4 -0
- data/lib/orangutan.rb +2 -2
- data/lib/orangutan/chantek.rb +49 -67
- data/lib/orangutan/clean_slate.rb +31 -2
- data/lib/orangutan/container.rb +3 -1
- data/lib/orangutan/expectation.rb +38 -36
- data/lib/orangutan/raiser.rb +9 -9
- data/lib/orangutan/stub_base.rb +32 -0
- data/orangutan.gemspec +65 -62
- data/prepare.cmd +11 -11
- data/spec/{ClassWithANonVirtualMethod.cs → clr/ClassWithANonVirtualMethod.cs} +12 -12
- data/spec/{ClassWithANonVirtualProperty.cs → clr/ClassWithANonVirtualProperty.cs} +21 -21
- data/spec/{ClassWithAVirtualMethod.cs → clr/ClassWithAVirtualMethod.cs} +13 -13
- data/spec/{ClassWithAVirtualProperty.cs → clr/ClassWithAVirtualProperty.cs} +22 -22
- data/spec/{Consumer.cs → clr/Consumer.cs} +29 -29
- data/spec/{IHaveAMethod.cs → clr/IHaveAMethod.cs} +8 -8
- data/spec/{IHaveAProperty.cs → clr/IHaveAProperty.cs} +9 -9
- data/spec/{IHaveAnEvent.cs → clr/IHaveAnEvent.cs} +8 -8
- data/spec/spec_chantek.rb +60 -60
- data/spec/spec_chantek_clr.rb +11 -11
- data/spec/spec_chantek_recurse.rb +24 -0
- data/spec/spec_expectation.rb +48 -50
- metadata +15 -14
- data/VERSION +0 -1
data/README
CHANGED
@@ -1,59 +1,59 @@
|
|
1
|
-
Orangutan is a mocking library.
|
2
|
-
|
3
|
-
It allows you to create stub objects and to setup methods with return, yield and raise behaviours.
|
4
|
-
|
5
|
-
It can be used in testing .net code using ironruby.
|
6
|
-
|
7
|
-
At this stage only the simplest of clr interfaces can be stubbed.
|
8
|
-
|
9
|
-
Note that only stub instances of objects are created. It can not create mocks of class methods.
|
10
|
-
|
11
|
-
It works by recording all method calls so that assertions can be made about them after the fact.
|
12
|
-
|
13
|
-
This means that orangutan can be used with any testing framework and in combination with other mock frameworks.
|
14
|
-
|
15
|
-
Installation:
|
16
|
-
|
17
|
-
gem install markryall-orangutan
|
18
|
-
|
19
|
-
Usage:
|
20
|
-
|
21
|
-
require 'orangutan'
|
22
|
-
@o = Orangutan::Chantek.new
|
23
|
-
|
24
|
-
# Creating a pure ruby stub
|
25
|
-
@stub = @orangutan.stub :stub
|
26
|
-
|
27
|
-
# Creating a stub that implements a clr interface
|
28
|
-
@clr_stub = @orangutan.stub :clr_stub, :clr_interface => System::IDisposable
|
29
|
-
|
30
|
-
# Setting up stub methods that return values
|
31
|
-
@o.when(:stub).receives(:execute).with(7).return('baz')
|
32
|
-
|
33
|
-
# Setting up stub methods that yield values
|
34
|
-
@o.when(:stub).receives(:execute).with(7).yield('baz')
|
35
|
-
|
36
|
-
# Setting up stub methods that raise errors
|
37
|
-
@o.when(:stub).receives(:execute).with(7).raise('baz')
|
38
|
-
|
39
|
-
# Checking recorded method calls
|
40
|
-
# at this stage you need to scan the array of call structs recorded in @o.calls
|
41
|
-
@o.calls[0].should == Orangutan::Call.new(:stub, :execute, [7])
|
42
|
-
|
43
|
-
Questions:
|
44
|
-
|
45
|
-
* Why Orangutan?
|
46
|
-
|
47
|
-
My daughter likes orangutans and I couldn't think of a better name. Both Sumatran and Bornean orangutans are endangered species so even if you intensely dislike this project or its implementation, at least you can be made aware of the plight of these spectacular creatures.
|
48
|
-
|
49
|
-
* Did it have anything to do with Clyde in "Every Which Way But Loose"
|
50
|
-
|
51
|
-
Definately not. What a ridiculous question. I'm appalled.
|
52
|
-
|
53
|
-
* What's Chantek?
|
54
|
-
|
55
|
-
Chantek is a famous orangutan that can solve sudokus and the rubik's cube - http://en.wikipedia.org/wiki/Chantek
|
56
|
-
|
57
|
-
* Why do I not need to register this as a mock framework?
|
58
|
-
|
1
|
+
Orangutan is a mocking library.
|
2
|
+
|
3
|
+
It allows you to create stub objects and to setup methods with return, yield and raise behaviours.
|
4
|
+
|
5
|
+
It can be used in testing .net code using ironruby.
|
6
|
+
|
7
|
+
At this stage only the simplest of clr interfaces can be stubbed.
|
8
|
+
|
9
|
+
Note that only stub instances of objects are created. It can not create mocks of class methods.
|
10
|
+
|
11
|
+
It works by recording all method calls so that assertions can be made about them after the fact.
|
12
|
+
|
13
|
+
This means that orangutan can be used with any testing framework and in combination with other mock frameworks.
|
14
|
+
|
15
|
+
Installation:
|
16
|
+
|
17
|
+
gem install markryall-orangutan
|
18
|
+
|
19
|
+
Usage:
|
20
|
+
|
21
|
+
require 'orangutan'
|
22
|
+
@o = Orangutan::Chantek.new
|
23
|
+
|
24
|
+
# Creating a pure ruby stub
|
25
|
+
@stub = @orangutan.stub :stub
|
26
|
+
|
27
|
+
# Creating a stub that implements a clr interface
|
28
|
+
@clr_stub = @orangutan.stub :clr_stub, :clr_interface => System::IDisposable
|
29
|
+
|
30
|
+
# Setting up stub methods that return values
|
31
|
+
@o.when(:stub).receives(:execute).with(7).return('baz')
|
32
|
+
|
33
|
+
# Setting up stub methods that yield values
|
34
|
+
@o.when(:stub).receives(:execute).with(7).yield('baz')
|
35
|
+
|
36
|
+
# Setting up stub methods that raise errors
|
37
|
+
@o.when(:stub).receives(:execute).with(7).raise('baz')
|
38
|
+
|
39
|
+
# Checking recorded method calls
|
40
|
+
# at this stage you need to scan the array of call structs recorded in @o.calls
|
41
|
+
@o.calls[0].should == Orangutan::Call.new(:stub, :execute, [7])
|
42
|
+
|
43
|
+
Questions:
|
44
|
+
|
45
|
+
* Why Orangutan?
|
46
|
+
|
47
|
+
My daughter likes orangutans and I couldn't think of a better name. Both Sumatran and Bornean orangutans are endangered species so even if you intensely dislike this project or its implementation, at least you can be made aware of the plight of these spectacular creatures.
|
48
|
+
|
49
|
+
* Did it have anything to do with Clyde in "Every Which Way But Loose"
|
50
|
+
|
51
|
+
Definately not. What a ridiculous question. I'm appalled.
|
52
|
+
|
53
|
+
* What's Chantek?
|
54
|
+
|
55
|
+
Chantek is a famous orangutan that can solve sudokus and the rubik's cube - http://en.wikipedia.org/wiki/Chantek
|
56
|
+
|
57
|
+
* Why do I not need to register this as a mock framework?
|
58
|
+
|
59
59
|
Most frameworks such as rspec's mocks, mocha and stubba replace methods on existing classes. Because this can't be done with this library - you can only create pure stub objects and setup method behaviours, there's nothing that needs to be undone at the end of a test/example.
|
data/Rakefile
CHANGED
@@ -1,34 +1,34 @@
|
|
1
|
-
desc 'build necessary assemblies for tests'
|
2
|
-
task 'spec/ClassLibrary.dll' => FileList["spec/**/*.cs"] do
|
3
|
-
system "csc /target:library /out:spec\\ClassLibrary.dll spec\\*.cs"
|
4
|
-
end
|
5
|
-
|
6
|
-
task :compile => 'spec/ClassLibrary.dll'
|
7
|
-
|
8
|
-
desc 'run specs with bacon on ironruby'
|
9
|
-
task :bacon => :compile do
|
10
|
-
system "ibacon -Ispec -a"
|
11
|
-
end
|
12
|
-
|
13
|
-
(1..4).each do |i|
|
14
|
-
desc "run spike #{i}"
|
15
|
-
task "spike#{i}" do
|
16
|
-
system "ir -I spec -I spikes spikes\\experiment#{i}.rb"
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
begin
|
21
|
-
require 'jeweler'
|
22
|
-
Jeweler::Tasks.new do |gemspec|
|
23
|
-
gemspec.name = "orangutan"
|
24
|
-
gemspec.summary = "A mock objects library"
|
25
|
-
gemspec.email = "mark@ryall.name"
|
26
|
-
gemspec.homepage = "http://github.com/markryall/orangutan"
|
27
|
-
gemspec.description = "A mocking library that supports creation of ironruby mock objects (in addition to pure ruby ones)"
|
28
|
-
gemspec.files = FileList["[A-Z]*", "{lib,spec}/**/*.{rb,cs}"]
|
29
|
-
gemspec.authors = ["Mark Ryall"]
|
30
|
-
gemspec.rubyforge_project = 'orangutan'
|
31
|
-
end
|
32
|
-
rescue LoadError
|
33
|
-
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
34
|
-
end
|
1
|
+
desc 'build necessary assemblies for tests'
|
2
|
+
task 'spec/ClassLibrary.dll' => FileList["spec/**/*.cs"] do
|
3
|
+
system "csc /target:library /out:spec\\ClassLibrary.dll spec\\clr\\*.cs"
|
4
|
+
end
|
5
|
+
|
6
|
+
task :compile => 'spec/ClassLibrary.dll'
|
7
|
+
|
8
|
+
desc 'run specs with bacon on ironruby'
|
9
|
+
task :bacon => :compile do
|
10
|
+
system "ibacon -Ispec -a"
|
11
|
+
end
|
12
|
+
|
13
|
+
(1..4).each do |i|
|
14
|
+
desc "run spike #{i}"
|
15
|
+
task "spike#{i}" do
|
16
|
+
system "ir -I spec -I spikes spikes\\experiment#{i}.rb"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
require 'jeweler'
|
22
|
+
Jeweler::Tasks.new do |gemspec|
|
23
|
+
gemspec.name = "orangutan"
|
24
|
+
gemspec.summary = "A mock objects library"
|
25
|
+
gemspec.email = "mark@ryall.name"
|
26
|
+
gemspec.homepage = "http://github.com/markryall/orangutan"
|
27
|
+
gemspec.description = "A mocking library that supports creation of ironruby mock objects (in addition to pure ruby ones)"
|
28
|
+
gemspec.files = FileList["[A-Z]*", "{lib,spec}/**/*.{rb,cs}"]
|
29
|
+
gemspec.authors = ["Mark Ryall"]
|
30
|
+
gemspec.rubyforge_project = 'orangutan'
|
31
|
+
end
|
32
|
+
rescue LoadError
|
33
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
34
|
+
end
|
data/VERSION.yml
ADDED
data/lib/orangutan.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module Orangutan
|
2
|
-
end
|
1
|
+
module Orangutan
|
2
|
+
end
|
3
3
|
require 'orangutan/chantek'
|
data/lib/orangutan/chantek.rb
CHANGED
@@ -1,68 +1,50 @@
|
|
1
|
-
require 'orangutan/
|
2
|
-
require 'orangutan/expectation'
|
3
|
-
require 'orangutan/call'
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
def when name
|
53
|
-
expectations_for_name = @expectations[name]
|
54
|
-
@expectations[name] = expectations_for_name = [] unless expectations_for_name
|
55
|
-
expectation = Orangutan::Expectation.new
|
56
|
-
expectations_for_name << expectation
|
57
|
-
expectation
|
58
|
-
end
|
59
|
-
|
60
|
-
def first_match name, method, args
|
61
|
-
expectations_for_name = @expectations[name]
|
62
|
-
if expectations_for_name
|
63
|
-
expectations_for_name.each do |expectation|
|
64
|
-
return expectation if expectation.matches?(method, *args)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
1
|
+
require 'orangutan/stub_base'
|
2
|
+
require 'orangutan/expectation'
|
3
|
+
require 'orangutan/call'
|
4
|
+
|
5
|
+
module Orangutan
|
6
|
+
class Chantek
|
7
|
+
attr_reader :calls
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@calls = []
|
11
|
+
@expectations = {}
|
12
|
+
@stubs= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def stub name, params={}
|
16
|
+
return @stubs[name] if @stubs[name]
|
17
|
+
c = Class.new(StubBase) do
|
18
|
+
if params[:clr_interface]
|
19
|
+
include params[:clr_interface]
|
20
|
+
params[:clr_interface].to_clr_type.get_methods.each do |m_info|
|
21
|
+
snake = m_info.name.scan(/[A-Z][a-z0-9]*/).map {|a|a.downcase}.join('_').to_sym
|
22
|
+
define_method snake do |*args|
|
23
|
+
yield_container, return_container = __react__(snake, args)
|
24
|
+
yield yield_container.value if yield_container && block_given?
|
25
|
+
__return__(method, return_container)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
@stubs[name] = c.new(name, self, params[:recursive])
|
31
|
+
end
|
32
|
+
|
33
|
+
def when name
|
34
|
+
expectations_for_name = @expectations[name]
|
35
|
+
@expectations[name] = expectations_for_name = [] unless expectations_for_name
|
36
|
+
expectation = Orangutan::Expectation.new
|
37
|
+
expectations_for_name << expectation
|
38
|
+
expectation
|
39
|
+
end
|
40
|
+
|
41
|
+
def first_match name, method, args
|
42
|
+
expectations_for_name = @expectations[name]
|
43
|
+
if expectations_for_name
|
44
|
+
expectations_for_name.each do |expectation|
|
45
|
+
return expectation if expectation.matches?(method, *args)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
68
50
|
end
|
@@ -1,3 +1,32 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module Orangutan
|
2
|
+
class CleanSlate
|
3
|
+
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
|
4
|
+
|
5
|
+
def initialize name, parent, recursive
|
6
|
+
@name, @parent, @recursive = name, parent, recursive
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing method, *args
|
10
|
+
yield_container, return_container = __react__(method, args)
|
11
|
+
yield yield_container.value if yield_container && block_given?
|
12
|
+
__return__(method, return_container)
|
13
|
+
end
|
14
|
+
private
|
15
|
+
def __return__ method, return_container
|
16
|
+
return return_container.value if return_container
|
17
|
+
return @parent.stub(:"@name/method") if @recursive
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def __react__ method, args
|
22
|
+
yield_container, return_value = nil, nil
|
23
|
+
@parent.calls << Orangutan::Call.new(@name, method, args)
|
24
|
+
first_match = @parent.first_match(@name, method, args)
|
25
|
+
if first_match
|
26
|
+
first_match.raiser.execute if first_match.raiser
|
27
|
+
yield_container, return_value = first_match.yield_container, first_match.return_value
|
28
|
+
end
|
29
|
+
return yield_container, return_value
|
30
|
+
end
|
31
|
+
end
|
3
32
|
end
|
data/lib/orangutan/container.rb
CHANGED
@@ -1,37 +1,39 @@
|
|
1
|
-
require 'orangutan/raiser'
|
2
|
-
require 'orangutan/container'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
1
|
+
require 'orangutan/raiser'
|
2
|
+
require 'orangutan/container'
|
3
|
+
|
4
|
+
module Orangutan
|
5
|
+
class Expectation
|
6
|
+
attr_reader :return_container, :yield_container, :raiser
|
7
|
+
|
8
|
+
def receives method
|
9
|
+
@method = method
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def with *args
|
14
|
+
@args = args
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def return value
|
19
|
+
@return_container = Container.new value
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def yield value
|
24
|
+
@yield_container = Container.new value
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def raise *args
|
29
|
+
@raiser = Raiser.new args
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
def matches? method, *args
|
34
|
+
return false unless method == @method
|
35
|
+
return true unless @args
|
36
|
+
@args == args
|
37
|
+
end
|
38
|
+
end
|
37
39
|
end
|
data/lib/orangutan/raiser.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
class Orangutan::Raiser
|
2
|
-
def initialize args
|
3
|
-
@args = args
|
4
|
-
end
|
5
|
-
|
6
|
-
def execute
|
7
|
-
puts 'RAISING ' + @args.inspect
|
8
|
-
raise *@args
|
9
|
-
end
|
1
|
+
class Orangutan::Raiser
|
2
|
+
def initialize args
|
3
|
+
@args = args
|
4
|
+
end
|
5
|
+
|
6
|
+
def execute
|
7
|
+
puts 'RAISING ' + @args.inspect
|
8
|
+
raise *@args
|
9
|
+
end
|
10
10
|
end
|