pretentious 0.1.12 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +45 -0
- data/README.md +67 -44
- data/bin/pretentious +77 -17
- data/lib/pretentious.rb +7 -0
- data/lib/pretentious/deconstructor.rb +1 -3
- data/lib/pretentious/generator.rb +87 -21
- data/lib/pretentious/lazy_trigger.rb +85 -0
- data/lib/pretentious/minitest_generator.rb +4 -0
- data/lib/pretentious/rspec_generator.rb +6 -0
- data/lib/pretentious/utils/file_writer.rb +1 -1
- data/lib/pretentious/version.rb +1 -1
- data/pretentious.yml +8 -0
- data/run_test.sh +1 -1
- data/sample.rb +13 -0
- data/spec/generated/meme_spec.rb +18 -0
- data/spec/generated/test_class1_spec.rb +1 -1
- data/spec/generator_spec.rb +5 -13
- data/spec/lazy_trigger_spec.rb +35 -0
- data/spec/prententious_spec.rb +6 -0
- data/test/generated/test_test_class1.rb +1 -1
- data/test_classes.rb +1 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0ad59d1020d7aa1cf6df1664080617dadb649d6
|
4
|
+
data.tar.gz: a1e0a3e083db31a8ddadee40312f4bc564e75bf1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eca3b03454ca118c1b43f5812edbe06ac59ea474357dbb2c79ed5406529ccae21633270070cce17f169707ce4dc1ad7aa90143f9e9a0fea443f7df868f72cc72
|
7
|
+
data.tar.gz: f791eb14e868c0c0cc181a516ce11a4898a0a92a6b99301b301844f471a5dbf1a87963f11ad306f0e8e5054ce8e7485461fa928a99aa688d90e5a33d0fc69eb9
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- '*.gemspec'
|
4
|
+
- 'Gemfile'
|
5
|
+
- 'bin/**/*'
|
6
|
+
- 'db/migrate/**/*'
|
7
|
+
- 'db/schema.rb'
|
8
|
+
- 'log/**/*'
|
9
|
+
- 'tmp/**/*'
|
10
|
+
- 'vendor/**/*'
|
11
|
+
DisplayCopNames: true
|
12
|
+
RunRailsCops: true
|
13
|
+
|
14
|
+
Metrics/LineLength:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Metrics/MethodLength:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Metrics/ModuleLength:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/Documentation:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/ExtraSpacing:
|
27
|
+
AllowForAlignment: true
|
28
|
+
|
29
|
+
Style/MultilineOperationIndentation:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Style/NegatedIf:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Style/RegexpLiteral:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Style/SingleSpaceBeforeFirstArg:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/SpaceAroundOperators:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Style/TrailingComma:
|
45
|
+
EnforcedStyleForMultiline: 'comma'
|
data/README.md
CHANGED
@@ -8,17 +8,17 @@ On a serious note, this gem allows you to generate tests template used for "char
|
|
8
8
|
## Table of Contents
|
9
9
|
1. [Installation](#installation)
|
10
10
|
- [Usage](#usage)
|
11
|
-
1. [
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
11
|
+
1. [Using the pretentious.yml file](#using-pretentious.yml)
|
12
|
+
2. [Declarative generation without using example files](#declarative-generation-without-using-example-files)
|
13
|
+
3. [Minitest](#minitest)
|
14
|
+
|
15
|
+
- [Handling complex parameters and object constructors](#handling-complex-parameters-and-object-constructors)
|
16
|
+
2. [Capturing Exceptions](#capturing-exceptions)
|
17
|
+
3. [Auto Stubbing](#auto-stubbing)
|
18
|
+
4. [Object Deconstruction Utility](#object-deconstruction-utility)
|
19
|
+
5. [Using the Object deconstructor in rails](#using-the-object-deconstructor-in-rails)
|
20
|
+
6. [Things to do after](#things-to-do-after)
|
21
|
+
7. [Limitations](#limitations)
|
22
22
|
|
23
23
|
## Installation
|
24
24
|
Add this line to your application's Gemfile:
|
@@ -40,6 +40,13 @@ $ gem install pretentious
|
|
40
40
|
```
|
41
41
|
|
42
42
|
## Usage
|
43
|
+
The are various ways to use the pretentious gem. First is using an example file. An example file is simply a ruby script that uses your target class in a way that you want to test. The pretentious gem will then analyze what methods are called, how it is created and generate test cases for it.
|
44
|
+
|
45
|
+
The other way is using an init file to declare which classes to test and when. This is useful if you want to document how a class is used in an existing application. This is the prefered method for characterization testing on framework like rails.
|
46
|
+
|
47
|
+
Both uses cases are discussed in the succeeding sections:
|
48
|
+
|
49
|
+
### Using an example file
|
43
50
|
First Create an example file (etc. example.rb) and define the classes that you want to test, if the class is already defined elsewhere just require them. Below is an example:
|
44
51
|
|
45
52
|
```ruby
|
@@ -186,43 +193,23 @@ end
|
|
186
193
|
|
187
194
|
Note: If your test subject is already part of a larger application and would like to capture behavior in the manner that the application uses it, please look at [Declarative Generation](#declarative-generation-without-using-example-files).
|
188
195
|
|
189
|
-
|
190
|
-
|
196
|
+
### Using pretentious.yml
|
197
|
+
If you run pretentious without passing an example file, it will look for pretentious.yml in the current location. Below is an example pretentious.yml file:
|
191
198
|
|
192
|
-
```
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
199
|
+
```YAML
|
200
|
+
# Sample pretentious targets file
|
201
|
+
targets:
|
202
|
+
- class: Meme
|
203
|
+
generators:
|
204
|
+
- rspec
|
205
|
+
- minitest
|
206
|
+
examples:
|
207
|
+
- sample.rb
|
198
208
|
```
|
199
209
|
|
200
|
-
|
201
|
-
|
202
|
-
```ruby
|
203
|
-
# This file was automatically generated by the pretentious gem
|
204
|
-
require 'minitest_helper'
|
205
|
-
require 'minitest/autorun'
|
206
|
-
|
207
|
-
class MemeTest < Minitest::Test
|
208
|
-
end
|
209
|
-
|
210
|
-
class MemeScenario1 < MemeTest
|
211
|
-
def setup
|
212
|
-
@fixture = Meme.new
|
213
|
-
end
|
214
|
-
|
215
|
-
def test_current_expectation
|
216
|
-
# Meme#i_can_has_cheezburger? should return 'OHAI!'
|
217
|
-
assert_equal 'OHAI!', @fixture.i_can_has_cheezburger?
|
218
|
-
|
219
|
-
# Meme#will_it_blend? should return 'YES!'
|
220
|
-
assert_equal 'YES!', @fixture.will_it_blend?
|
221
|
-
end
|
222
|
-
end
|
223
|
-
```
|
210
|
+
It basically contains three parts, the target classes to generate test for, the generators to use (rspec/minitest) and the example files to run. Note that in this case, Pretentious.spec_for/minitest_for is not needed in the example file as the target classes are already specified in the targets section.
|
224
211
|
|
225
|
-
|
212
|
+
### Declarative generation without using example files
|
226
213
|
Instead of using Pretentious.spec_for and wrapping the target code around a block, you may declaratively define when test generation should occur beforehand. This allows you to generate tests around code blocks without modifying source codes. This is useful for testing code embedded inside frameworks like rails where your "example" is already embedded inside existing code.
|
227
214
|
|
228
215
|
For example lets say you want to generate tests for UserAuthenticaion that is used inside the login method inside the UsersController inside a Rails app. You'd simply define like below:
|
@@ -275,6 +262,42 @@ end
|
|
275
262
|
|
276
263
|
IMPORTANT: If using rails or if it is part of a larger app, make sure to enable this only when you intend to generate specs! delete the initializer or comment the code out when it is not needed.
|
277
264
|
|
265
|
+
## Minitest
|
266
|
+
The minitest test framework is also supported, simply use Pretentious.minitest_for instead
|
267
|
+
|
268
|
+
```ruby
|
269
|
+
Pretentious.minitest_for(Meme) do
|
270
|
+
meme = Meme.new
|
271
|
+
meme.i_can_has_cheezburger?
|
272
|
+
meme.will_it_blend?
|
273
|
+
end
|
274
|
+
```
|
275
|
+
|
276
|
+
outputs:
|
277
|
+
|
278
|
+
```ruby
|
279
|
+
# This file was automatically generated by the pretentious gem
|
280
|
+
require 'minitest_helper'
|
281
|
+
require 'minitest/autorun'
|
282
|
+
|
283
|
+
class MemeTest < Minitest::Test
|
284
|
+
end
|
285
|
+
|
286
|
+
class MemeScenario1 < MemeTest
|
287
|
+
def setup
|
288
|
+
@fixture = Meme.new
|
289
|
+
end
|
290
|
+
|
291
|
+
def test_current_expectation
|
292
|
+
# Meme#i_can_has_cheezburger? should return 'OHAI!'
|
293
|
+
assert_equal 'OHAI!', @fixture.i_can_has_cheezburger?
|
294
|
+
|
295
|
+
# Meme#will_it_blend? should return 'YES!'
|
296
|
+
assert_equal 'YES!', @fixture.will_it_blend?
|
297
|
+
end
|
298
|
+
end
|
299
|
+
```
|
300
|
+
|
278
301
|
## Handling complex parameters and object constructors
|
279
302
|
No need to do anything special, just do as what you would do normally and the pretentious gem will figure it out. see below for an example:
|
280
303
|
|
data/bin/pretentious
CHANGED
@@ -6,6 +6,32 @@ require 'ripper'
|
|
6
6
|
require 'readline'
|
7
7
|
require 'json'
|
8
8
|
require 'fileutils'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
def eval_example(filename)
|
12
|
+
example_body = ''
|
13
|
+
index = 0
|
14
|
+
File.open(filename, "r") do |f|
|
15
|
+
f.each_line do |line|
|
16
|
+
example_body << "#{line}\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
eval(example_body, binding, filename, 1)
|
21
|
+
end
|
22
|
+
|
23
|
+
def write_output(output_folder, output_subfolder, last_results = nil)
|
24
|
+
# collect results and write them
|
25
|
+
puts "writing tests to #{output_folder}"
|
26
|
+
filewriter = Pretentious::FileWriter.new(output_folder: output_folder,
|
27
|
+
spec_output_folder: output_subfolder)
|
28
|
+
filewriter.write_results(last_results || Pretentious.last_results)
|
29
|
+
end
|
30
|
+
|
31
|
+
def process_file(filename, output_folder, output_subfolder, last_results = nil)
|
32
|
+
eval_example(filename)
|
33
|
+
write_output(output_folder, output_subfolder, last_results)
|
34
|
+
end
|
9
35
|
|
10
36
|
output_folder = nil
|
11
37
|
output_subfolder =nil
|
@@ -26,24 +52,58 @@ end
|
|
26
52
|
filename = ARGV[0]
|
27
53
|
|
28
54
|
if filename.nil?
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
55
|
+
if File.exists?('pretentious.yml')
|
56
|
+
targets_file = YAML.load_file('pretentious.yml')
|
57
|
+
targets_file['targets'].each do |target|
|
58
|
+
puts "generate for #{target['class']}"
|
59
|
+
Pretentious::LazyTrigger.new(target['class'], {})
|
60
|
+
end
|
33
61
|
|
34
|
-
|
62
|
+
Pretentious.watch {
|
63
|
+
targets_file['examples'].each do |f|
|
64
|
+
puts "executing target #{f}"
|
65
|
+
eval_example(f)
|
66
|
+
end
|
67
|
+
}
|
35
68
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
69
|
+
generator_classes = targets_file['generators'].collect do |g|
|
70
|
+
case g
|
71
|
+
when 'rspec'
|
72
|
+
Pretentious::RspecGenerator
|
73
|
+
when 'minitest'
|
74
|
+
Pretentious::MinitestGenerator
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
per_spec = {}
|
79
|
+
generator_classes.each do |generator_class|
|
80
|
+
puts "generating #{generator_class.to_sym} tests"
|
81
|
+
all_results = {}
|
82
|
+
Pretentious::LazyTrigger.collect_targets.each do |target|
|
83
|
+
standin_klass = target.stand_in_klass
|
84
|
+
klass = target.original_klass
|
85
|
+
puts "generate for #{klass}"
|
86
|
+
generator = generator_class.new
|
42
87
|
|
43
|
-
|
88
|
+
generator.begin_spec(klass)
|
89
|
+
generator.body(standin_klass._instances) unless standin_klass._instances.nil?
|
90
|
+
generator.end_spec
|
44
91
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
92
|
+
result = all_results[klass]
|
93
|
+
all_results[klass] = [] if result.nil?
|
94
|
+
|
95
|
+
result_output = generator.output.is_a?(String) ? generator.output.chomp : generator.output
|
96
|
+
all_results[klass] = { output: result_output, generator: generator.class }
|
97
|
+
end
|
98
|
+
per_spec[generator_class.to_sym] = all_results
|
99
|
+
end
|
100
|
+
puts "writing output..."
|
101
|
+
write_output(output_folder, output_subfolder, per_spec)
|
102
|
+
else
|
103
|
+
puts 'a target or an example file is required.'
|
104
|
+
puts options
|
105
|
+
exit(1)
|
106
|
+
end
|
107
|
+
else
|
108
|
+
process_file(filename, output_folder, output_subfolder)
|
109
|
+
end
|
data/lib/pretentious.rb
CHANGED
@@ -8,6 +8,7 @@ require 'pretentious/generator'
|
|
8
8
|
require 'binding_of_caller'
|
9
9
|
require 'pretentious/deconstructor'
|
10
10
|
require 'pretentious/trigger'
|
11
|
+
require 'pretentious/lazy_trigger'
|
11
12
|
require 'pretentious/utils/file_writer'
|
12
13
|
|
13
14
|
Class.class_eval do
|
@@ -64,6 +65,12 @@ module Pretentious
|
|
64
65
|
.generate_for(*klasses, &block))
|
65
66
|
end
|
66
67
|
|
68
|
+
def self.write_results(output_folder = nil, output_subfolder = nil, last_results = nil)
|
69
|
+
filewriter = Pretentious::FileWriter.new(output_folder: output_folder,
|
70
|
+
spec_output_folder: output_subfolder)
|
71
|
+
filewriter.write_results(last_results || Pretentious.last_results)
|
72
|
+
end
|
73
|
+
|
67
74
|
def self.clear_results
|
68
75
|
@spec_results = {}
|
69
76
|
@minitest_results = {}
|
@@ -355,13 +355,11 @@ module Pretentious
|
|
355
355
|
params = []
|
356
356
|
if definition[:ref] && definition[:ref].size > 0
|
357
357
|
|
358
|
-
i = 0
|
359
358
|
params_types = definition[:params_types]
|
360
359
|
definition[:ref].each_with_index do |v, index|
|
361
360
|
type = :param
|
362
|
-
if params_types
|
361
|
+
if params_types && params_types[index]
|
363
362
|
type = params_types[index][0]
|
364
|
-
i += 1
|
365
363
|
end
|
366
364
|
|
367
365
|
# to inline?
|
@@ -42,7 +42,15 @@ module Pretentious
|
|
42
42
|
")
|
43
43
|
|
44
44
|
new_standin_klass.class_exec do
|
45
|
+
|
45
46
|
def initialize(*args, &block)
|
47
|
+
#check for special invocations
|
48
|
+
an_instance = if args[0] == :_no_init
|
49
|
+
_cmd, an_instance = args.shift(2)
|
50
|
+
an_instance
|
51
|
+
else
|
52
|
+
nil
|
53
|
+
end
|
46
54
|
@_instance_init = { object_id: object_id, params: [], block: nil }
|
47
55
|
|
48
56
|
self.class.replace_procs_with_recorders(args)
|
@@ -52,7 +60,12 @@ module Pretentious
|
|
52
60
|
|
53
61
|
@_instance_init[:block] = recorded_proc
|
54
62
|
|
55
|
-
|
63
|
+
@_instance = if an_instance
|
64
|
+
an_instance
|
65
|
+
else
|
66
|
+
setup_instance(*args, &recorded_proc)
|
67
|
+
end
|
68
|
+
|
56
69
|
param_types = @_instance.method(:initialize).parameters
|
57
70
|
@_instance_init[:params_types] = param_types
|
58
71
|
|
@@ -67,8 +80,11 @@ module Pretentious
|
|
67
80
|
v_locals = caller_context.eval('local_variables')
|
68
81
|
|
69
82
|
v_locals.each do |v|
|
70
|
-
|
71
|
-
|
83
|
+
begin
|
84
|
+
variable_value = caller_context.eval("#{v.to_s}")
|
85
|
+
@_init_let_variables[variable_value.object_id] = v
|
86
|
+
rescue NoMethodError
|
87
|
+
end
|
72
88
|
end
|
73
89
|
|
74
90
|
args.each_with_index do |a, index|
|
@@ -82,6 +98,10 @@ module Pretentious
|
|
82
98
|
@_instance_init
|
83
99
|
end
|
84
100
|
|
101
|
+
def _get_init_arguments
|
102
|
+
@_instance_init
|
103
|
+
end
|
104
|
+
|
85
105
|
def test_class
|
86
106
|
@_instance.class
|
87
107
|
end
|
@@ -110,6 +130,10 @@ module Pretentious
|
|
110
130
|
@_instance.to_s
|
111
131
|
end
|
112
132
|
|
133
|
+
def impostor?
|
134
|
+
true
|
135
|
+
end
|
136
|
+
|
113
137
|
def ==(other)
|
114
138
|
@_instance == other
|
115
139
|
end
|
@@ -148,6 +172,10 @@ module Pretentious
|
|
148
172
|
|
149
173
|
class << self
|
150
174
|
|
175
|
+
def impostor?
|
176
|
+
true
|
177
|
+
end
|
178
|
+
|
151
179
|
def replace_procs_with_recorders(args)
|
152
180
|
(0..args.size).each do |index|
|
153
181
|
if args[index].kind_of? Proc
|
@@ -171,7 +199,7 @@ module Pretentious
|
|
171
199
|
end
|
172
200
|
|
173
201
|
def let_variables
|
174
|
-
@_let_variables.dup
|
202
|
+
@_let_variables ? @_let_variables.dup : {}
|
175
203
|
end
|
176
204
|
|
177
205
|
def method_calls_by_method
|
@@ -226,8 +254,11 @@ module Pretentious
|
|
226
254
|
v_locals = caller_context.eval('local_variables')
|
227
255
|
|
228
256
|
v_locals.each do |v|
|
229
|
-
|
230
|
-
|
257
|
+
begin
|
258
|
+
variable_value = caller_context.eval("#{v}")
|
259
|
+
@_let_variables[variable_value.object_id] = v
|
260
|
+
rescue NoMethodError
|
261
|
+
end
|
231
262
|
end
|
232
263
|
|
233
264
|
klass.replace_procs_with_recorders(arguments)
|
@@ -300,13 +331,19 @@ module Pretentious
|
|
300
331
|
@_instance = _current_old_class
|
301
332
|
_call_method(self, method_sym, *arguments, &block)
|
302
333
|
end
|
334
|
+
|
335
|
+
def const_missing(sym)
|
336
|
+
_add_instances(self)
|
337
|
+
@_instance = _current_old_class
|
338
|
+
@_instance.const_get(sym)
|
339
|
+
end
|
303
340
|
end
|
304
341
|
end
|
305
342
|
|
306
343
|
new_standin_klass
|
307
344
|
end
|
308
345
|
|
309
|
-
def self.
|
346
|
+
def self.denamespace(klass)
|
310
347
|
klass_name_parts = klass.name.split('::')
|
311
348
|
last_part = klass_name_parts.pop
|
312
349
|
|
@@ -318,7 +355,13 @@ module Pretentious
|
|
318
355
|
end
|
319
356
|
end
|
320
357
|
|
358
|
+
[last_part, module_space]
|
359
|
+
end
|
360
|
+
|
361
|
+
def self.replace_class(klass, stub = false)
|
362
|
+
last_part, module_space = denamespace(klass)
|
321
363
|
new_standin_klass = impostor_for module_space, klass
|
364
|
+
|
322
365
|
new_standin_klass._set_is_stub if stub
|
323
366
|
|
324
367
|
module_space.send(:remove_const, last_part.to_sym)
|
@@ -341,16 +384,20 @@ module Pretentious
|
|
341
384
|
mock_dict = {}
|
342
385
|
|
343
386
|
klasses_or_instances.each do |klass_or_instance|
|
344
|
-
|
345
|
-
|
387
|
+
if klass_or_instance.is_a? String
|
388
|
+
Pretentious::LazyTrigger.new(klass_or_instance, {})
|
389
|
+
else
|
390
|
+
klass = klass_or_instance.class == Class ? klass_or_instance : klass_or_instance.class
|
391
|
+
klasses << replace_class(klass)
|
346
392
|
|
347
|
-
|
393
|
+
mock_klasses = []
|
348
394
|
|
349
|
-
|
350
|
-
|
351
|
-
|
395
|
+
klass._get_mock_classes.each do |mock_klass|
|
396
|
+
mock_klasses << replace_class(mock_klass, true)
|
397
|
+
end unless klass._get_mock_classes.nil?
|
352
398
|
|
353
|
-
|
399
|
+
mock_dict[klass] = mock_klasses
|
400
|
+
end
|
354
401
|
end
|
355
402
|
|
356
403
|
watch_new_instances
|
@@ -359,13 +406,17 @@ module Pretentious
|
|
359
406
|
|
360
407
|
unwatch_new_instances
|
361
408
|
|
409
|
+
# check for lazy triggers, collect and then clean
|
410
|
+
klasses += Pretentious::LazyTrigger.collect_targets.map(&:to_a)
|
411
|
+
Pretentious::LazyTrigger.clear
|
412
|
+
|
362
413
|
klasses.each do |module_space, klass, last_part, new_standin_klass|
|
363
414
|
# restore the previous class
|
364
415
|
restore_class module_space, klass, last_part
|
365
416
|
|
366
417
|
mock_dict[klass].each do |mock_module_space, mock_klass, mock_last_part, mock_new_standin_klass|
|
367
418
|
restore_class mock_module_space, mock_klass, mock_last_part
|
368
|
-
end
|
419
|
+
end if mock_dict[klass]
|
369
420
|
|
370
421
|
generator = test_generator.new
|
371
422
|
generator.begin_spec(klass)
|
@@ -391,9 +442,9 @@ module Pretentious
|
|
391
442
|
end
|
392
443
|
|
393
444
|
def _set_init_arguments(*args, &block)
|
394
|
-
@_init_arguments
|
395
|
-
@_init_arguments[:params]
|
396
|
-
unless
|
445
|
+
@_init_arguments ||= {}
|
446
|
+
@_init_arguments[:params] = args
|
447
|
+
unless block.nil?
|
397
448
|
@_init_arguments[:block] = RecordedProc.new(block) {}
|
398
449
|
end
|
399
450
|
@_variable_names = {}
|
@@ -409,7 +460,6 @@ module Pretentious
|
|
409
460
|
p = params[index]
|
410
461
|
@_variable_names[arg.object_id] = p[1].to_s if p && p.size > 1
|
411
462
|
end unless args.nil?
|
412
|
-
|
413
463
|
end
|
414
464
|
|
415
465
|
def _variable_map
|
@@ -446,17 +496,33 @@ module Pretentious
|
|
446
496
|
alias_method :_ddt_old_new, :new
|
447
497
|
|
448
498
|
def new(*args, &block)
|
449
|
-
|
499
|
+
lazy_trigger = Pretentious::LazyTrigger.lookup(self.to_s)
|
500
|
+
instance = nil
|
501
|
+
if !lazy_trigger.nil?
|
502
|
+
klass = self
|
503
|
+
instance = if methods.include? :_current_old_class
|
504
|
+
_ddt_old_new(*args, &block)
|
505
|
+
else
|
506
|
+
module_space, klass, last_part, stand_in_class = Pretentious::Generator.replace_class(self)
|
507
|
+
lazy_trigger.register_class(module_space, klass, last_part, stand_in_class)
|
508
|
+
inst = _ddt_old_new(*args, &block)
|
509
|
+
stand_in_class.new(*([:_no_init, inst] + args), &block)
|
510
|
+
end
|
511
|
+
else
|
512
|
+
instance = _ddt_old_new(*args, &block)
|
513
|
+
end
|
450
514
|
|
451
515
|
# rescues for handling native objects that don't have standard methods
|
452
516
|
begin
|
453
|
-
if instance.respond_to?(:_set_init_arguments)
|
517
|
+
if instance.respond_to?(:_set_init_arguments) && !instance.respond_to?(:impostor?)
|
454
518
|
instance._set_init_arguments(*args, &block)
|
455
519
|
end
|
456
520
|
rescue NoMethodError
|
457
521
|
begin
|
522
|
+
puts "no method error"
|
458
523
|
instance._set_init_arguments(*args, &block)
|
459
524
|
rescue NoMethodError
|
525
|
+
# eat up NoMethodError for now
|
460
526
|
end
|
461
527
|
end
|
462
528
|
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Pretentious
|
2
|
+
class LazyTrigger
|
3
|
+
attr_accessor :target_class, :options, :targets
|
4
|
+
|
5
|
+
class Target
|
6
|
+
attr_accessor :stand_in_klass, :original_klass, :module_space, :name
|
7
|
+
|
8
|
+
def initialize(module_space, klass, last_part, stand_in_class)
|
9
|
+
@module_space = module_space
|
10
|
+
@stand_in_klass = stand_in_class
|
11
|
+
@original_klass = klass
|
12
|
+
@name = last_part
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_a
|
16
|
+
[@module_space, @original_klass, @name, @stand_in_klass]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(target_class, options = {})
|
21
|
+
@target_class = target_class
|
22
|
+
@options = options
|
23
|
+
@targets = {}
|
24
|
+
Pretentious::LazyTrigger.register_instance(self)
|
25
|
+
end
|
26
|
+
|
27
|
+
def disable!
|
28
|
+
Pretentious::LazyTrigger.unregister_instance(self)
|
29
|
+
end
|
30
|
+
|
31
|
+
def restore
|
32
|
+
@targets.each do |_stand_in_klass, target|
|
33
|
+
Pretentious::Generator.restore_class target.module_space, target.original_klass, target.name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def register_class(module_space, klass, last_part, stand_in_class)
|
38
|
+
target = Pretentious::LazyTrigger::Target.new(module_space, klass, last_part, stand_in_class)
|
39
|
+
@targets[target.stand_in_klass] = target unless @targets.include? target.stand_in_klass
|
40
|
+
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
def lookup(class_name)
|
44
|
+
@instances ||= []
|
45
|
+
@instances.each do |instance|
|
46
|
+
return instance if instance.target_class == class_name
|
47
|
+
end
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def collect_targets
|
52
|
+
artifacts = []
|
53
|
+
@instances.each do |instance|
|
54
|
+
instance.targets.values.each do |target|
|
55
|
+
artifacts << target
|
56
|
+
end
|
57
|
+
end
|
58
|
+
artifacts
|
59
|
+
end
|
60
|
+
|
61
|
+
def collect_artifacts
|
62
|
+
artifacts = []
|
63
|
+
@instances.each do |instance|
|
64
|
+
instance.targets.values.each do |target|
|
65
|
+
artifacts << target.stand_in_klass
|
66
|
+
end
|
67
|
+
end
|
68
|
+
artifacts
|
69
|
+
end
|
70
|
+
|
71
|
+
def clear
|
72
|
+
@instances = []
|
73
|
+
end
|
74
|
+
|
75
|
+
def register_instance(instance)
|
76
|
+
@instances ||= []
|
77
|
+
@instances << instance unless @instances.include? instance
|
78
|
+
end
|
79
|
+
|
80
|
+
def unregister_instance(instance)
|
81
|
+
@instances.delete(instance)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module Pretentious
|
2
2
|
# Generator that outputs minitest specs
|
3
3
|
class MinitestGenerator < Pretentious::GeneratorBase
|
4
|
+
def self.to_sym
|
5
|
+
:minitest
|
6
|
+
end
|
7
|
+
|
4
8
|
def begin_spec(test_class)
|
5
9
|
@test_class = test_class
|
6
10
|
buffer('# This file was automatically generated by the pretentious gem')
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module Pretentious
|
2
2
|
# Generator for RSPEC
|
3
3
|
class RspecGenerator < Pretentious::GeneratorBase
|
4
|
+
def self.to_sym
|
5
|
+
:rspec
|
6
|
+
end
|
7
|
+
|
4
8
|
def begin_spec(test_class)
|
5
9
|
buffer('# This file was automatically generated by the pretentious gem')
|
6
10
|
buffer("require 'spec_helper'")
|
@@ -88,6 +92,8 @@ module Pretentious
|
|
88
92
|
mocks_collection = {}
|
89
93
|
method_call_collection = []
|
90
94
|
|
95
|
+
return if method_calls.nil?
|
96
|
+
|
91
97
|
method_calls.each_key do |k|
|
92
98
|
info_blocks_arr = method_calls[k]
|
93
99
|
info_blocks_arr.each do |block|
|
data/lib/pretentious/version.rb
CHANGED
data/pretentious.yml
ADDED
data/run_test.sh
CHANGED
data/sample.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# This file was automatically generated by the pretentious gem
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
RSpec.describe Meme do
|
5
|
+
context 'Scenario 1' do
|
6
|
+
before do
|
7
|
+
@fixture = Meme.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should pass current expectations' do
|
11
|
+
# Meme#i_can_has_cheezburger? should return 'OHAI!'
|
12
|
+
expect(@fixture.i_can_has_cheezburger?).to eq('OHAI!')
|
13
|
+
|
14
|
+
# Meme#will_it_blend? should return 'YES!'
|
15
|
+
expect(@fixture.will_it_blend?).to eq('YES!')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -54,7 +54,7 @@ RSpec.describe TestClass1 do
|
|
54
54
|
|
55
55
|
it 'should pass current expectations' do
|
56
56
|
another_object = TestClass1.new('test')
|
57
|
-
# TestClass1#return_self when passed message = #<TestClass1:
|
57
|
+
# TestClass1#return_self when passed message = #<TestClass1:0x000000012b4098> should return another_object
|
58
58
|
expect(@fixture.return_self(another_object)).to eq(another_object)
|
59
59
|
end
|
60
60
|
end
|
data/spec/generator_spec.rb
CHANGED
@@ -7,7 +7,6 @@ class TestSubClass
|
|
7
7
|
end
|
8
8
|
|
9
9
|
class TestClass
|
10
|
-
|
11
10
|
def initialize(dep = nil)
|
12
11
|
@test_class2 = TestSubClass.new
|
13
12
|
end
|
@@ -26,7 +25,6 @@ class TestClass
|
|
26
25
|
end
|
27
26
|
|
28
27
|
class DummyGenerator
|
29
|
-
|
30
28
|
def initialize
|
31
29
|
@data = []
|
32
30
|
end
|
@@ -47,24 +45,22 @@ class DummyGenerator
|
|
47
45
|
instance_count: instance_count}
|
48
46
|
end
|
49
47
|
|
50
|
-
def end_spec
|
48
|
+
def end_spec
|
51
49
|
@data << :end
|
52
50
|
end
|
53
51
|
|
54
52
|
def output
|
55
53
|
@data
|
56
54
|
end
|
57
|
-
|
58
55
|
end
|
59
56
|
|
60
57
|
class DummyGenerator2
|
61
|
-
|
62
58
|
def initialize
|
63
59
|
@data = []
|
64
60
|
end
|
65
61
|
|
66
62
|
def begin_spec(test_class)
|
67
|
-
@data << {begin: test_class}
|
63
|
+
@data << { begin: test_class }
|
68
64
|
end
|
69
65
|
|
70
66
|
def body(instances)
|
@@ -80,10 +76,10 @@ class DummyGenerator2
|
|
80
76
|
|
81
77
|
deconstruct_targets = [test_instance]
|
82
78
|
test_instance.method_calls.each do |method_calls|
|
83
|
-
deconstruct_targets
|
79
|
+
deconstruct_targets += method_calls[:params]
|
84
80
|
end
|
85
81
|
|
86
|
-
deconstruct =
|
82
|
+
deconstruct = deconstructor.deconstruct(test_instance.method_calls, *deconstruct_targets)
|
87
83
|
deconstruct[:declaration].each do |d|
|
88
84
|
@data << d
|
89
85
|
end
|
@@ -94,18 +90,16 @@ class DummyGenerator2
|
|
94
90
|
@data << :generate_end
|
95
91
|
end
|
96
92
|
|
97
|
-
def end_spec
|
93
|
+
def end_spec
|
98
94
|
@data << :end
|
99
95
|
end
|
100
96
|
|
101
97
|
def output
|
102
98
|
@data
|
103
99
|
end
|
104
|
-
|
105
100
|
end
|
106
101
|
|
107
102
|
RSpec.describe Pretentious::Generator do
|
108
|
-
|
109
103
|
context 'Pretentious::Generator#impostor_for' do
|
110
104
|
before do
|
111
105
|
@impostor = Pretentious::Generator.impostor_for(Object, TestClass)
|
@@ -126,7 +120,6 @@ RSpec.describe Pretentious::Generator do
|
|
126
120
|
end
|
127
121
|
|
128
122
|
context "Pretentious::Generator#replace_class" do
|
129
|
-
|
130
123
|
around(:each) do |example|
|
131
124
|
@old_class = TestClass
|
132
125
|
module_space, klass, last, new_class = Pretentious::Generator.replace_class(TestClass)
|
@@ -179,7 +172,6 @@ RSpec.describe Pretentious::Generator do
|
|
179
172
|
end
|
180
173
|
|
181
174
|
context "auto mocks generator" do
|
182
|
-
|
183
175
|
it "generates a stub call structure" do
|
184
176
|
|
185
177
|
call_artifacts = Pretentious::Generator.generate_for(TestClass._stub(TestSubClass)) do
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Pretentious::LazyTrigger do
|
4
|
+
it 'Can predeclare even if the class is not yet defined' do
|
5
|
+
Pretentious.watch do
|
6
|
+
lazy_trigger = Pretentious::LazyTrigger.new('TestLazyClass')
|
7
|
+
|
8
|
+
class TestLazyClass
|
9
|
+
def test_method
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
lazy_class = TestLazyClass.new
|
14
|
+
lazy_class.test_method
|
15
|
+
|
16
|
+
expect(lazy_trigger.targets.keys).to eq([Object.const_get('TestLazyClass')])
|
17
|
+
expect(Pretentious::LazyTrigger.collect_artifacts).to eq([Object.const_get('TestLazyClass')])
|
18
|
+
expect(TestLazyClass._instances).to eq([lazy_class])
|
19
|
+
lazy_trigger.disable!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can use strings in spec_for to use the lazy trigger" do
|
24
|
+
call_artifacts = Pretentious::Generator.generate_for("TestLazyClass2") do
|
25
|
+
class TestLazyClass2
|
26
|
+
def test_method
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
lazy_class = TestLazyClass2.new
|
31
|
+
lazy_class.test_method
|
32
|
+
end
|
33
|
+
expect(call_artifacts).to eq({TestLazyClass2=>{:output=>"# This file was automatically generated by the pretentious gem\nrequire 'spec_helper'\n\nRSpec.describe TestLazyClass2 do\n context 'Scenario 1' do\n before do\n @fixture = TestLazyClass2.new\n end\n\n it 'should pass current expectations' do\n # TestLazyClass2#test_method should return nil\n expect(@fixture.test_method).to be_nil\n end\n end\nend", :generator=>Pretentious::RspecGenerator}})
|
34
|
+
end
|
35
|
+
end
|
data/spec/prententious_spec.rb
CHANGED
@@ -65,6 +65,12 @@ RSpec.describe Pretentious::Generator do
|
|
65
65
|
expect(result[TestClass1][:output]).to match('expect { @fixture.something_is_wrong }.to raise_error')
|
66
66
|
end
|
67
67
|
|
68
|
+
it "handles constants inside classes" do
|
69
|
+
Pretentious.spec_for(TestClass1) do
|
70
|
+
expect(TestClass1::SOME_CONSTANT).to eq('Yes this is a constant')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
68
74
|
it "handles method missing" do
|
69
75
|
result = Pretentious.spec_for(TestClassMethodMissing) do
|
70
76
|
test_class = TestClassMethodMissing.new
|
@@ -59,7 +59,7 @@ class TestClass1Scenario3 < TestClass1Test
|
|
59
59
|
def test_current_expectation
|
60
60
|
another_object = TestClass1.new('test')
|
61
61
|
|
62
|
-
# TestClass1#return_self when passed message = #<TestClass1:
|
62
|
+
# TestClass1#return_self when passed message = #<TestClass1:0x0000000214e978> should return another_object
|
63
63
|
assert_equal another_object, @fixture.return_self(another_object)
|
64
64
|
end
|
65
65
|
end
|
data/test_classes.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pretentious
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joseph Emmanuel Dayo
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-12-
|
11
|
+
date: 2015-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: binding_of_caller
|
@@ -161,6 +161,7 @@ extensions: []
|
|
161
161
|
extra_rdoc_files: []
|
162
162
|
files:
|
163
163
|
- ".gitignore"
|
164
|
+
- ".rubocop.yml"
|
164
165
|
- CHANGELOG.md
|
165
166
|
- Gemfile
|
166
167
|
- LICENSE.txt
|
@@ -173,6 +174,7 @@ files:
|
|
173
174
|
- lib/pretentious/deconstructor.rb
|
174
175
|
- lib/pretentious/generator.rb
|
175
176
|
- lib/pretentious/generator_base.rb
|
177
|
+
- lib/pretentious/lazy_trigger.rb
|
176
178
|
- lib/pretentious/minitest_generator.rb
|
177
179
|
- lib/pretentious/recorded_proc.rb
|
178
180
|
- lib/pretentious/rspec_generator.rb
|
@@ -180,10 +182,13 @@ files:
|
|
180
182
|
- lib/pretentious/utils/file_writer.rb
|
181
183
|
- lib/pretentious/version.rb
|
182
184
|
- pretentious.gemspec
|
185
|
+
- pretentious.yml
|
183
186
|
- run_test.sh
|
187
|
+
- sample.rb
|
184
188
|
- spec/deconstructor_spec.rb
|
185
189
|
- spec/generated/fibonacci_spec.rb
|
186
190
|
- spec/generated/m_d5_spec.rb
|
191
|
+
- spec/generated/meme_spec.rb
|
187
192
|
- spec/generated/test_class1_spec.rb
|
188
193
|
- spec/generated/test_class2_spec.rb
|
189
194
|
- spec/generated/test_class3_spec.rb
|
@@ -191,6 +196,7 @@ files:
|
|
191
196
|
- spec/generated/test_class_for_auto_stub_spec.rb
|
192
197
|
- spec/generated/test_class_for_mocks_spec.rb
|
193
198
|
- spec/generator_spec.rb
|
199
|
+
- spec/lazy_trigger_spec.rb
|
194
200
|
- spec/minitest_generator_spec.rb
|
195
201
|
- spec/prententious_spec.rb
|
196
202
|
- spec/spec_helper.rb
|
@@ -235,6 +241,7 @@ test_files:
|
|
235
241
|
- spec/deconstructor_spec.rb
|
236
242
|
- spec/generated/fibonacci_spec.rb
|
237
243
|
- spec/generated/m_d5_spec.rb
|
244
|
+
- spec/generated/meme_spec.rb
|
238
245
|
- spec/generated/test_class1_spec.rb
|
239
246
|
- spec/generated/test_class2_spec.rb
|
240
247
|
- spec/generated/test_class3_spec.rb
|
@@ -242,6 +249,7 @@ test_files:
|
|
242
249
|
- spec/generated/test_class_for_auto_stub_spec.rb
|
243
250
|
- spec/generated/test_class_for_mocks_spec.rb
|
244
251
|
- spec/generator_spec.rb
|
252
|
+
- spec/lazy_trigger_spec.rb
|
245
253
|
- spec/minitest_generator_spec.rb
|
246
254
|
- spec/prententious_spec.rb
|
247
255
|
- spec/spec_helper.rb
|