mockery 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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