pretentious 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +164 -0
- data/Rakefile +1 -0
- data/bin/ddtgen +72 -0
- data/example.rb +93 -0
- data/lib/pretentious.rb +370 -0
- data/lib/pretentious/deconstructor.rb +292 -0
- data/lib/pretentious/rspec_generator.rb +215 -0
- data/lib/pretentious/version.rb +3 -0
- data/pretentious.gemspec +23 -0
- data/run_test.sh +6 -0
- data/spec/fibonacci_spec.rb +66 -0
- data/spec/m_d5_spec.rb +13 -0
- data/spec/spec_helper.rb +63 -0
- data/spec/test_class1_spec.rb +42 -0
- data/spec/test_class2_spec.rb +25 -0
- data/spec/test_class3_spec.rb +51 -0
- data/test/test_generator.rb +105 -0
- data/test_class3_spec.rb +1 -0
- metadata +117 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4eac89f08c915484d2749c73f703b6d8654f5e94
|
4
|
+
data.tar.gz: abf3901c3235fa2ee6d266cbb5cd019f22e83c2a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a0f020ba8a6903e3bd55682c58e42a63c3ffddb3db7e99bada136aae4ecc2252a6ddd5a45ebe02f82e23f287aa8062f6a18b32d85a88c59af4558e782ac08d50
|
7
|
+
data.tar.gz: 4c4c7d237a30ec08800be2d09fa363f6ced13a2cfaea11651c41508b1950e499f7077d759a194c76f2262bfb784825c2605b20254d146e7ed5e1792843330357
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Joseph Emmanuel Dayo
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# Ruby::Pretentious
|
2
|
+
|
3
|
+
Do you have a pretentious boss or dev lead that pushes you to embrace bdd/tdd but for reasons hate it or them?
|
4
|
+
here is a gem to deal with that. Now you CAN write code first and then GENERATE tests later!! Yes you heard that
|
5
|
+
right! This gem allows you to write your code first and then automatically generate tests using the code
|
6
|
+
you've written!
|
7
|
+
|
8
|
+
On a serious note, this gem allows you to generate tests template much better than those generated by default
|
9
|
+
for various frameworks.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'pretentious'
|
17
|
+
```
|
18
|
+
|
19
|
+
And then execute:
|
20
|
+
|
21
|
+
$ bundle
|
22
|
+
|
23
|
+
Or install it yourself as:
|
24
|
+
|
25
|
+
$ gem install pretentious
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
First Create an example file (etc. example.rb) and define the classes that you want to test, if the class is
|
30
|
+
already defined elsewhere just require them. Below is an example:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
class Fibonacci
|
34
|
+
|
35
|
+
def fib(n)
|
36
|
+
return 0 if (n == 0)
|
37
|
+
return 1 if (n == 1)
|
38
|
+
return 1 if (n == 2)
|
39
|
+
return fib(n - 1) + fib(n - 2)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.say_hello
|
43
|
+
"hello"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
Inside a Pretentious.spec_for(...) block. Just write boring code that calls the methods of your class like
|
50
|
+
how you'd normally use them. Finally Specify the classes that you want to test:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
class Fibonacci
|
54
|
+
|
55
|
+
def fib(n)
|
56
|
+
return 0 if (n == 0)
|
57
|
+
return 1 if (n == 1)
|
58
|
+
return 1 if (n == 2)
|
59
|
+
return fib(n - 1) + fib(n - 2)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.say_hello
|
63
|
+
"hello"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
Pretentious.spec_for(Fibonacci) do
|
69
|
+
|
70
|
+
|
71
|
+
instance = Fibonacci.new
|
72
|
+
|
73
|
+
(1..10).each do |n|
|
74
|
+
instance.fib(n)
|
75
|
+
end
|
76
|
+
|
77
|
+
Fibonacci.say_hello
|
78
|
+
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
Save your file and then switch to the terminal to invoke:
|
83
|
+
|
84
|
+
ddtgen example.rb
|
85
|
+
|
86
|
+
This will automatically generate rspec tests for Fibonacci under spec of the current working directory.
|
87
|
+
|
88
|
+
you can invoke spec at this point, but the tests will fail. Instead you should edit spec/spec_helper.rb and
|
89
|
+
put the necessary requires and definitions there.
|
90
|
+
|
91
|
+
For this example place the following into spec_helper.rb:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
#inside spec_helper.rb
|
95
|
+
|
96
|
+
class Fibonacci
|
97
|
+
|
98
|
+
def fib(n)
|
99
|
+
return 0 if (n == 0)
|
100
|
+
return 1 if (n == 1)
|
101
|
+
return 1 if (n == 2)
|
102
|
+
return fib(n - 1) + fib(n - 2)
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.say_hello
|
106
|
+
"hello"
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
You can also try this out with build in libraries like MD5 for example
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
#example.rb
|
116
|
+
|
117
|
+
Pretentious.spec_for(Digest::MD5) do
|
118
|
+
sample = "This is the digest"
|
119
|
+
Digest::MD5.hexdigest(sample)
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
You should get something like:
|
124
|
+
|
125
|
+
```ruby
|
126
|
+
require 'spec_helper'
|
127
|
+
|
128
|
+
RSpec.describe Digest::MD5 do
|
129
|
+
|
130
|
+
it 'should pass current expectations' do
|
131
|
+
|
132
|
+
sample = "This is the digest"
|
133
|
+
|
134
|
+
# Digest::MD5::hexdigest when passed "This is the digest" should return 9f12248dcddeda976611d192efaaf72a
|
135
|
+
expect( Digest::MD5.hexdigest(sample) ).to eq("9f12248dcddeda976611d192efaaf72a")
|
136
|
+
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
Only RSpec is support at this point. But other testing frameworks should be trivial to add support to.
|
142
|
+
|
143
|
+
## Limitations
|
144
|
+
|
145
|
+
Computers are bad at mind reading (for now) and they don't really know your expectation of "correctness", as such
|
146
|
+
it assumes your code is correct and can only use equality based matchers. It can also only reliably match
|
147
|
+
primitive data types and hashs and arrays to degree. More complex expectations are unfortunately left for the human to resolve.
|
148
|
+
|
149
|
+
Also do note that it tries its best to determine how your fixtures are created, as well as the types
|
150
|
+
of your parameters and does so by figuring out the components that your object needs. Failure can happen during this process.
|
151
|
+
|
152
|
+
Finally, Limit this gem for test environments only.
|
153
|
+
|
154
|
+
## Bugs
|
155
|
+
|
156
|
+
This is the first iteration and a lot of broken things could happen
|
157
|
+
|
158
|
+
## Contributing
|
159
|
+
|
160
|
+
1. Fork it (https://github.com/jedld/pretentious.git)
|
161
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
162
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
163
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
164
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/ddtgen
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pretentious'
|
4
|
+
require 'optparse'
|
5
|
+
require 'ripper'
|
6
|
+
require "readline"
|
7
|
+
require 'json'
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
$test_framework = :rspec
|
11
|
+
$output_folder = 'spec'
|
12
|
+
|
13
|
+
# ddtgen example.rb -t rspec -o rspec/
|
14
|
+
options = OptionParser.new do |o|
|
15
|
+
o.banner =
|
16
|
+
"Usage: ddtgen FILENAME [options] # Generates tests using the specified example file\n"
|
17
|
+
o.separator ""
|
18
|
+
o.separator "options:"
|
19
|
+
o.on('-t','--test-type','test framework to use (default :rspec)') { |b| $test_framework = b.to_sym}
|
20
|
+
o.on('-o','--output-dir','folder to place the files in') { |b| $output_folder = b}
|
21
|
+
o.parse!
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
filename = ARGV[0]
|
26
|
+
|
27
|
+
if filename.nil?
|
28
|
+
puts "an example file is required."
|
29
|
+
puts options
|
30
|
+
exit(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
example_body = ""
|
34
|
+
|
35
|
+
index = 0
|
36
|
+
File.open(filename, "r") do |f|
|
37
|
+
f.each_line do |line|
|
38
|
+
example_body << "#{line}\n"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
eval(example_body)
|
43
|
+
|
44
|
+
#collect results
|
45
|
+
|
46
|
+
FileUtils.mkdir_p $output_folder
|
47
|
+
|
48
|
+
module DdtUtils
|
49
|
+
def self.to_underscore(str)
|
50
|
+
str.gsub(/(.)([A-Z])/,'\1_\2').downcase
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
Pretentious.last_results.each { |klass, result|
|
55
|
+
|
56
|
+
klass_name_parts = klass.name.split('::')
|
57
|
+
last_part = klass_name_parts.pop
|
58
|
+
|
59
|
+
filename = File.join($output_folder,"#{DdtUtils.to_underscore(last_part)}_spec.rb")
|
60
|
+
File.open(filename, 'w') {
|
61
|
+
|f| f.write(result)
|
62
|
+
}
|
63
|
+
puts "#{filename}"
|
64
|
+
}
|
65
|
+
|
66
|
+
filename = File.join($output_folder,"spec_helper.rb")
|
67
|
+
unless File.exists?(filename)
|
68
|
+
File.open(filename, 'w') {
|
69
|
+
|f| f.write("#Place your requires here")
|
70
|
+
}
|
71
|
+
puts "#{filename}"
|
72
|
+
end
|
data/example.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
class Fibonacci
|
4
|
+
|
5
|
+
def fib(n)
|
6
|
+
return 0 if (n == 0)
|
7
|
+
return 1 if (n == 1)
|
8
|
+
return 1 if (n == 2)
|
9
|
+
return fib(n - 1) + fib(n - 2)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.say_hello
|
13
|
+
"hello"
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class TestClass1
|
19
|
+
|
20
|
+
def initialize(message)
|
21
|
+
@message = message
|
22
|
+
end
|
23
|
+
|
24
|
+
def print_message
|
25
|
+
puts @message
|
26
|
+
end
|
27
|
+
|
28
|
+
def something_is_wrong
|
29
|
+
raise StandardError.new
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class TestClass2
|
34
|
+
def initialize(message)
|
35
|
+
@message = {message: message}
|
36
|
+
end
|
37
|
+
|
38
|
+
def print_message
|
39
|
+
puts @message[:message]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class TestClass3
|
44
|
+
|
45
|
+
def initialize(testclass1, testclass2)
|
46
|
+
@class1 = testclass1
|
47
|
+
@class2 = testclass2
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_hash
|
51
|
+
{hello: "world", message: {another: :hash}}
|
52
|
+
end
|
53
|
+
|
54
|
+
def show_messages
|
55
|
+
@class1.print_message
|
56
|
+
@class2.print_message
|
57
|
+
"awesome!!!"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
Pretentious.spec_for(Fibonacci) do
|
63
|
+
|
64
|
+
|
65
|
+
instance = Fibonacci.new
|
66
|
+
|
67
|
+
(1..10).each do |n|
|
68
|
+
instance.fib(n)
|
69
|
+
end
|
70
|
+
|
71
|
+
Fibonacci.say_hello
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
Pretentious.spec_for(TestClass1, TestClass2, TestClass3) do
|
76
|
+
|
77
|
+
another_object = TestClass1.new("test")
|
78
|
+
test_class_one = TestClass1.new({hello: "world", test: another_object, arr_1: [1,2,3,4,5, another_object],
|
79
|
+
sub_hash: {yes: true, obj: another_object}})
|
80
|
+
test_class_two = TestClass2.new("This is message 2")
|
81
|
+
|
82
|
+
class_to_test = TestClass3.new(test_class_one, test_class_two)
|
83
|
+
class_to_test.show_messages
|
84
|
+
|
85
|
+
class_to_test = TestClass3.new(test_class_one, test_class_two)
|
86
|
+
class_to_test.show_messages
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
Pretentious.spec_for(Digest::MD5) do
|
91
|
+
sample = "This is the digest"
|
92
|
+
Digest::MD5.hexdigest(sample)
|
93
|
+
end
|
data/lib/pretentious.rb
ADDED
@@ -0,0 +1,370 @@
|
|
1
|
+
require "pretentious/version"
|
2
|
+
require "pretentious/rspec_generator"
|
3
|
+
require 'binding_of_caller'
|
4
|
+
require 'pretentious/deconstructor'
|
5
|
+
|
6
|
+
module Pretentious
|
7
|
+
|
8
|
+
def self.spec_for(*klasses, &block)
|
9
|
+
@results = @results || {}
|
10
|
+
@results.merge!(Pretentious::Generator.generate_for(*klasses, &block))
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.clear_results
|
14
|
+
@results = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.last_results
|
18
|
+
@results
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.value_ize(value, let_variables, declared_names)
|
22
|
+
if (value.kind_of? String)
|
23
|
+
"#{value.dump}"
|
24
|
+
elsif (value.is_a? Symbol)
|
25
|
+
":#{value.to_s}"
|
26
|
+
elsif (value.is_a? Hash)
|
27
|
+
Pretentious::Deconstructor.pick_name(let_variables, value.object_id, declared_names)
|
28
|
+
else
|
29
|
+
"#{value.to_s}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.watch(&block)
|
34
|
+
Pretentious::Generator.watch_new_instances
|
35
|
+
block.call
|
36
|
+
Pretentious::Generator.unwatch_new_instances
|
37
|
+
end
|
38
|
+
|
39
|
+
class Generator
|
40
|
+
|
41
|
+
def self.impostor_for(module_space, klass)
|
42
|
+
newStandInKlass = Class.new()
|
43
|
+
name = klass.name
|
44
|
+
module_space.const_set "#{name.split('::').last}Impostor", newStandInKlass
|
45
|
+
|
46
|
+
common_snippet = "
|
47
|
+
@_method_calls = @_method_calls || []
|
48
|
+
@_method_calls_by_method = @_method_calls_by_method || {}
|
49
|
+
@_methods_for_test = @_methods_for_test || []
|
50
|
+
@_let_variables = @_let_variables || {}
|
51
|
+
|
52
|
+
caller_context = binding.of_caller(1)
|
53
|
+
#puts \"local_variables\"
|
54
|
+
v_locals = caller_context.eval('local_variables')
|
55
|
+
|
56
|
+
v_locals.each { |v|
|
57
|
+
variable_value = caller_context.eval(\"\#{v.to_s}\")
|
58
|
+
@_let_variables[variable_value.object_id] = v
|
59
|
+
}
|
60
|
+
|
61
|
+
info_block = {}
|
62
|
+
info_block[:method] = method_sym
|
63
|
+
info_block[:params] = arguments
|
64
|
+
info_block[:names] = @_instance.method(method_sym).parameters
|
65
|
+
|
66
|
+
begin
|
67
|
+
if (@_instance.methods.include? method_sym)
|
68
|
+
result = @_instance.send(method_sym, *arguments, &block)
|
69
|
+
else
|
70
|
+
result = @_instance.send(:method_missing, method_sym, *arguments, &block)
|
71
|
+
end
|
72
|
+
info_block[:result] = result
|
73
|
+
rescue Exception=>e
|
74
|
+
info_block[:result] = e
|
75
|
+
rescue StandardError=>e
|
76
|
+
info_block[:result] = e
|
77
|
+
end
|
78
|
+
|
79
|
+
@_method_calls << info_block
|
80
|
+
|
81
|
+
if (@_method_calls_by_method[method_sym].nil?)
|
82
|
+
@_method_calls_by_method[method_sym] = []
|
83
|
+
end
|
84
|
+
|
85
|
+
@_method_calls_by_method[method_sym] << info_block
|
86
|
+
raise e if (e.kind_of? Exception)
|
87
|
+
result"
|
88
|
+
|
89
|
+
newStandInKlass.class_eval("
|
90
|
+
def setup_instance(*args, &block)
|
91
|
+
@_instance = #{klass.name}_ddt.new(*args, &block)
|
92
|
+
end
|
93
|
+
")
|
94
|
+
|
95
|
+
newStandInKlass.class_exec do
|
96
|
+
def initialize(*args, &block)
|
97
|
+
|
98
|
+
@_instance_init = {params: [], block: nil}
|
99
|
+
|
100
|
+
@_instance_init[:params] = args
|
101
|
+
@_instance_init[:block] = block
|
102
|
+
|
103
|
+
setup_instance(*args, &block)
|
104
|
+
|
105
|
+
|
106
|
+
@_method_calls = []
|
107
|
+
@_method_calls_by_method = {}
|
108
|
+
@_methods_for_test = []
|
109
|
+
@_let_variables = {}
|
110
|
+
|
111
|
+
|
112
|
+
@_init_let_variables = {}
|
113
|
+
|
114
|
+
caller_context = binding.of_caller(2)
|
115
|
+
v_locals = caller_context.eval('local_variables')
|
116
|
+
|
117
|
+
v_locals.each { |v|
|
118
|
+
variable_value = caller_context.eval("#{v.to_s}")
|
119
|
+
@_init_let_variables[variable_value.object_id] = v
|
120
|
+
}
|
121
|
+
|
122
|
+
self.class._add_instances(self)
|
123
|
+
end
|
124
|
+
|
125
|
+
def _init_arguments
|
126
|
+
@_instance_init
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_class
|
130
|
+
@_instance.class
|
131
|
+
end
|
132
|
+
|
133
|
+
def include_for_tests(method_list = [])
|
134
|
+
@_methods_for_test = @_methods_for_test + method_list
|
135
|
+
end
|
136
|
+
|
137
|
+
def let_variables
|
138
|
+
@_let_variables
|
139
|
+
end
|
140
|
+
|
141
|
+
def init_let_variables
|
142
|
+
@_init_let_variables
|
143
|
+
end
|
144
|
+
|
145
|
+
def method_calls_by_method
|
146
|
+
@_method_calls_by_method
|
147
|
+
end
|
148
|
+
|
149
|
+
def method_calls
|
150
|
+
@_method_calls
|
151
|
+
end
|
152
|
+
|
153
|
+
def to_s
|
154
|
+
@_instance.to_s
|
155
|
+
end
|
156
|
+
|
157
|
+
def ==(other)
|
158
|
+
@_instance==other
|
159
|
+
end
|
160
|
+
|
161
|
+
def kind_of?(klass)
|
162
|
+
@_instance.kind_of? klass
|
163
|
+
end
|
164
|
+
|
165
|
+
def methods
|
166
|
+
@_instance.methods + [:method_calls]
|
167
|
+
end
|
168
|
+
|
169
|
+
def freeze
|
170
|
+
@_instance.freeze
|
171
|
+
end
|
172
|
+
|
173
|
+
def hash
|
174
|
+
@instance.hash
|
175
|
+
end
|
176
|
+
|
177
|
+
def inspect
|
178
|
+
@_instance.inspect
|
179
|
+
end
|
180
|
+
|
181
|
+
def is_a?(something)
|
182
|
+
@_instance.is_a? something
|
183
|
+
end
|
184
|
+
|
185
|
+
class << self
|
186
|
+
def _add_instances(instance)
|
187
|
+
@_instances = @_instances || []
|
188
|
+
@_instances << instance unless @_instances.include? instance
|
189
|
+
end
|
190
|
+
|
191
|
+
def let_variables
|
192
|
+
@_let_variables
|
193
|
+
end
|
194
|
+
|
195
|
+
def method_calls_by_method
|
196
|
+
@_method_calls_by_method
|
197
|
+
end
|
198
|
+
|
199
|
+
def method_calls
|
200
|
+
@_method_calls
|
201
|
+
end
|
202
|
+
|
203
|
+
def _add_instances(instance)
|
204
|
+
@_instances = @_instances || []
|
205
|
+
@_instances << instance unless @_instances.include? instance
|
206
|
+
end
|
207
|
+
|
208
|
+
def _instances
|
209
|
+
@_instances
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
newStandInKlass.class_eval("
|
217
|
+
def method_missing(method_sym, *arguments, &block)
|
218
|
+
#puts \"\#{method_sym} \#{arguments}\"
|
219
|
+
#{common_snippet}
|
220
|
+
end
|
221
|
+
|
222
|
+
class << self
|
223
|
+
|
224
|
+
def test_class
|
225
|
+
#{klass.name}
|
226
|
+
end
|
227
|
+
|
228
|
+
def method_missing(method_sym, *arguments, &block)
|
229
|
+
#puts \"method \#{method_sym.to_s}\"
|
230
|
+
_add_instances(self)
|
231
|
+
@_instance = #{klass.name}_ddt
|
232
|
+
#{common_snippet}
|
233
|
+
end
|
234
|
+
end
|
235
|
+
")
|
236
|
+
|
237
|
+
newStandInKlass
|
238
|
+
end
|
239
|
+
|
240
|
+
def self.generate_for(*klasses_or_instances, &block)
|
241
|
+
all_results = {}
|
242
|
+
klasses = []
|
243
|
+
|
244
|
+
klasses_or_instances.each { |klass_or_instance|
|
245
|
+
klass = klass_or_instance.class == Class ? klass_or_instance : klass_or_instance.class
|
246
|
+
|
247
|
+
|
248
|
+
klass_name_parts = klass.name.split('::')
|
249
|
+
last_part = klass_name_parts.pop
|
250
|
+
|
251
|
+
module_space = Object
|
252
|
+
|
253
|
+
if (klass_name_parts.size > 0)
|
254
|
+
klass_name_parts.each do |part|
|
255
|
+
module_space = module_space.const_get(part)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
newStandInKlass = impostor_for module_space, klass
|
260
|
+
|
261
|
+
module_space.send(:remove_const,last_part.to_sym)
|
262
|
+
module_space.const_set("#{last_part}_ddt", klass)
|
263
|
+
module_space.const_set("#{last_part}", newStandInKlass)
|
264
|
+
|
265
|
+
klasses << [module_space, klass, last_part, newStandInKlass]
|
266
|
+
}
|
267
|
+
|
268
|
+
watch_new_instances
|
269
|
+
|
270
|
+
block.call
|
271
|
+
|
272
|
+
unwatch_new_instances
|
273
|
+
|
274
|
+
klasses.each { |module_space, klass, last_part, newStandInKlass|
|
275
|
+
|
276
|
+
module_space.send(:remove_const,"#{last_part}Impostor".to_sym)
|
277
|
+
module_space.send(:remove_const,"#{last_part}".to_sym)
|
278
|
+
module_space.const_set(last_part, klass)
|
279
|
+
module_space.send(:remove_const,"#{last_part}_ddt".to_sym)
|
280
|
+
|
281
|
+
test_generator = Pretentious::RspecGenerator.new
|
282
|
+
test_generator.begin_spec(klass)
|
283
|
+
num = 1
|
284
|
+
|
285
|
+
newStandInKlass._instances.each do |instance|
|
286
|
+
test_generator.generate(instance, num)
|
287
|
+
num+=1
|
288
|
+
end
|
289
|
+
|
290
|
+
test_generator.end_spec
|
291
|
+
|
292
|
+
result = all_results[klass]
|
293
|
+
if result.nil?
|
294
|
+
all_results[klass] = []
|
295
|
+
end
|
296
|
+
|
297
|
+
all_results[klass] = test_generator.output
|
298
|
+
|
299
|
+
}
|
300
|
+
|
301
|
+
all_results
|
302
|
+
end
|
303
|
+
|
304
|
+
def self.watch_new_instances
|
305
|
+
Object.class_eval do
|
306
|
+
def _get_init_arguments
|
307
|
+
@_init_arguments
|
308
|
+
end
|
309
|
+
|
310
|
+
def _set_init_arguments(*args, &block)
|
311
|
+
@_init_arguments = @_init_arguments || {}
|
312
|
+
@_init_arguments[:params] = args
|
313
|
+
@_init_arguments[:block] = block
|
314
|
+
@_variable_names= {}
|
315
|
+
|
316
|
+
index = 0
|
317
|
+
params = method(:initialize).parameters
|
318
|
+
|
319
|
+
args.each do |arg|
|
320
|
+
p = params[index]
|
321
|
+
if p.size > 1
|
322
|
+
@_variable_names[arg.object_id] = p[1].to_s
|
323
|
+
end
|
324
|
+
index+=1
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
328
|
+
|
329
|
+
def _variable_map
|
330
|
+
@_variable_names
|
331
|
+
end
|
332
|
+
|
333
|
+
def _deconstruct
|
334
|
+
Pretentious::Deconstructor.new().deconstruct(self)
|
335
|
+
end
|
336
|
+
|
337
|
+
def _deconstruct_to_ruby(indentation = 0)
|
338
|
+
Pretentious::Deconstructor.new().deconstruct_to_ruby(indentation, _variable_map, self)
|
339
|
+
end
|
340
|
+
|
341
|
+
end
|
342
|
+
|
343
|
+
Class.class_eval do
|
344
|
+
alias_method :_ddt_old_new, :new
|
345
|
+
|
346
|
+
def new(*args, &block)
|
347
|
+
instance = _ddt_old_new(*args, &block)
|
348
|
+
instance._set_init_arguments(*args, &block)
|
349
|
+
instance
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
def self.clean_watches
|
355
|
+
Class.class_eval do
|
356
|
+
remove_method :new
|
357
|
+
alias_method :new, :_ddt_old_new
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def self.unwatch_new_instances
|
362
|
+
Class.class_eval do
|
363
|
+
remove_method :new
|
364
|
+
alias_method :new, :_ddt_old_new
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
end
|
369
|
+
|
370
|
+
end
|