rutema 2.0.1 → 2.0.3

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.
@@ -1,6 +1,6 @@
1
1
  # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
2
 
3
- require 'patir/command'
3
+ require "patir/command"
4
4
 
5
5
  module Rutema
6
6
  ##
@@ -20,11 +20,11 @@ module Rutema
20
20
  # * +value+ - the initial value of the attribute
21
21
  #
22
22
  # If +symbol+ is neither a string nor a symbol this method will be a no-op.
23
- def attribute symbol,value
24
- @attributes||=Hash.new
23
+ def attribute(symbol, value)
24
+ @attributes ||= {}
25
25
  case symbol
26
- when String then @attributes[:"#{symbol}"]=value
27
- when Symbol then @attributes[symbol]=value
26
+ when String then @attributes[:"#{symbol}"] = value
27
+ when Symbol then @attributes[symbol] = value
28
28
  end
29
29
  end
30
30
 
@@ -37,29 +37,33 @@ module Rutema
37
37
  # object.attribute= will set the attribute to the right operand and
38
38
  # object.has_attribute? will return +true+ or +false+ according to the
39
39
  # existence of the attribute.
40
- def method_missing symbol,*args
41
- @attributes||=Hash.new
42
- key=symbol.id2name.chomp('?').chomp('=').sub(/^has_/,"")
43
- @attributes[:"#{key}"]=args[0] if key+"="==symbol.id2name
44
- if @attributes.has_key?(:"#{key}")
45
- return true if "has_"+key+"?"==symbol.id2name
46
- return @attributes[:"#{key}"]
40
+ def method_missing(symbol, *args)
41
+ @attributes ||= {}
42
+ key = symbol.id2name.chomp("?").chomp("=").sub(/^has_/, "")
43
+ @attributes[:"#{key}"] = args[0] if "#{key}=" == symbol.id2name
44
+ if @attributes.key?(:"#{key}")
45
+ return true if "has_#{key}?" == symbol.id2name
46
+
47
+ return @attributes[:"#{key}"]
47
48
  else
48
- return false if "has_"+key+"?"==symbol.id2name
49
- super(symbol,*args)
49
+ return false if "has_#{key}?" == symbol.id2name
50
+
51
+ super
50
52
  end
51
53
  end
52
54
 
55
+ def respond_to_missing?(*_args)
56
+ true
57
+ end
58
+
53
59
  ##
54
60
  # Return +true+ if the object responds to the given method or else +false+
55
- def respond_to? symbol,include_all
56
- @attributes||=Hash.new
57
- key=symbol.id2name.chomp('?').chomp('=').sub(/^has_/,"")
58
- if @attributes.has_key?(:"#{key}")
59
- return true
60
- else
61
- super(symbol,include_all)
62
- end
61
+ def respond_to?(symbol, include_all)
62
+ @attributes ||= {}
63
+ key = symbol.id2name.chomp("?").chomp("=").sub(/^has_/, "")
64
+ return true if @attributes.key?(:"#{key}")
65
+
66
+ super
63
67
  end
64
68
  end
65
69
 
@@ -70,6 +74,7 @@ module Rutema
70
74
  include SpecificationElement
71
75
 
72
76
  attr_accessor :scenario
77
+
73
78
  ##
74
79
  # Expects a Hash of parameters
75
80
  #
@@ -88,16 +93,14 @@ module Rutema
88
93
  # :version - The version of this specification
89
94
  #
90
95
  # Default values are empty strings and arrays. (scenario is nil)
91
- def initialize params
92
- begin
93
- @attributes=params
94
- end if params
95
- @attributes||=Hash.new
96
- @attributes[:name]||=""
97
- @attributes[:title]||=""
98
- @attributes[:filename]||=""
99
- @attributes[:description]||=""
100
- @scenario=@attributes[:scenario]
96
+ def initialize(params)
97
+ @attributes = params if params
98
+ @attributes ||= {}
99
+ @attributes[:name] ||= ""
100
+ @attributes[:title] ||= ""
101
+ @attributes[:filename] ||= ""
102
+ @attributes[:description] ||= ""
103
+ @scenario = @attributes[:scenario]
101
104
  end
102
105
 
103
106
  ##
@@ -107,93 +110,90 @@ module Rutema
107
110
  end
108
111
  end
109
112
 
110
- #A Rutema::Scenario is a sequence of Rutema::Step instances.
113
+ # A Rutema::Scenario is a sequence of Rutema::Step instances.
111
114
  #
112
- #Rutema::Step instances are run in the definition sequence and the scenario
113
- #is succesfull when all steps are succesfull.
115
+ # Rutema::Step instances are run in the definition sequence and the scenario
116
+ # is succesfull when all steps are succesfull.
114
117
  #
115
- #From the execution point of view each step is either succesfull or failed and it depends on
116
- #the exit code of the step's command.
118
+ # From the execution point of view each step is either succesfull or failed and it depends on
119
+ # the exit code of the step's command.
117
120
  #
118
- #Failure in a step results in the interruption of execution and the report of the errors.
121
+ # Failure in a step results in the interruption of execution and the report of the errors.
119
122
  class Scenario
120
123
  include SpecificationElement
121
124
 
122
- attr_reader :steps
123
-
124
- def initialize steps
125
- @attributes=Hash.new
126
- @steps=steps
127
- @steps||=Array.new
128
- end
125
+ attr_accessor :steps
129
126
 
130
- #Adds a step at the end of the step sequence
131
- def add_step step
132
- @steps<<step
127
+ def initialize(steps)
128
+ @attributes = {}
129
+ @steps = steps
130
+ @steps ||= []
133
131
  end
134
132
 
135
- #Overwrites the step sequence
136
- def steps= array_of_steps
137
- @steps=array_of_steps
133
+ # Adds a step at the end of the step sequence
134
+ def add_step(step)
135
+ @steps << step
138
136
  end
137
+
138
+ # Overwrites the step sequence
139
139
  end
140
140
 
141
- #Represents a step in a Scenario.
141
+ # Represents a step in a Scenario.
142
142
  #
143
- #Each Rutema::Step can have text and a command associated with it.
143
+ # Each Rutema::Step can have text and a command associated with it.
144
144
  #
145
- #Step standard attributes are.
145
+ # Step standard attributes are.
146
146
  #
147
- #attended - the step can only run in attended mode, it requires user input.
147
+ # attended - the step can only run in attended mode, it requires user input.
148
148
  #
149
- #step_type - a string identifying the type of the step. It is "step" by default.
149
+ # step_type - a string identifying the type of the step. It is "step" by default.
150
150
  #
151
- #ignore - set to true if the step's success or failure is to be ignored. It essentially means that the step is always considered succesfull
151
+ # ignore - set to true if the step's success or failure is to be ignored. It essentially means that the step is always considered succesfull
152
152
  #
153
- #continue - set to true if the step's success or failure is to be recognized, but following steps in the same scenario are to be carried out regardless
153
+ # continue - set to true if the step's success or failure is to be recognized, but following steps in the same scenario are to be carried out regardless
154
154
  # of if indicates test failure, but ensures any further state is carried out as needed
155
155
  #
156
156
  # skip_on_error - if the test case has been marked a failure, skip steps marked with this attribute
157
157
  #
158
- #number - this is set when the step is assigned to a Scenario and is the sequence number
158
+ # number - this is set when the step is assigned to a Scenario and is the sequence number
159
159
  #
160
- #cmd - the command associated with this step. This should quack like Patir::Command.
160
+ # cmd - the command associated with this step. This should quack like Patir::Command.
161
161
  #
162
- #status - one of :not_executed, :success, :warning, :error. Encapsulates the underlying command's status
162
+ # status - one of :not_executed, :success, :warning, :error. Encapsulates the underlying command's status
163
163
  #
164
164
  #==Dynamic behaviour
165
165
  #
166
- #A Rutema::Step can be queried dynamicaly about the attributes it posesses:
166
+ # A Rutema::Step can be queried dynamicaly about the attributes it posesses:
167
167
  # step.has_script? - will return true if script is step's attribute.
168
- #Attribute's are mostly assigned by the parser, i.e. the Rutema::BaseXMLParser from the XML element
168
+ # Attribute's are mostly assigned by the parser, i.e. the Rutema::BaseXMLParser from the XML element
169
169
  # <test script="some_script"/>
170
- #will create a Step instance with step_type=="test" and script="some_script". In this case
170
+ # will create a Step instance with step_type=="test" and script="some_script". In this case
171
171
  #
172
172
  # step.has_script? returns true
173
173
  # step.script returns "some_script"
174
174
  #
175
- #Just like an OpenStruct, Step attributes will be created by direct assignment:
175
+ # Just like an OpenStruct, Step attributes will be created by direct assignment:
176
176
  # step.script="some_script" creates the script attribute if it does not exist.
177
177
  #
178
- #See Rutema::SpecificationElement for the implementation details.
178
+ # See Rutema::SpecificationElement for the implementation details.
179
179
  class Step
180
180
  include SpecificationElement
181
181
  include Patir::Command
182
-
183
- #_txt_ describes the step, _cmd_ is the command to run
184
- def initialize txt="",cmd=nil
185
- @attributes=Hash.new
186
- #ignore is off by default
187
- @attributes[:ignore]=false
182
+
183
+ # _txt_ describes the step, _cmd_ is the command to run
184
+ def initialize(txt = "", cmd = nil)
185
+ @attributes = {}
186
+ # ignore is off by default
187
+ @attributes[:ignore] = false
188
188
  # continue is off by default
189
189
  @attributes[:continue] = false
190
190
  # skip_on_error is off by default
191
- @attributes[:skip_on_error]=false
192
- #assign
193
- @attributes[:cmd]=cmd if cmd
194
- @attributes[:text]=txt
195
- @number=0
196
- @attributes[:step_type]="step"
191
+ @attributes[:skip_on_error] = false
192
+ # assign
193
+ @attributes[:cmd] = cmd if cmd
194
+ @attributes[:text] = txt
195
+ @number = 0
196
+ @attributes[:step_type] = "step"
197
197
  end
198
198
 
199
199
  def name
@@ -202,83 +202,100 @@ module Rutema
202
202
 
203
203
  def output
204
204
  return "" unless @attributes[:cmd]
205
+
205
206
  return @attributes[:cmd].output
206
207
  end
207
208
 
208
209
  def error
209
210
  return "no command associated" unless @attributes[:cmd]
211
+
210
212
  return @attributes[:cmd].error
211
213
  end
212
214
 
213
215
  def backtrace
214
216
  return "no backtrace associated" unless @attributes[:cmd]
215
217
  return @attributes[:cmd].backtrace if @attributes[:cmd].respond_to?(:backtrace)
218
+
216
219
  return ""
217
220
  end
218
221
 
219
222
  def skip_on_error?
220
223
  return false unless @attributes[:skip_on_error]
224
+
221
225
  return @attributes[:skip_on_error]
222
226
  end
223
227
 
224
228
  def ignore?
225
229
  return false unless @attributes[:ignore]
230
+
226
231
  return @attributes[:ignore]
227
232
  end
228
233
 
229
234
  def continue?
230
235
  return false unless @attributes[:continue]
236
+
231
237
  return @attributes[:continue]
232
238
  end
233
239
 
234
240
  def exec_time
235
241
  return 0 unless @attributes[:cmd]
242
+
236
243
  return @attributes[:cmd].exec_time
237
244
  end
238
245
 
239
246
  def status
240
247
  return :warning unless @attributes[:cmd]
248
+
241
249
  return @attributes[:cmd].status
242
250
  end
243
251
 
244
- def status= st
245
- @attributes[:cmd].status=st if @attributes[:cmd]
252
+ def status=(stts)
253
+ @attributes[:cmd].status = stts if @attributes[:cmd]
246
254
  end
247
255
 
248
- def run context=nil
256
+ def run(context = nil)
249
257
  return not_executed unless @attributes[:cmd]
258
+
250
259
  return @attributes[:cmd].run(context)
251
260
  end
252
261
 
253
262
  def reset
254
- @attributes[:cmd].reset if @attributes[:cmd]
263
+ @attributes[:cmd]&.reset
255
264
  end
256
265
 
257
266
  def name_with_parameters
258
- param=" - #{self.cmd.to_s}" if self.has_cmd?
267
+ param = " - #{cmd}" if has_cmd?
259
268
  return "#{@attributes[:step_type]}#{param}"
260
269
  end
261
270
 
262
- def to_s#:nodoc:
263
- if self.has_cmd?
264
- msg="#{self.number} - #{self.cmd.to_s}"
271
+ def to_s # :nodoc:
272
+ if has_cmd?
273
+ msg = "#{number} - #{cmd}"
265
274
  else
266
- msg="#{self.number} - #{self.name}"
275
+ msg = "#{number} - #{name}"
267
276
  end
268
- msg<<" in #{self.included_in}" if self.has_included_in?
277
+ msg << " in #{included_in}" if has_included_in?
269
278
  return msg
270
279
  end
271
280
  end
272
281
  end
273
282
 
274
- class Patir::ShellCommand
275
- def to_s#:nodoc:
276
- return @command
283
+ # rubocop:disable-next Style/OneClassPerFile
284
+ # Class functionality extensions - ye old good monkey patch
285
+ module Patir
286
+ # Decorates the class with a to_s
287
+ class ShellCommand
288
+ # :nodoc:
289
+ def to_s
290
+ return @command
291
+ end
277
292
  end
278
- end
279
293
 
280
- class Patir::RubyCommand
281
- def to_s#:nodoc:
282
- return @name
294
+ # Decorates the class with a to_s
295
+ class RubyCommand
296
+ # :nodoc:
297
+ def to_s
298
+ return @name
299
+ end
283
300
  end
284
301
  end
@@ -1,6 +1,6 @@
1
1
  # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
2
 
3
- require_relative 'framework'
3
+ require_relative "framework"
4
4
 
5
5
  module Rutema
6
6
  ##
@@ -23,9 +23,9 @@ module Rutema
23
23
  ##
24
24
  # Initialize a new instance internally storing and validating the passed
25
25
  # Configuration instance
26
- def initialize configuration
27
- @configuration=configuration
28
- @configuration||={}
26
+ def initialize(configuration)
27
+ @configuration = configuration
28
+ @configuration ||= {}
29
29
  validate_configuration
30
30
  end
31
31
 
@@ -34,15 +34,15 @@ module Rutema
34
34
  #
35
35
  # The passed argument can either be the path to a test specification file
36
36
  # or the test specification itself.
37
- def parse_specification param
38
- raise ParserError,"not implemented. You should derive a parser implementation from SpecificationParser!"
37
+ def parse_specification(_param)
38
+ raise ParserError, "not implemented. You should derive a parser implementation from SpecificationParser!"
39
39
  end
40
40
 
41
41
  ##
42
42
  # Parse a setup specification
43
43
  #
44
44
  # This calls #parse_specification by default.
45
- def parse_setup param
45
+ def parse_setup(param)
46
46
  parse_specification(param)
47
47
  end
48
48
 
@@ -50,7 +50,7 @@ module Rutema
50
50
  # Parse a teardown specification
51
51
  #
52
52
  # This calls #parse_specification by default.
53
- def parse_teardown param
53
+ def parse_teardown(param)
54
54
  parse_specification(param)
55
55
  end
56
56
 
@@ -59,8 +59,7 @@ module Rutema
59
59
  # internally
60
60
  #
61
61
  # To avoid validating the configuration in element_* methods repeatedly, do all configuration validation here
62
- def validate_configuration
63
- end
62
+ def validate_configuration; end
64
63
  end
65
64
  end
66
65
  end
@@ -24,32 +24,31 @@ module Rutema
24
24
  #
25
25
  # * +configuration+ - the Configuration instance of the test run
26
26
  # * +dispatcher+ - unused
27
- def initialize configuration,dispatcher
28
- @configuration=configuration
27
+ def initialize(configuration, _dispatcher)
28
+ @configuration = configuration
29
29
  end
30
30
 
31
31
  ##
32
32
  #
33
- def report specifications,states,errors
34
- end
33
+ def report(specifications, states, errors); end
35
34
  end
36
35
 
37
36
  ##
38
37
  # Event reporters receive and process information continually during a test
39
38
  # run
40
39
  class EventReporter
41
- def initialize configuration,dispatcher
42
- @configuration=configuration
43
- @queue=dispatcher.subscribe(self.object_id)
40
+ def initialize(configuration, dispatcher)
41
+ @configuration = configuration
42
+ @queue = dispatcher.subscribe(object_id)
44
43
  end
45
44
 
46
45
  def run!
47
- @thread=Thread.new do
48
- while true do
49
- data=@queue.pop
46
+ @thread = Thread.new do
47
+ loop do
48
+ data = @queue.pop
50
49
  begin
51
50
  update(data) if data
52
- rescue
51
+ rescue StandardError
53
52
  puts "#{self.class} failed with #{$!.message}"
54
53
  raise
55
54
  end
@@ -57,104 +56,111 @@ module Rutema
57
56
  end
58
57
  end
59
58
 
60
- def update data
61
- end
59
+ def update(data); end
62
60
 
63
61
  def exit
64
62
  puts "Exiting #{self.class}" if $DEBUG
65
- if @thread
66
- puts "Reporter died with #{@queue.size} messages in the queue" unless @thread.alive?
67
- while @queue.size>0 && @thread.alive? do
68
- sleep 0.1
69
- end
70
- Thread.kill(@thread)
71
- end
63
+ return unless @thread
64
+
65
+ puts "Reporter died with #{@queue.size} messages in the queue" unless @thread.alive?
66
+ sleep 0.1 while !@queue.empty? && @thread.alive?
67
+ Thread.kill(@thread)
72
68
  end
73
69
  end
74
- #This reporter is always instantiated and collects all messages fired by the rutema engine
70
+
71
+ # This reporter is always instantiated and collects all messages fired by the rutema engine
75
72
  #
76
- #The collections of errors and states are then at the end of a run fed to the block reporters
77
- class Collector<EventReporter
78
- attr_reader :errors,:states
79
- def initialize params,dispatcher
80
- super(params,dispatcher)
81
- @errors=[]
82
- @states={}
73
+ # The collections of errors and states are then at the end of a run fed to the block reporters
74
+ class Collector < EventReporter
75
+ attr_reader :errors, :states
76
+
77
+ def initialize(params, dispatcher)
78
+ super
79
+ @errors = []
80
+ @states = {}
83
81
  end
84
82
 
85
- def update message
83
+ def update(message)
86
84
  case message
87
85
  when RunnerMessage
88
- test_state=@states[message.test]
86
+ test_state = @states[message.test]
89
87
  if test_state
90
- test_state<<message
88
+ test_state << message
91
89
  else
92
- test_state=Rutema::ReportState.new(message)
90
+ test_state = Rutema::ReportState.new(message)
93
91
  end
94
- @states[message.test]=test_state
92
+ @states[message.test] = test_state
95
93
  when ErrorMessage
96
- @errors<<message
94
+ @errors << message
97
95
  end
98
96
  end
99
97
  end
100
- #A very simple event reporter that outputs to the console
98
+
99
+ # A very simple event reporter that outputs to the console
101
100
  #
102
- #It has three settings: off, normal and verbose.
101
+ # It has three settings: off, normal and verbose.
103
102
  #
104
- #Example configuration:
103
+ # Example configuration:
105
104
  # cfg.reporter={:class=>Rutema::Reporters::Console, "mode"=>"verbose"}
106
- class Console<EventReporter
107
- def initialize configuration,dispatcher
108
- super(configuration,dispatcher)
109
- @mode=configuration.reporters.fetch(self.class,{})["mode"]
105
+ class Console < EventReporter
106
+ def initialize(configuration, dispatcher)
107
+ super
108
+ @mode = configuration.reporters.fetch(self.class, {})["mode"]
110
109
  end
111
- def update message
112
- unless @mode=="off"
113
- case message
114
- when RunnerMessage
115
- if message.status == :error
116
- puts "FATAL|#{message.to_s}"
117
- elsif message.status == :warning
118
- puts "WARNING|#{message.to_s}"
119
- else
120
- puts "#{message.to_s} #{message.status}." if @mode=="verbose"
121
- end
122
- when ErrorMessage
123
- puts message.to_s
124
- when Message
125
- puts message.to_s if @mode=="verbose"
110
+
111
+ # rubocop:disable Metrics/CyclomaticComplexity
112
+ def update(message)
113
+ return if @mode == "off"
114
+
115
+ case message
116
+ when RunnerMessage
117
+ if message.status == :error
118
+ puts "FATAL|#{message}"
119
+ elsif message.status == :warning
120
+ puts "WARNING|#{message}"
121
+ elsif @mode == "verbose"
122
+ puts "#{message} #{message.status}."
126
123
  end
124
+ when ErrorMessage
125
+ puts message
126
+ when Message
127
+ puts message if @mode == "verbose"
127
128
  end
128
129
  end
129
130
  end
131
+ # rubocop:enable Metrics/CyclomaticComplexity
130
132
 
131
- class Summary<BlockReporter
132
- def initialize configuration,dispatcher
133
- super(configuration,dispatcher)
134
- @silent=configuration.reporters.fetch(self.class,{})["silent"]
133
+ # Produces a summary of the test run returning aggregate numbers for tests and failures
134
+ class Summary < BlockReporter
135
+ def initialize(configuration, dispatcher)
136
+ super
137
+ @silent = configuration.reporters.fetch(self.class, {})["silent"]
135
138
  end
136
- def report specs,states,errors
137
- failures=[]
138
- states.each{|k,v| failures<<v.test if v.status==:error}
139
+
140
+ # rubocop:disable-next Metrics/CyclomaticComplexity
141
+ def report(specs, states, errors)
142
+ failures = []
143
+ states.each_value { |v| failures << v.test if v.status == :error }
139
144
 
140
145
  unless @silent
141
- count_tests_run = states.select { |name, state| !state.is_special }.count
146
+ count_tests_run = states.reject { |_name, state| state.is_special }.count
142
147
  puts "#{errors.size} errors. #{count_tests_run} test cases executed. #{failures.size} failed"
143
148
  unless failures.empty?
144
149
  puts "Failures:"
145
- puts specs.map{|spec| " #{spec.name} - #{spec.filename}" if failures.include?(spec.name)}.compact.join("\n")
150
+ puts specs.map { |spec| " #{spec.name} - #{spec.filename}" if failures.include?(spec.name) }.compact.join("\n")
146
151
  end
147
152
  end
148
- return failures.size+errors.size
153
+ return failures.size + errors.size
149
154
  end
150
155
  end
151
156
  end
152
157
 
158
+ # rubocop:disable-next Style/Documentation
153
159
  module Utilities
154
160
  require "fileutils"
155
- def self.write_file filename,content
156
- FileUtils.mkdir_p(File.dirname(filename),:verbose=>false)
157
- File.open(filename, 'wb') {|f| f.write(content) }
158
- end
161
+ def self.write_file(filename, content)
162
+ FileUtils.mkdir_p(File.dirname(filename), :verbose => false)
163
+ File.binwrite(filename, content)
164
+ end
159
165
  end
160
166
  end