qed 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,94 @@
1
+ module QED
2
+
3
+ # = Mock
4
+ #
5
+ class Mock < Module
6
+ attr :object
7
+
8
+ def initialize
9
+ super()
10
+ @table = {}
11
+ end
12
+
13
+ #
14
+ def __table__ ; @table ; end
15
+
16
+ # TODO: Ruby has retry, but I need continue!
17
+ def method_missing(meth, *args, &block)
18
+ table = @table
19
+ interface = [meth, args, block_given?]
20
+
21
+ table[interface] = nil
22
+
23
+ define_method(meth) do |*args|
24
+ result = super
25
+ result.assert == table[interface]
26
+ return result
27
+ end
28
+
29
+ Setter.new(table, interface)
30
+ end
31
+
32
+ #
33
+ class Setter
34
+ def initialize(table, interface)
35
+ @table = table
36
+ @interface = interface
37
+ end
38
+
39
+ def ==(result)
40
+ @table[@interface] = result
41
+ end
42
+ end
43
+
44
+ # = Mock::Delegator
45
+ #
46
+ class Delegator
47
+ instance_methods(true).each{ |m| protected m unless m.to_s =~ /^__/ }
48
+
49
+ def initialize(object, mock_module)
50
+ @instance_delegate = object
51
+ extend(mock_module)
52
+ end
53
+
54
+ def method_missing(s, *a, &b)
55
+ @instance_delegate.__send__(s, *a, &b)
56
+ end
57
+ end#class Delegator
58
+
59
+ end#class Mock
60
+
61
+ class ::Object
62
+ # Create mock object.
63
+ def mock(mock_module=nil)
64
+ if mock_module
65
+ Mock::Delegator.new(self, mock_module)
66
+ else
67
+ @_mock ||= Mock.new
68
+ extend(@_mock)
69
+ @_mock
70
+ end
71
+ end
72
+
73
+ # We can't remove the module per-say. So we have to
74
+ # just neuter it. This is a very weak solution, but
75
+ # it will suffice for the moment.
76
+ #--
77
+ # TODO: Use Carats for #unmix.
78
+ #++
79
+ def remove_mock(mock_module=nil)
80
+ mock_module ||= @_mock
81
+ obj = self
82
+ mod = Module.new
83
+ mock_module.__table__.each do |interface, result|
84
+ meth = interface[0]
85
+ mod.module_eval do
86
+ define_method(meth, &obj.class.instance_method(meth).bind(obj))
87
+ end
88
+ end
89
+ extend(mod)
90
+ end
91
+ end#class ::Object
92
+
93
+ end#module Quarry
94
+
@@ -0,0 +1,191 @@
1
+ raise "Spy class is under construction"
2
+
3
+ module QED
4
+
5
+ # = Spy
6
+ #
7
+ # Spy (aka DuckHunter) is a decoy object which is dropped into
8
+ # methods which records the calls made against it --hence a method probe.
9
+ # Of course, it is not perfect --an inescapable matter it seems for any
10
+ # internal probe. There are a couple of issues related to conditionals.
11
+ # Since the method test for a certain condition against the decoy, how
12
+ # is the decoy to respond? Thus ceratin paths in the code may never get
13
+ # exceuted and thus go unmapped. If Ruby had better conditional reflection
14
+ # (i.e. if 'if', 'case', 'unless', 'when', etc. were true methods) then
15
+ # this could be fixed by making the Probe reentrant, mapping out variant
16
+ # true/false/nil replies. The likely insurmountable problem though is the
17
+ # Halting problem. A probe can cause some methods to complete execution.
18
+ # It's pretty rare, but it can happen and little can be done about it (I think).
19
+ #
20
+ # Note, the alternative to this kind of probe is a program that examines, rather
21
+ # then executes, the code. This would circumvent the above problems, but run
22
+ # into difficulties with dynamic evals. It would also be more complicated,
23
+ # but might prove a better means in the future.
24
+ #
25
+ # This script is provided for experimetnal purposes. Please inform the author
26
+ # if you find ways to improve it or put it to an interesting use.
27
+ #
28
+ # == Synopsis
29
+ #
30
+ # require 'methodprobe'
31
+ #
32
+ # def amethod(x)
33
+ # x + 1
34
+ # end
35
+ #
36
+ # p method(:amethod).signiture
37
+ # p method(:amethod).signiture(:class)
38
+ # p method(:amethod).signiture(:pretty)
39
+ #
40
+ # produces
41
+ #
42
+ # [["+"]]
43
+ # [{"+"=>[["Fixnum"]]}]
44
+ # [["+( Fixnum )"]]
45
+ #
46
+ class Spy
47
+
48
+ def self.duckcall
49
+ begin
50
+ yield
51
+ rescue TypeError => e
52
+ self.send(e.message)
53
+ retry
54
+ end
55
+ end
56
+
57
+ attr_reader :ducks, :decoys
58
+
59
+ def initialize
60
+ @ducks, @decoys = {}, {}
61
+ end
62
+
63
+ def initialize_copy(from)
64
+ initialize
65
+ end
66
+
67
+ def method_missing(aSym, *args)
68
+ aSymStr = aSym.to_s
69
+
70
+ # This will happen the first time
71
+ @ducks[aSymStr] ||= [] #unless @ducks[aSymStr]
72
+ @ducks[aSymStr] << args.collect { |a| "#{a.class}" }
73
+
74
+ decoy = self.dup
75
+
76
+ @decoys[aSymStr] ||= [] #unless @decoys[aSymStr]
77
+ @decoys[aSymStr] << decoy
78
+
79
+ # build proxy?
80
+ #begin
81
+ # d = <<-HERE
82
+ # def self.#{aSymStr}(*args)
83
+ # # This will happen the subsequent times
84
+ # @ducks["#{aSymStr}"] << args.collect { |a| #{'"#{a.class}"'} }
85
+ # @ducks["#{aSymStr}"].uniq!
86
+ # decoy = self.dup
87
+ # @decoys["#{aSymStr}"] = [] unless @decoys["#{aSymStr}"]
88
+ # @decoys["#{aSymStr}"] << decoy
89
+ # decoy
90
+ # end
91
+ # HERE
92
+ # instance_eval d
93
+ #rescue SyntaxError
94
+ # puts "This error may be avoidable by returning the failing duck type as the error message."
95
+ # raise
96
+ #end
97
+
98
+ decoy
99
+ end
100
+
101
+ end # class MethodProbe
102
+
103
+ end
104
+
105
+
106
+ class ::Method
107
+
108
+ # Outputs migration information.
109
+ def migration
110
+ parameters = []; argc = self.arity
111
+ if argc > 0
112
+ argc.times { parameters << Quarry::Probe.new }
113
+ Probe.duckcall { self.call(*parameters) }
114
+ elsif argc < 0
115
+ raise "(NYI) method takes unlimited arguments"
116
+ end
117
+ return parameters
118
+ end
119
+ private :migration
120
+
121
+ # Outputs signiture information.
122
+ def signature(detail=nil)
123
+ ds = []
124
+ case detail
125
+ when :complete, :all, :full
126
+ ds = migration
127
+ when :class, :with_class
128
+ migration.each { |dh| ds << dh.ducks }
129
+ when :pp, :pretty, :prettyprint, :pretty_print
130
+ migration.each do |dh|
131
+ responders = []
132
+ dh.ducks.each do |responder, argss|
133
+ argss.each { |args| responders << "#{responder}( #{args.join(',')} )" }
134
+ end
135
+ ds << responders
136
+ end
137
+ else
138
+ migration.each { |dh| ds << dh.ducks.keys }
139
+ end
140
+ return ds
141
+ end
142
+
143
+ end
144
+
145
+
146
+
147
+
148
+
149
+ =begin test
150
+
151
+ require 'test/unit'
152
+
153
+ # " I am a Duck Hunter ! "
154
+
155
+ class TC_MethodProbe < Test::Unit::TestCase
156
+
157
+ # fixture
158
+ def amethod(x)
159
+ x + 1
160
+ end
161
+
162
+ def test_signiture_default
163
+ assert_nothing_raised {
164
+ method(:amethod).signature
165
+ }
166
+ end
167
+
168
+ def test_signiture_with_class
169
+ assert_nothing_raised {
170
+ method(:amethod).signature(:class)
171
+ }
172
+ end
173
+
174
+ def test_signiture_pp
175
+ assert_nothing_raised {
176
+ method(:amethod).signature(:pp)
177
+ }
178
+ end
179
+
180
+ def test_signiture_all
181
+ assert_nothing_raised {
182
+ method(:amethod).signature(:complete)
183
+ }
184
+ end
185
+
186
+ end
187
+
188
+ =end
189
+
190
+ # Copyright (c) 2004,2008 Thomas Sawyer
191
+
@@ -0,0 +1,94 @@
1
+ module QED
2
+
3
+ # = Stub
4
+ #
5
+ class Stub < Module
6
+ attr :object
7
+
8
+ def initialize
9
+ super()
10
+ @table = {}
11
+ end
12
+
13
+ #
14
+ def __table__ ; @table ; end
15
+
16
+ #
17
+ def method_missing(meth, *args, &block)
18
+ table = @table
19
+ interface = [meth, args, block_given?]
20
+
21
+ table[interface] = nil
22
+
23
+ define_method(meth) do |*args|
24
+ table[interface]
25
+ end
26
+
27
+ Setter.new(table, interface)
28
+ end
29
+
30
+ #
31
+ class Setter
32
+ def initialize(table, interface)
33
+ @table = table
34
+ @interface = interface
35
+ end
36
+
37
+ def ==(result)
38
+ @table[@interface] = result
39
+ end
40
+ end#class Setter
41
+
42
+ # = Stub::Delegator
43
+ #
44
+ class Delegator
45
+ instance_methods(true).each{ |m| protected m unless m.to_s =~ /^__/ }
46
+
47
+ def initialize(object, stub_module)
48
+ @instance_delegate = object
49
+ extend(stub_module)
50
+ end
51
+
52
+ def method_missing(s, *a, &b)
53
+ @instance_delegate.__send__(s, *a, &b)
54
+ end
55
+ end
56
+
57
+ end#class Stub
58
+
59
+ class ::Object
60
+
61
+ # Create a new stub.
62
+ def stub(stub_module=nil)
63
+ if stub_module
64
+ Stub::Delegator.new(self, stub_module)
65
+ else
66
+ @_stub ||= Stub.new
67
+ extend(@_stub)
68
+ @_stub
69
+ end
70
+ end
71
+
72
+ # We can't remove the module per-say. So we have to
73
+ # just neuter it. This is a very weak solution, but
74
+ # it will suffice for the moment.
75
+ #--
76
+ # TODO: Use Carats for #unmix.
77
+ #++
78
+ def remove_stub(stub_module=nil)
79
+ stub_module ||= @_stub
80
+ obj = self
81
+ mod = Module.new
82
+ stub_module.__table__.each do |interface, result|
83
+ meth = interface[0]
84
+ mod.module_eval do
85
+ define_method(meth, &obj.class.instance_method(meth).bind(obj))
86
+ end
87
+ end
88
+ extend(mod)
89
+ end
90
+
91
+ end#class ::Object
92
+
93
+ end#module Quarry
94
+
@@ -0,0 +1,60 @@
1
+ module QED
2
+
3
+ require 'qed/assertion'
4
+
5
+ # = Expectation
6
+ #
7
+ # Expectation is an Assertion Functor.
8
+ #
9
+ class Expectation
10
+
11
+ hide = instance_methods.select{ |m| m.to_s !~ /^__/ }
12
+ hide.each{ |m| protected m }
13
+
14
+ private
15
+
16
+ # New Expectation.
17
+ #
18
+ def initialize(delegate, ioc={}) #, backtrace)
19
+ @delegate = delegate
20
+ @negate = ioc[:negate]
21
+ @message = ioc[:message]
22
+ @backtrace = ioc[:backtrace] || caller #[1..-1]
23
+ end
24
+
25
+ # Converts missing method into an Assertion.
26
+ #
27
+ def method_missing(sym, *a, &b)
28
+ test = @delegate.__send__(sym, *a, &b)
29
+
30
+ if (@negate ? test : !test)
31
+ msg = @message || __msg__(sym, *a, &b)
32
+ error = Assertion.new(msg)
33
+ error.set_backtrace(@backtrace)
34
+ raise error
35
+ end
36
+ end
37
+
38
+ # Puts together a suitable error message.
39
+ #
40
+ def __msg__(m, *a, &b)
41
+ if @negate
42
+ "! #{@delegate.inspect} #{m} #{a.collect{|x| x.inspect}.join(',')}"
43
+ else
44
+ "#{@delegate.inspect} #{m} #{a.collect{|x| x.inspect}.join(',')}"
45
+ end
46
+ #self.class.message(m)[@delegate, *a] )
47
+ end
48
+
49
+ # TODO: Ultimately better messages would be nice ?
50
+ #
51
+ #def self.message(op,&block)
52
+ # @message ||= {}
53
+ # block ? @message[op.to_sym] = block : @message[op.to_sym]
54
+ #end
55
+ #
56
+ #message(:==){ |*a| "Expected #{a[0].inspect} to be equal to #{a[1].inspect}" }
57
+ end
58
+
59
+ end
60
+
@@ -0,0 +1,104 @@
1
+ module QED
2
+
3
+ require 'qed/expectation'
4
+
5
+ module Grammar
6
+
7
+ # = Assert Nomenclature
8
+ #
9
+ module Assert
10
+
11
+ # Assert a operational relationship.
12
+ #
13
+ # 4.assert == 3
14
+ #
15
+ # If only a single test argument is given then
16
+ # #assert simple validates that it evalutate to true.
17
+ # An optional message argument can be given in this
18
+ # case which will be used instead of the deafult message.
19
+ #
20
+ # assert(4==3, "not the same thing")
21
+ #
22
+ # In block form, #assert ensures the block evalutes
23
+ # truthfully, i.e. not as nil or false.
24
+ #
25
+ # assert{ 4==3 }
26
+ #
27
+ # If an argument is given with a block, #assert compares
28
+ # the argument to the result of evaluating the block.
29
+ #
30
+ # assert(4){ 3 }
31
+ #
32
+ # #assert compares the expected value and the actual
33
+ # value with regular equality <code>#==</code>.
34
+ #
35
+ def assert(test=Exception, msg=nil, &block)
36
+ if block
37
+ act = block.call
38
+ if test == Exception
39
+ raise Assertion.new(msg, caller) unless act
40
+ else
41
+ yes = (test == act)
42
+ msg = "#{exp}.equate? #{act}" unless msg
43
+ raise Assertion.new(msg, caller) unless yes
44
+ end
45
+ elsif test != Exception
46
+ msg = "failed assertion (no message given)" unless msg
47
+ raise Assertion.new(msg, caller) unless test
48
+ else
49
+ return Expectation.new(self, :backtrace=>caller)
50
+ end
51
+ end
52
+
53
+ # Assert not an operational relationship.
54
+ # Read it as "assert not".
55
+ #
56
+ # 4.assert! == 4
57
+ #
58
+ # See #assert.
59
+ #
60
+ # AUHTOR'S NOTE: This method would not be necessary
61
+ # if Ruby would allow +!=+ to be define as a method,
62
+ # or at least +!+ as a unary method.
63
+ #
64
+ def assert!(test=Exception, msg=nil, &block)
65
+ if block
66
+ act = block.call
67
+ if test == Exception
68
+ raise Assertion.new(msg, caller) if act
69
+ else
70
+ yes = (test == act)
71
+ msg = "#{exp}.equate? #{act}" unless msg
72
+ raise Assertion.new(msg, caller) if yes
73
+ end
74
+ elsif test != Exception
75
+ msg = "failed assertion (no message given)" unless msg
76
+ raise Assertion.new(msg, caller) if test
77
+ else
78
+ return Expectation.new(self, :negate=>true, :backtrace=>caller)
79
+ end
80
+
81
+ if test
82
+ msg = "failed assertion (no message given)" unless msg
83
+ raise Assertion.new(msg, caller) if test
84
+ else
85
+ return Expectation.new(self, :negate=>true, :backtrace=>caller)
86
+ end
87
+ end
88
+
89
+ # Same as #assert!.
90
+ #
91
+ # 4.refute == 4 #=> Assertion Error
92
+ #
93
+ alias_method :refute, :assert!
94
+
95
+ end
96
+
97
+ end
98
+
99
+ class ::Object #:nodoc:
100
+ include Grammar::Assert
101
+ end
102
+
103
+ end
104
+