mockery 0.4.1

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/Rakefile ADDED
@@ -0,0 +1,106 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/gempackagetask'
4
+ require 'rake/packagetask'
5
+ require 'rake/rdoctask'
6
+ require 'rake/testtask'
7
+
8
+ PKG_VERSION = "0.4.1"
9
+
10
+ desc "Default task"
11
+ task :default => [:unit_tests, :acc_tests]
12
+
13
+ desc "Run the unit tests"
14
+ Rake::TestTask.new do |t|
15
+ t.name = 'unit_tests'
16
+ #t.libs << 'tests/unit'
17
+ #t.libs << 'lib'
18
+ t.test_files = FileList['tests/unit/unit_tests.rb']
19
+ t.verbose = true
20
+ end
21
+
22
+ desc "Run the acceptance tests"
23
+ Rake::TestTask.new do |t|
24
+ t.name = 'acc_tests'
25
+ #t.libs << 'tests/acc'
26
+ #t.libs << 'lib'
27
+ t.test_files = FileList['tests/acc/acc_tests.rb']
28
+ t.verbose = true
29
+ end
30
+
31
+ SOURCE_FILES = FileList.new do |fl|
32
+ ["lib", "tests"].each do |dir|
33
+ fl.include "#{dir}/**/*"
34
+ end
35
+ fl.include "Rakefile"
36
+ fl.include "setup.rb"
37
+ fl.exclude( /\bCVS\b/ )
38
+ end
39
+
40
+ desc "Build the Mockery distribution"
41
+ Rake::PackageTask.new("mockery", PKG_VERSION) do |p|
42
+ p.need_tar = true
43
+ p.need_zip = true
44
+ p.package_dir = '../../tmp/mockery-pkg'
45
+ p.package_files = SOURCE_FILES
46
+ end
47
+
48
+ Rake::RDocTask.new do |rd|
49
+ rd.rdoc_files.include('lib/**/*.rb')
50
+ rd.template = 'jamis'
51
+ end
52
+
53
+ desc "Create the 'build' directory"
54
+ task :build_build do
55
+ Dir.mkdir('build') unless File.directory?('build')
56
+ end
57
+
58
+ desc "Build rdoc pages"
59
+ task :build_rdoc => [:rdoc, :build_build] do
60
+ File.rename('html', 'build/rdoc')
61
+ end
62
+
63
+ desc "create missing file rdoc blank.html"
64
+ task :build_blank do
65
+ if ! File.exist?("build/rdoc/blank.html")
66
+ File.open('build/rdoc/blank.html', 'w') do |handle|
67
+ handle.puts('<html/>')
68
+ end
69
+ end
70
+ end
71
+
72
+ GEM_FILES = FileList.new do |fl|
73
+ ['lib', 'tests'].each do |dir|
74
+ fl.include "#{dir}/**/*"
75
+ end
76
+ fl.include "Rakefile"
77
+ fl.exclude( /\bCVS\b/ )
78
+ end
79
+
80
+ gem_spec = Gem::Specification.new do |s|
81
+ s.autorequire = 'mockery/controller'
82
+ s.description = <<EOF
83
+ Mockery dynamically generates mock objects and verifies
84
+ that they are used as expected.
85
+ EOF
86
+ s.email = 'shea@gtsdesign.com'
87
+ s.files = GEM_FILES
88
+ s.has_rdoc = false
89
+ s.homepage = 'http://mockery.rubyforge.org'
90
+ s.name = 'mockery'
91
+ s.requirements << 'none'
92
+ s.rubyforge_project = 'mockery'
93
+ s.summary = "Dynamic mock objects"
94
+ s.version = PKG_VERSION
95
+ end
96
+
97
+ desc "Create a .gem file for Mockery"
98
+ task :gem do
99
+ end
100
+
101
+ Rake::GemPackageTask.new(gem_spec) do |p|
102
+ p.package_dir = '../../tmp/mockery-pkg'
103
+ p.need_zip = true
104
+ p.need_tar = true
105
+ end
106
+
@@ -0,0 +1,40 @@
1
+
2
+ module Mockery
3
+
4
+ class Call
5
+
6
+ attr_accessor :args,
7
+ :caller,
8
+ :method_name,
9
+ :return_value
10
+
11
+ def digest(caller, args)
12
+ @caller = caller
13
+ @method_name = args[0]
14
+ @args = args[1 .. -1]
15
+ end
16
+
17
+ # equality of Call objects is based on equality of
18
+ # the attributes, with the exception of @caller (since
19
+ # the recording is done by a Recorder, not an object
20
+ # of the target class)
21
+ def ==(call)
22
+ return call != nil &&
23
+ call.class == Mockery::Call &&
24
+ @method_name == call.method_name &&
25
+ @args == call.args
26
+ end
27
+
28
+ def to_s
29
+ args_str = (@args == nil) ?
30
+ 'nil' :
31
+ "[#{@args.join(',')}]"
32
+ return "<#{self.class.name}:0x#{object_id.abs.to_s(16)}" +
33
+ " caller=#{@caller}" +
34
+ " method_name=#{@method_name}" +
35
+ " args=#{args_str}" +
36
+ ">"
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,75 @@
1
+
2
+ #
3
+ # Name: Mockery::Controller (lib/mockery/controller.rb)
4
+ #
5
+ # Description:
6
+ #
7
+ # The Controller class coordinates a test.
8
+ #
9
+ #
10
+ # Copyright 2005 Gary Shea
11
+ #
12
+ # Licensed under the Apache License, Version 2.0 (the "License");
13
+ # you may not use this file except in compliance with the License.
14
+ # You may obtain a copy of the License at
15
+ #
16
+ # http://www.apache.org/licenses/LICENSE-2.0
17
+ #
18
+ # Unless required by applicable law or agreed to in writing, software
19
+ # distributed under the License is distributed on an "AS IS" BASIS,
20
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
+ # See the License for the specific language governing permissions and
22
+ # limitations under the License.
23
+ #
24
+
25
+ require 'mockery/call'
26
+ require 'mockery/mock'
27
+ require 'mockery/mock_class_factory'
28
+ require 'mockery/record_control'
29
+ require 'mockery/recorder'
30
+
31
+ module Mockery
32
+
33
+ class Controller
34
+
35
+ def initialize(*klasses)
36
+ @mocks = []
37
+ klasses.each do |klass|
38
+ mock = Mock.new(klass)
39
+ @mocks << mock
40
+ end
41
+ end
42
+
43
+ def record(&block)
44
+ recorders = @mocks.collect { |mock| mock.recorder }
45
+ ctl = RecordControl.new(recorders)
46
+ args = [recorders, ctl].flatten[0 ... block.arity.abs]
47
+ block.call(*args)
48
+ end
49
+
50
+ def try(&block)
51
+ objs = @mocks.collect { |mock| mock.mocked_object }
52
+ block.call(*objs)
53
+ end
54
+
55
+ def validate
56
+ @mocks.each do |mock|
57
+ return false if ! mock.validate
58
+ end
59
+ return true
60
+ end
61
+
62
+ def error_report
63
+ report = ''
64
+ index = 1
65
+ @mocks.each do |mock|
66
+ tmp_index = index
67
+ index = index + 1
68
+ report << "mock #{tmp_index} (class: #{mock.class})\n"
69
+ report << mock.error_report
70
+ end
71
+ return report
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,158 @@
1
+
2
+ #
3
+ # Name: Mockery::Mock (lib/mockery/mock.rb)
4
+ #
5
+ # Description:
6
+ #
7
+ # The Mock class handles configuration, construction,
8
+ # and validation of a single mock object.
9
+ #
10
+ #
11
+ # Copyright 2005 Gary Shea
12
+ #
13
+ # Licensed under the Apache License, Version 2.0 (the "License");
14
+ # you may not use this file except in compliance with the License.
15
+ # You may obtain a copy of the License at
16
+ #
17
+ # http://www.apache.org/licenses/LICENSE-2.0
18
+ #
19
+ # Unless required by applicable law or agreed to in writing, software
20
+ # distributed under the License is distributed on an "AS IS" BASIS,
21
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ # See the License for the specific language governing permissions and
23
+ # limitations under the License.
24
+ #
25
+
26
+ require 'mockery/call'
27
+ require 'mockery/mock_class_factory'
28
+ require 'mockery/recorder'
29
+
30
+ module Mockery
31
+
32
+ class Mock
33
+
34
+ attr_reader :klass, :recorder
35
+
36
+ def initialize(klass)
37
+ @klass = klass
38
+ @recorder = Recorder.new(klass)
39
+ @class_factory = MockClassFactory.new(klass)
40
+ @return_values = nil
41
+ end
42
+
43
+ def process_history
44
+ @recorder.history.each do |call|
45
+ method = call.method_name
46
+ if @return_values.has_key?(method)
47
+ @return_values[method] << call.return_value
48
+ else
49
+ @return_values[method] = [call.return_value]
50
+ end
51
+ end
52
+ end
53
+
54
+ def add_methods
55
+ @return_values.each_key do |method_name|
56
+ @class_factory.add_method(method_name)
57
+ end
58
+ end
59
+
60
+ def mocked_object
61
+ @return_values = Hash.new
62
+ process_history
63
+ add_methods
64
+ @class_factory.create_initialize(@return_values.keys)
65
+ @instance = @class_factory.create_instance(@return_values)
66
+ return @instance
67
+ end
68
+
69
+ def validate
70
+ return @recorder.history == @instance.instance_history
71
+ end
72
+
73
+ def error_report
74
+
75
+ report = ''
76
+
77
+ recorded = @recorder.history
78
+ actual = @instance.instance_history
79
+ if recorded.size > actual.size
80
+ max_idx = @recorder.history.size
81
+ else
82
+ max_idx = @instance.instance_history.size
83
+ end
84
+
85
+ (0 ... max_idx).each do |idx|
86
+ if idx >= recorded.size
87
+ report << "unexpected: #{describe_call(actual[idx])}\n"
88
+ elsif idx >= actual.size
89
+ report << "expected: #{describe_call(recorded[idx])}\n"
90
+ elsif recorded[idx] != actual[idx]
91
+ report << "expected\n#{describe_call(recorded[idx])}\n"
92
+ report << "but got\n#{describe_call(actual[idx])}\n"
93
+ end
94
+ end
95
+
96
+ return report
97
+
98
+ end
99
+
100
+ def describe_call(call)
101
+ return '<' + call.caller.class.name + '>.' +
102
+ call.method_name.to_s + '(' +
103
+ call.args[0 .. -1].collect{|arg| expanding_describe_value(arg)}.join(', ') +
104
+ ')'
105
+ end
106
+
107
+ def expanding_describe_value(value)
108
+ dscr = describe_simple_value(value)
109
+ if dscr == nil
110
+ dscr = "<#{value.class.name}:#{object_id_to_s(value)} "
111
+ dscr << value.instance_variables.collect { |var_name|
112
+ var_dscr = ''
113
+ var_dscr << "#{var_name}="
114
+ var_value = value.instance_variable_get(eval(":#{var_name}"))
115
+ var_dscr << non_expanding_describe_value(var_value)
116
+ var_dscr
117
+ }.join(', ')
118
+ dscr << '>'
119
+ end
120
+ return dscr
121
+ end
122
+
123
+ def non_expanding_describe_value(value)
124
+ dscr = describe_simple_value(value)
125
+ if dscr == nil
126
+ dscr = '<' + value.class.name + object_id_to_s(value) + '>'
127
+ end
128
+ return dscr
129
+ end
130
+
131
+ def describe_simple_value(value)
132
+ if value == nil
133
+ return 'nil'
134
+ elsif value.class == Fixnum
135
+ return value.to_s
136
+ elsif value.class == Symbol
137
+ return ':' + value.to_s
138
+ elsif value.class == String
139
+ return "'" + value + "'"
140
+ elsif value.class == Array
141
+ return '[' + value.join(', ') + ']'
142
+ elsif value.class == Hash
143
+ dscrs = []
144
+ value.each { |key, value|
145
+ dscrs << "#{key} => #{value}"
146
+ }
147
+ return '{' + dscrs.join(',') + '}'
148
+ else
149
+ return nil
150
+ end
151
+ end
152
+
153
+ def object_id_to_s(obj)
154
+ return ':0x' + obj.object_id.abs.to_s(16)
155
+ end
156
+
157
+ end
158
+ end
@@ -0,0 +1,54 @@
1
+
2
+ module Mockery
3
+
4
+ class MockClassFactory
5
+
6
+ def initialize(user_klass)
7
+
8
+ klass = Class.new(user_klass)
9
+ klass.class_eval {
10
+ attr_reader :instance_history
11
+ }
12
+
13
+ @klass = klass
14
+ @return_values = Hash.new
15
+
16
+ end
17
+
18
+ def add_method(method_name)
19
+ var_name = "@___#{method_name}_rv"
20
+ def_string = "@klass.class_eval {\n" +
21
+ " def #{method_name}(*args)\n" +
22
+ " call = Mockery::Call.new\n" +
23
+ " call.caller = self\n" +
24
+ " call.method_name = :#{method_name}\n" +
25
+ " call.args = args\n" +
26
+ " @instance_history << call\n" +
27
+ " return #{var_name}.size == 0 ? nil : #{var_name}.shift\n" +
28
+ " end\n" +
29
+ "}\n"
30
+ eval(def_string)
31
+ end
32
+
33
+ def create_initialize(method_names)
34
+ def_string = "@klass.class_eval {\n" +
35
+ " def initialize(*args, &block)\n" +
36
+ " @instance_history = []\n"
37
+ method_names.each do |method, values|
38
+ def_string << " @__#{method.to_s}_rv = nil\n"
39
+ end
40
+ def_string << (" end\n" + "}\n")
41
+ eval(def_string)
42
+ end
43
+
44
+ def create_instance(return_values)
45
+ mock = @klass.new
46
+ return_values.each do |method, value|
47
+ mock.instance_variable_set(eval(":@___#{method}_rv"), value)
48
+ end
49
+ return mock
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,54 @@
1
+
2
+ #
3
+ # Name: Mockery::RecordControl (lib/mockery/record_control.rb)
4
+ #
5
+ # Description:
6
+ #
7
+ # The RecordControl class enables recording to be 'paused'
8
+ # inside a 'try' block.
9
+ #
10
+ #
11
+ # Copyright 2005 Gary Shea
12
+ #
13
+ # Licensed under the Apache License, Version 2.0 (the "License");
14
+ # you may not use this file except in compliance with the License.
15
+ # You may obtain a copy of the License at
16
+ #
17
+ # http://www.apache.org/licenses/LICENSE-2.0
18
+ #
19
+ # Unless required by applicable law or agreed to in writing, software
20
+ # distributed under the License is distributed on an "AS IS" BASIS,
21
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ # See the License for the specific language governing permissions and
23
+ # limitations under the License.
24
+ #
25
+
26
+ module Mockery
27
+
28
+ class RecordControl
29
+
30
+ def initialize(mocks)
31
+ @mocks = mocks
32
+ end
33
+
34
+ def pause(&block)
35
+ self.stop
36
+ block.call
37
+ self.start
38
+ end
39
+
40
+ def stop
41
+ @mocks.each do |mock|
42
+ mock.__record_state = false
43
+ end
44
+ end
45
+
46
+ def start
47
+ @mocks.each do |mock|
48
+ mock.__record_state = true
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ end