pretentious 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,460 @@
1
+ module Pretentious
2
+ class Generator
3
+
4
+ def self.test_generator=(generator)
5
+ @test_generator = generator
6
+ end
7
+
8
+ def self.test_generator
9
+ @test_generator || Pretentious::RspecGenerator
10
+ end
11
+
12
+ def self.impostor_for(module_space, klass)
13
+ newStandInKlass = Class.new()
14
+ name = klass.name
15
+ module_space.const_set "#{name.split('::').last}Impostor", newStandInKlass
16
+
17
+ newStandInKlass.class_eval("
18
+ def setup_instance(*args, &block)
19
+ @_instance = #{klass.name}_ddt.new(*args, &block)
20
+ end
21
+ ")
22
+
23
+ newStandInKlass.class_eval("
24
+ class << self
25
+ def _get_standin_class
26
+ #{newStandInKlass}
27
+ end
28
+
29
+ def test_class
30
+ #{klass.name}
31
+ end
32
+
33
+ def _current_old_class
34
+ #{klass.name}_ddt
35
+ end
36
+ end
37
+ ")
38
+
39
+ newStandInKlass.class_exec do
40
+
41
+ def initialize(*args, &block)
42
+
43
+ @_instance_init = {params: [], block: nil}
44
+
45
+ self.class.replace_procs_with_recorders(args)
46
+
47
+ @_instance_init[:params] = args
48
+
49
+ recordedProc = if (block)
50
+ RecordedProc.new(block, true)
51
+ else
52
+ nil
53
+ end
54
+
55
+ @_instance_init[:block] = recordedProc
56
+
57
+ setup_instance(*args, &recordedProc)
58
+
59
+
60
+ @_method_calls = []
61
+ @_method_calls_by_method = {}
62
+ @_methods_for_test = []
63
+ @_let_variables = {}
64
+
65
+
66
+ @_init_let_variables = {}
67
+
68
+ caller_context = binding.of_caller(2)
69
+ v_locals = caller_context.eval('local_variables')
70
+
71
+ v_locals.each { |v|
72
+ variable_value = caller_context.eval("#{v.to_s}")
73
+ @_init_let_variables[variable_value.object_id] = v
74
+ }
75
+
76
+ self.class._add_instances(self)
77
+ end
78
+
79
+ def _init_arguments
80
+ @_instance_init
81
+ end
82
+
83
+ def test_class
84
+ @_instance.class
85
+ end
86
+
87
+ def include_for_tests(method_list = [])
88
+ @_methods_for_test = @_methods_for_test + method_list
89
+ end
90
+
91
+ def let_variables
92
+ @_let_variables
93
+ end
94
+
95
+ def init_let_variables
96
+ @_init_let_variables
97
+ end
98
+
99
+ def method_calls_by_method
100
+ @_method_calls_by_method
101
+ end
102
+
103
+ def method_calls
104
+ @_method_calls
105
+ end
106
+
107
+ def to_s
108
+ @_instance.to_s
109
+ end
110
+
111
+ def ==(other)
112
+ @_instance==other
113
+ end
114
+
115
+ def kind_of?(klass)
116
+ @_instance.kind_of? klass
117
+ end
118
+
119
+ def methods
120
+ @_instance.methods + [:method_calls]
121
+ end
122
+
123
+ def freeze
124
+ @_instance.freeze
125
+ end
126
+
127
+ def hash
128
+ @instance.hash
129
+ end
130
+
131
+ def inspect
132
+ @_instance.inspect
133
+ end
134
+
135
+ def is_a?(something)
136
+ @_instance.is_a? something
137
+ end
138
+
139
+ def instance_variable_get(sym)
140
+ @_instance.instance_variable_get(sym)
141
+ end
142
+
143
+ def instance_variable_set(sym, val)
144
+ @_instance.instance_variable_get(sym, val)
145
+ end
146
+
147
+ class << self
148
+
149
+ def replace_procs_with_recorders(args)
150
+ (0..args.size).each do |index|
151
+ if (args[index].kind_of? Proc)
152
+ args[index] = Pretentious::RecordedProc.new(args[index]) {}
153
+ end
154
+ end
155
+ end
156
+
157
+ def _set_is_stub
158
+ @_is_stub = true
159
+ end
160
+
161
+ def _is_stub?
162
+ @_is_stub = @_is_stub || false
163
+ @_is_stub
164
+ end
165
+
166
+ def _add_instances(instance)
167
+ @_instances = @_instances || []
168
+ @_instances << instance unless @_instances.include? instance
169
+ end
170
+
171
+ def let_variables
172
+ @_let_variables
173
+ end
174
+
175
+ def method_calls_by_method
176
+ @_method_calls_by_method
177
+ end
178
+
179
+ def method_calls
180
+ @_method_calls
181
+ end
182
+
183
+ def _add_instances(instance)
184
+ @_instances = @_instances || []
185
+ @_instances << instance unless @_instances.include? instance
186
+ end
187
+
188
+ def _instances
189
+ @_instances
190
+ end
191
+
192
+ def instance_methods
193
+ methods = super
194
+ test_class.instance_methods + methods
195
+ end
196
+
197
+ def _call_method(target, method_sym, *arguments, &block)
198
+
199
+ klass = _get_standin_class
200
+ caller_context = binding.of_caller(2)
201
+
202
+ is_stub = _is_stub?
203
+
204
+ target.instance_exec do
205
+ @_method_calls = @_method_calls || []
206
+ @_method_calls_by_method = @_method_calls_by_method || {}
207
+ @_methods_for_test = @_methods_for_test || []
208
+ @_let_variables = @_let_variables || {}
209
+
210
+
211
+ #puts \"local_variables\"
212
+ v_locals = caller_context.eval('local_variables')
213
+
214
+ v_locals.each { |v|
215
+ variable_value = caller_context.eval("#{v.to_s}")
216
+ @_let_variables[variable_value.object_id] = v
217
+ }
218
+
219
+ klass.replace_procs_with_recorders(arguments)
220
+
221
+ info_block = {}
222
+ info_block[:method] = method_sym
223
+ info_block[:params] = arguments
224
+
225
+ recordedProc = if (block)
226
+ RecordedProc.new(block, true)
227
+ else
228
+ nil
229
+ end
230
+ info_block[:block] = recordedProc
231
+
232
+ info_block[:names] = @_instance.method(method_sym).parameters
233
+
234
+ begin
235
+
236
+ unless is_stub
237
+ current_context = { calls: [] }
238
+ info_block[:context] = current_context
239
+
240
+ Thread.current._push_context(current_context)
241
+ end
242
+
243
+ if (@_instance.methods.include? method_sym)
244
+ result = @_instance.send(method_sym, *arguments, &recordedProc)
245
+ else
246
+ result = @_instance.send(:method_missing, method_sym, *arguments, &recordedProc)
247
+ end
248
+
249
+ Thread.current._pop_context unless is_stub
250
+
251
+ # methods that end with = are a special case with return values
252
+ if method_sym.to_s.end_with? '='
253
+ info_block[:result] = arguments[0]
254
+ else
255
+ info_block[:result] = result
256
+ end
257
+
258
+ rescue Exception=>e
259
+ info_block[:result] = e
260
+ rescue StandardError=>e
261
+ info_block[:result] = e
262
+ end
263
+
264
+ if is_stub
265
+ info_block[:class] = test_class
266
+ Thread.current._all_context.each { |mock_context|
267
+ mock_context[:calls] << info_block if mock_context
268
+ }
269
+ end
270
+
271
+ @_method_calls << info_block
272
+
273
+ if (@_method_calls_by_method[method_sym].nil?)
274
+ @_method_calls_by_method[method_sym] = []
275
+ end
276
+
277
+ @_method_calls_by_method[method_sym] << info_block
278
+ raise e if (e.kind_of? Exception)
279
+ result
280
+ end
281
+ end
282
+
283
+ end
284
+
285
+ end
286
+
287
+ newStandInKlass.class_exec do
288
+ def method_missing(method_sym, *arguments, &block)
289
+ #puts "#{method_sym} #{arguments}"
290
+ self.class._call_method(self, method_sym, *arguments, &block)
291
+ end
292
+
293
+ class << self
294
+ def method_missing(method_sym, *arguments, &block)
295
+ #puts "method #{method_sym.to_s}"
296
+ _add_instances(self)
297
+ @_instance = _current_old_class
298
+ _call_method(self, method_sym, *arguments, &block)
299
+ end
300
+ end
301
+ end
302
+
303
+ newStandInKlass
304
+ end
305
+
306
+ def self.replace_class(klass, stub = false)
307
+ klass_name_parts = klass.name.split('::')
308
+ last_part = klass_name_parts.pop
309
+
310
+ module_space = Object
311
+
312
+ if (klass_name_parts.size > 0)
313
+ klass_name_parts.each do |part|
314
+ module_space = module_space.const_get(part)
315
+ end
316
+ end
317
+
318
+ newStandInKlass = impostor_for module_space, klass
319
+ newStandInKlass._set_is_stub if stub
320
+
321
+ module_space.send(:remove_const,last_part.to_sym)
322
+ module_space.const_set("#{last_part}_ddt", klass)
323
+ module_space.const_set("#{last_part}", newStandInKlass)
324
+
325
+ [module_space, klass, last_part, newStandInKlass]
326
+ end
327
+
328
+ def self.restore_class(module_space, klass, last_part)
329
+ module_space.send(:remove_const,"#{last_part}Impostor".to_sym)
330
+ module_space.send(:remove_const,"#{last_part}".to_sym)
331
+ module_space.const_set(last_part, klass)
332
+ module_space.send(:remove_const,"#{last_part}_ddt".to_sym)
333
+ end
334
+
335
+ def self.generate_for(*klasses_or_instances, &block)
336
+ all_results = {}
337
+ klasses = []
338
+ mock_dict = {}
339
+
340
+ klasses_or_instances.each { |klass_or_instance|
341
+ klass = klass_or_instance.class == Class ? klass_or_instance : klass_or_instance.class
342
+ klasses << replace_class(klass)
343
+
344
+ mock_klasses = []
345
+
346
+ klass._get_mock_classes.each do |mock_klass|
347
+ mock_klasses << replace_class(mock_klass , true)
348
+ end unless klass._get_mock_classes.nil?
349
+
350
+ mock_dict[klass] = mock_klasses
351
+ }
352
+
353
+ watch_new_instances
354
+
355
+ block.call
356
+
357
+ unwatch_new_instances
358
+
359
+ klasses.each { |module_space, klass, last_part, newStandInKlass|
360
+
361
+ #restore the previous class
362
+ restore_class module_space, klass, last_part
363
+
364
+ mock_dict[klass].each do |_module_space, _klass, _last_part, _newStandInKlass|
365
+ restore_class _module_space, _klass, _last_part
366
+ end
367
+
368
+ generator = test_generator.new
369
+ generator.begin_spec(klass)
370
+ num = 1
371
+
372
+ newStandInKlass._instances.each do |instance|
373
+ generator.generate(instance, num)
374
+ num+=1
375
+ end unless newStandInKlass._instances.nil?
376
+
377
+ generator.end_spec
378
+
379
+ result = all_results[klass]
380
+ if result.nil?
381
+ all_results[klass] = []
382
+ end
383
+
384
+ all_results[klass] = generator.output
385
+
386
+ } unless klasses.nil?
387
+
388
+ all_results
389
+ end
390
+
391
+ def self.watch_new_instances
392
+ Object.class_eval do
393
+ def _get_init_arguments
394
+ @_init_arguments
395
+ end
396
+
397
+ def _set_init_arguments(*args, &block)
398
+ @_init_arguments = @_init_arguments || {}
399
+ @_init_arguments[:params] = args
400
+ unless (block.nil?)
401
+ @_init_arguments[:block] = RecordedProc.new(block) {}
402
+ end
403
+ @_variable_names= {}
404
+
405
+ index = 0
406
+ params = method(:initialize).parameters
407
+
408
+ args.each do |arg|
409
+ p = params[index]
410
+ if p.size > 1
411
+ @_variable_names[arg.object_id] = p[1].to_s
412
+ end unless p.nil?
413
+ index+=1
414
+ end unless args.nil?
415
+
416
+ end
417
+
418
+ def _variable_map
419
+ @_variable_names
420
+ end
421
+
422
+ def _deconstruct
423
+ Pretentious::Deconstructor.new().deconstruct(self)
424
+ end
425
+
426
+ def _deconstruct_to_ruby(indentation = 0)
427
+ Pretentious::Deconstructor.new().deconstruct_to_ruby(indentation, _variable_map, {}, self)
428
+ end
429
+
430
+ end
431
+
432
+ Class.class_eval do
433
+ alias_method :_ddt_old_new, :new
434
+
435
+ def new(*args, &block)
436
+ instance = _ddt_old_new(*args, &block)
437
+ instance._set_init_arguments(*args, &block)
438
+ instance
439
+ end
440
+
441
+ end
442
+ end
443
+
444
+ def self.clean_watches
445
+ Class.class_eval do
446
+ remove_method :new
447
+ alias_method :new, :_ddt_old_new
448
+ end
449
+ end
450
+
451
+ def self.unwatch_new_instances
452
+ Class.class_eval do
453
+ remove_method :new
454
+ alias_method :new, :_ddt_old_new
455
+ end
456
+ end
457
+
458
+ end
459
+
460
+ end