lopata 0.0.15 → 0.0.16

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 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: []