lopata 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2b0067b5742eab7448c34b716f1db223a6928e72
4
- data.tar.gz: 3379c61e391b95c415be5df25eafae54adf6b6ae
2
+ SHA256:
3
+ metadata.gz: 6cd685207d7486c0cda7d76e5bbb0276b5af0e0ff73446e4d6866b49e5a8dbc5
4
+ data.tar.gz: 54350543eddacf904531c311dd301858ae4cb42830edef735daed97417956b42
5
5
  SHA512:
6
- metadata.gz: 37b97a6646174b527f5b62e4ff2140227fe8a57da199d36f06bfd8f30d45dd584640417f9225bbb00e1736711531c609df471c51a6e02dc4fc8551e974e7ff03
7
- data.tar.gz: 8d0004668ce2c2f64f7a05b8454c244e9e283119072ece0b54a986846fe57ef7bd376096ac6d038f44a1982a48622687abaa3f63982fb13a59812758e60bd9e7
6
+ metadata.gz: 34ac0e832ac235f88371a44773a9f2df2f87b8099d9857300761dcf4ba6fc81da2386988684253d80e2d4d423457cd6b60e59cf152895b44468276ae1c667284
7
+ data.tar.gz: e287063637735bf244f351396457f07857426fc568d269e6be6fd1de07f94df18c5bd29cca3aa53c8ffd1c81007f9c0b64c5cd4d96616d441f8f143611e300b7
@@ -1,2 +1,13 @@
1
1
  require 'lopata/id'
2
2
  require 'lopata/config'
3
+ require 'lopata/scenario'
4
+
5
+ module Lopata
6
+ def self.define(*args, &block)
7
+ Lopata::Scenario.define(*args, &block)
8
+ end
9
+
10
+ def self.xdefine(*args, &block)
11
+ Lopata::Scenario.xdefine(*args, &block)
12
+ end
13
+ end
@@ -3,7 +3,7 @@ module Lopata
3
3
  extend self
4
4
 
5
5
  attr_accessor :build_number, :lopata_host, :lopata_code, :only_roles, :role_descriptions, :after_as,
6
- :default_role, :ops
6
+ :default_role, :ops, :after_scenario
7
7
 
8
8
  def init(env)
9
9
  require 'yaml'
@@ -1 +1 @@
1
- Capybara.default_driver = :selenium if defined? Capybara
1
+ Capybara.default_driver = :selenium if defined? Capybara
@@ -1,7 +1,7 @@
1
1
  module Lopata
2
2
  module RSpec
3
3
  module Version
4
- STRING = '0.0.15'
4
+ STRING = '0.0.16'
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,393 @@
1
+ class Lopata::Scenario
2
+ def self.define(title = nil, metadata = nil, &block)
3
+ scenario = new
4
+ scenario.title(title) if title
5
+ scenario.metadata(metadata) if metadata
6
+ scenario.instance_exec &block
7
+ scenario.build_rspec
8
+ end
9
+
10
+ # Do noting. Exclude defined scenario from suite.
11
+ def self.xdefine(*attrs)
12
+ end
13
+
14
+ def build_rspec
15
+ option_combinations.each do |option_set|
16
+ args = prepare_args(option_set)
17
+ raise "scenario required a name in first argument" unless args.first.is_a? String
18
+ steps = @steps
19
+ spec = RSpec.describe(*args)
20
+ spec.send :extend, RSpecInjections
21
+ spec.nested_with_as(*args) do
22
+ steps.each do |block|
23
+ instance_exec &block
24
+ end
25
+ if Lopata::Config.after_scenario
26
+ instance_exec &Lopata::Config.after_scenario
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ def as(*args, &block)
33
+ @roles = args.flatten
34
+ @roles << CalculatedValue.new(&block) if block_given?
35
+ @role_options = nil
36
+ end
37
+
38
+ def role_options
39
+ @role_options ||= build_role_options
40
+ end
41
+
42
+ def metadata(hash)
43
+ raise 'metadata expected to be a Hash' unless hash.is_a?(Hash)
44
+ @common_metadata ||= {}
45
+ @common_metadata.merge! hash
46
+ end
47
+
48
+ def without_user
49
+ @without_user = true
50
+ end
51
+
52
+ def skip_when(&block)
53
+ @skip_when = block
54
+ end
55
+
56
+ def skip?(option_set)
57
+ @skip_when && @skip_when.call(option_set)
58
+ end
59
+
60
+ %i{setup action it context teardown include_context include_examples}.each do |name|
61
+ name_if = "%s_if" % name
62
+ name_unless = "%s_unless" % name
63
+ define_method name, ->(*args, &block) { add_step(name, *args, &block) }
64
+ define_method name_if, ->(condition, *args, &block) { add_if_step(name, condition, *args, &block) }
65
+ define_method name_unless, ->(condition, *args, &block) { add_unless_step(name, condition, *args, &block) }
66
+ end
67
+
68
+ def cleanup(*args, &block)
69
+ add_step_as_is(:cleanup, *args, &block)
70
+ end
71
+
72
+ def add_step(method_name, *args, &block)
73
+ @steps ||= []
74
+ @steps << Proc.new do
75
+ # will be called in context of rspec group
76
+ flat_args = args.flatten
77
+ flat_args = Lopata::Scenario.separate_args(flat_args) if method_name =~ /^(setup|action)/
78
+ converted_args = Lopata::Scenario.convert_args(metadata, *flat_args)
79
+ send method_name, *converted_args, &block
80
+ end
81
+ end
82
+
83
+ def add_if_step(method_name, condition, *args, &block)
84
+ @steps ||= []
85
+ @steps << Proc.new do
86
+ # will be called in context of rspec group
87
+ if match_metadata?(condition)
88
+ flat_args = args.flatten
89
+ flat_args = Lopata::Scenario.separate_args(flat_args) if method_name =~ /^(setup|action)/
90
+ converted_args = Lopata::Scenario.convert_args(metadata, *flat_args)
91
+ send method_name, *converted_args, &block
92
+ end
93
+ end
94
+ end
95
+
96
+ def add_unless_step(method_name, condition, *args, &block)
97
+ @steps ||= []
98
+ @steps << Proc.new do
99
+ # will be called in context of rspec group
100
+ unless match_metadata?(condition)
101
+ flat_args = args.flatten
102
+ flat_args = Lopata::Scenario.separate_args(flat_args) if method_name =~ /^(setup|action)/
103
+ converted_args = Lopata::Scenario.convert_args(metadata, *flat_args)
104
+ send method_name, *converted_args, &block
105
+ end
106
+ end
107
+ end
108
+
109
+ def add_step_as_is(method_name, *args, &block)
110
+ @steps ||= []
111
+ @steps << Proc.new do
112
+ # do not convert args - symbols mean name of instance variable
113
+ send method_name, *args, &block
114
+ end
115
+ end
116
+
117
+ def let_metadata(*keys)
118
+ @steps ||= []
119
+ @steps << Proc.new do
120
+ m = metadata
121
+ keys.each do |key|
122
+ define_method key do
123
+ m[key]
124
+ end
125
+
126
+ define_singleton_method key do
127
+ m[key]
128
+ end
129
+ end
130
+ end
131
+ end
132
+
133
+ def let_method(method_name, &block)
134
+ @steps ||= []
135
+ @steps << Proc.new do
136
+ define_method method_name, &block
137
+ define_singleton_method method_name, &block
138
+ end
139
+ end
140
+
141
+ def steps(&block)
142
+ @steps ||= []
143
+ @steps << block
144
+ end
145
+
146
+ def steps_if(metadata_key, &block)
147
+ @steps ||= []
148
+ @steps << Proc.new do
149
+ if match_metadata?(metadata_key)
150
+ instance_exec &block
151
+ end
152
+ end
153
+ end
154
+ alias steps_for steps_if
155
+
156
+ def steps_unless(metadata_key, &block)
157
+ @steps ||= []
158
+ @steps << Proc.new do
159
+ unless match_metadata?(metadata_key)
160
+ instance_exec &block
161
+ end
162
+ end
163
+ end
164
+ alias steps_for_not steps_unless
165
+
166
+ def self.convert_args(metadata, *args)
167
+ args.map do |arg|
168
+ case arg
169
+ # trait symbols as link to metadata.
170
+ when Symbol then metadata[arg]
171
+ else
172
+ arg
173
+ end
174
+ end.flatten
175
+ end
176
+
177
+ def self.separate_args(args)
178
+ args.map { |a| a.is_a?(String) && a =~ /,/ ? a.split(',').map(&:strip) : a }.flatten
179
+ end
180
+
181
+ def build_role_options
182
+ return [] unless roles
183
+ [Diagonal.new(:as, roles.map { |r| [nil, r] })]
184
+ end
185
+
186
+ def roles
187
+ return false if @without_user
188
+ @roles ||= [Lopata::Config.default_role].compact
189
+ end
190
+
191
+ def title(value)
192
+ @title = value
193
+ end
194
+
195
+ def option(metadata_key, variants)
196
+ options << Option.new(metadata_key, variants)
197
+ end
198
+
199
+ def diagonal(metadata_key, variants)
200
+ diagonals << Diagonal.new(metadata_key, variants)
201
+ end
202
+
203
+ def options
204
+ @options ||= []
205
+ end
206
+
207
+ def diagonals
208
+ @diagonals ||= []
209
+ end
210
+
211
+ def option_combinations
212
+ combinations = combine([OptionSet.new], options + diagonals + role_options)
213
+ while !(diagonals + role_options).all?(&:complete?)
214
+ combinations << OptionSet.new(*(options + diagonals + role_options).map(&:next_variant))
215
+ end
216
+ combinations.reject { |option_set| skip?(option_set) }
217
+ end
218
+
219
+ def combine(source_combinations, rest_options)
220
+ # raise 'source_combinations cannot be empty' if source_combinations.blank?
221
+ return source_combinations if rest_options.blank?
222
+ combinations = []
223
+ current_option = rest_options.shift
224
+ source_combinations.each do |source_variants|
225
+ current_option.level_variants.each do |v|
226
+ combinations << (source_variants + OptionSet.new(v))
227
+ end
228
+ end
229
+ combine(combinations, rest_options)
230
+ end
231
+
232
+ def prepare_args(option_set, *args)
233
+ options_title, metadata = option_set.title, option_set.metadata
234
+ if args[0].is_a? String
235
+ args[0] = [@title, options_title, args[0]].reject(&:blank?).join(' ')
236
+ else
237
+ args.unshift([@title, options_title].reject(&:blank?).join(' '))
238
+ end
239
+
240
+ metadata.merge!(@common_metadata) if @common_metadata
241
+
242
+ if args.last.is_a? Hash
243
+ args.last.merge!(metadata)
244
+ else
245
+ args << metadata
246
+ end
247
+ args
248
+ end
249
+
250
+ # Набор вариантов, собранный для одного теста
251
+ class OptionSet
252
+ attr_reader :variants
253
+ def initialize(*variants)
254
+ @variants = {}
255
+ variants.each { |v| self << v }
256
+ end
257
+
258
+ def +(other_set)
259
+ self.class.new(*@variants.values).tap do |sum|
260
+ other_set.each { |v| sum << v }
261
+ end
262
+ end
263
+
264
+ def <<(variant)
265
+ @variants[variant.key] = variant
266
+ end
267
+
268
+ def [](key)
269
+ @variants[key]
270
+ end
271
+
272
+ def each(&block)
273
+ @variants.values.each(&block)
274
+ end
275
+
276
+ def title
277
+ @variants.values.map(&:title).compact.join(' ')
278
+ end
279
+
280
+ def metadata
281
+ @variants.values.inject({}) do |metadata, variant|
282
+ metadata.merge(variant.metadata(self))
283
+ end
284
+ end
285
+ end
286
+
287
+ class Variant
288
+ attr_reader :key, :title, :value
289
+
290
+ def initialize(key, title, value)
291
+ @key, @title, @value = key, title, check_lambda_arity(value)
292
+ end
293
+
294
+ def metadata(option_set)
295
+ data = { key => value }
296
+ if value.is_a? Hash
297
+ value.each do |k, v|
298
+ sub_key = "%s_%s" % [key, k]
299
+ data[sub_key.to_sym] = v
300
+ end
301
+ end
302
+
303
+ data.each do |key, v|
304
+ data[key] = v.calculate(option_set) if v.is_a? CalculatedValue
305
+ end
306
+ data
307
+ end
308
+
309
+ def self.join(variants)
310
+ title, metadata = nil, {}
311
+ variants.each do |v|
312
+ title = [title, v.title].compact.join(' ')
313
+ metadata.merge!(v.metadata)
314
+ end
315
+ [title, metadata]
316
+ end
317
+
318
+ private
319
+
320
+ # Лямдда будет передаваться как блок в instance_eval, которому плохеет, если пришло что-то с нулевой
321
+ # arity. Поэтому для лямбд с нулевой arity делаем arity == 1
322
+ def check_lambda_arity(v)
323
+ if v.is_a?(Proc) && v.arity == 0
324
+ ->(_) { instance_exec(&v) }
325
+ else
326
+ v
327
+ end
328
+ end
329
+ end
330
+
331
+ class CalculatedValue
332
+ def initialize(&block)
333
+ @proc = block
334
+ end
335
+
336
+ def calculate(option_set)
337
+ @proc.call(option_set)
338
+ end
339
+ end
340
+
341
+ class Option
342
+ attr_reader :variants
343
+ def initialize(key, variants)
344
+ @variants =
345
+ if variants.is_a? Hash
346
+ variants.map { |title, value| Variant.new(key, title, value) }
347
+ else
348
+ # Array of arrays of two elements
349
+ variants.map { |v| Variant.new(key, *v) }
350
+ end
351
+ end
352
+
353
+ # Variants to apply at one level
354
+ def level_variants
355
+ variants
356
+ end
357
+
358
+ def next_variant
359
+ @current ||= 0
360
+ selected_variant = variants[@current]
361
+ @current += 1
362
+ if @current >= variants.length
363
+ @current = 0
364
+ @complete = true # all variants have been selected
365
+ end
366
+ selected_variant
367
+ end
368
+ end
369
+
370
+ class Diagonal < Option
371
+ def level_variants
372
+ [next_variant]
373
+ end
374
+
375
+ def complete?
376
+ @complete
377
+ end
378
+ end
379
+
380
+ # RSpec helpers for spec builing
381
+ module RSpecInjections
382
+ def match_metadata?(metadata_key)
383
+ case metadata_key
384
+ when Hash
385
+ metadata_key.keys.all? { |k| metadata[k] == metadata_key[k] }
386
+ when Array
387
+ metadata_key.map { |key| metadata[key] }.none?(&:nil?)
388
+ else
389
+ metadata[metadata_key]
390
+ end
391
+ end
392
+ end
393
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lopata
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.15
4
+ version: 0.0.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey Volochnev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-09 00:00:00.000000000 Z
11
+ date: 2020-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -63,6 +63,7 @@ files:
63
63
  - lib/lopata/rspec/role.rb
64
64
  - lib/lopata/rspec/version.rb
65
65
  - lib/lopata/runner.rb
66
+ - lib/lopata/scenario.rb
66
67
  homepage: https://github.com/avolochnev/lopata
67
68
  licenses:
68
69
  - MIT
@@ -82,9 +83,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
82
83
  - !ruby/object:Gem::Version
83
84
  version: '0'
84
85
  requirements: []
85
- rubyforge_project:
86
- rubygems_version: 2.5.2
86
+ rubygems_version: 3.0.3
87
87
  signing_key:
88
88
  specification_version: 4
89
- summary: lopata-0.0.15
89
+ summary: lopata-0.0.16
90
90
  test_files: []