rutema 2.0.0 → 2.0.1

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,222 +1,284 @@
1
- # Copyright (c) 2007-2017 Vassilis Rizopoulos. All rights reserved.
2
- require 'patir/command'
3
-
4
- module Rutema
5
- #This module adds functionality that allows us to
6
- #arbitrarily add attributes to a class and then have
7
- #the accessor methods for these attributes appear automagically.
8
- #
9
- #It will also add a has_attribute? method to query if _attribute_ is part of the object or not.
10
- module SpecificationElement
11
- #adds an attribute to the class with the given __value__. __symbol__ can be a Symbol or a String,
12
- #the rest are silently ignored
13
- def attribute symbol,value
14
- @attributes||=Hash.new
15
- case symbol
16
- when String then @attributes[:"#{symbol}"]=value
17
- when Symbol then @attributes[symbol]=value
18
- end
19
- end
20
- #allows us to call object.attribute, object.attribute=, object.attribute? and object.has_attribute?
21
- #
22
- #object.attribute and object.attribute? will throw NoMethodError if no attribute is set.
23
- #
24
- #object.attribute= will set the attribute to the right operand and
25
- #object.has_attribute? returns false or true according to the existence of the attribute.
26
- def method_missing symbol,*args
27
- @attributes||=Hash.new
28
- key=symbol.id2name.chomp('?').chomp('=').sub(/^has_/,"")
29
- @attributes[:"#{key}"]=args[0] if key+"="==symbol.id2name
30
- if @attributes.has_key?(:"#{key}")
31
- return true if "has_"+key+"?"==symbol.id2name
32
- return @attributes[:"#{key}"]
33
- else
34
- return false if "has_"+key+"?"==symbol.id2name
35
- super(symbol,*args)
36
- end
37
- end
38
-
39
- def respond_to? symbol,include_all
40
- @attributes||=Hash.new
41
- key=symbol.id2name.chomp('?').chomp('=').sub(/^has_/,"")
42
- if @attributes.has_key?(:"#{key}")
43
- return true
44
- else
45
- super(symbol,include_all)
46
- end
47
- end
48
- end
49
- #A Rutema::Specification encompasses all elements required to run a test, the builds used, the scenario to run,
50
- #together with a textual description and information that aids in tracing the test back to the requirements.
51
- class Specification
52
- include SpecificationElement
53
- attr_accessor :scenario
54
- #Expects a Hash of parameters
55
- #
56
- #Following keys have meaning in initialization:
57
- #
58
- #:name - the name of the testcase. Should uniquely identify the testcase
59
- #
60
- #:title - a one liner describing what the testcase does
61
- #
62
- #:filename - the filename describing the testcase
63
- #
64
- #:description - a full textual description for the testcase. To be used in reports and documents
65
- #
66
- #:scenario - An instance of Rutema::Scenario
67
- #
68
- #:version - The version of this specification
69
- #
70
- #Default values are empty strings and arrays. (scenario is nil)
71
- def initialize params
72
- begin
73
- @attributes=params
74
- end if params
75
- @attributes||=Hash.new
76
- @attributes[:name]||=""
77
- @attributes[:title]||=""
78
- @attributes[:filename]||=""
79
- @attributes[:description]||=""
80
- @scenario=@attributes[:scenario]
81
- end
82
- def to_s#:nodoc:
83
- return "#{@attributes[:name]} - #{@attributes[:title]}"
84
- end
85
- end
86
- #A Rutema::Scenario is a sequence of Rutema::Step instances.
87
- #
88
- #Rutema::Step instances are run in the definition sequence and the scenario
89
- #is succesfull when all steps are succesfull.
90
- #
91
- #From the execution point of view each step is either succesfull or failed and it depends on
92
- #the exit code of the step's command.
93
- #
94
- #Failure in a step results in the interruption of execution and the report of the errors.
95
- class Scenario
96
- include SpecificationElement
97
- attr_reader :steps
98
-
99
- def initialize steps
100
- @attributes=Hash.new
101
- @steps=steps
102
- @steps||=Array.new
103
- end
104
- #Adds a step at the end of the step sequence
105
- def add_step step
106
- @steps<<step
107
- end
108
- #Overwrites the step sequence
109
- def steps= array_of_steps
110
- @steps=array_of_steps
111
- end
112
- end
113
- #Represents a step in a Scenario.
114
- #
115
- #Each Rutema::Step can have text and a command associated with it.
116
- #
117
- #Step standard attributes are.
118
- #
119
- #attended - the step can only run in attended mode, it requires user input.
120
- #
121
- #step_type - a string identifying the type of the step. It is "step" by default.
122
- #
123
- #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
124
- #
125
- #number - this is set when the step is assigned to a Scenario and is the sequence number
126
- #
127
- #cmd - the command associated with this step. This should quack like Patir::Command.
128
- #
129
- #status - one of :not_executed, :success, :warning, :error. Encapsulates the underlying command's status
130
- #
131
- #==Dynamic behaviour
132
- #
133
- #A Rutema::Step can be queried dynamicaly about the attributes it posesses:
134
- # step.has_script? - will return true if script is step's attribute.
135
- #Attribute's are mostly assigned by the parser, i.e. the Rutema::BaseXMLParser from the XML element
136
- # <test script="some_script"/>
137
- #will create a Step instance with step_type=="test" and script="some_script". In this case
138
- #
139
- # step.has_script? returns true
140
- # step.script returns "some_script"
141
- #
142
- #Just like an OpenStruct, Step attributes will be created by direct assignment:
143
- # step.script="some_script" creates the script attribute if it does not exist.
144
- #
145
- #See Rutema::SpecificationElement for the implementation details.
146
- class Step
147
- include SpecificationElement
148
- include Patir::Command
149
-
150
- #_txt_ describes the step, _cmd_ is the command to run
151
- def initialize txt="",cmd=nil
152
- @attributes=Hash.new
153
- #ignore is off by default
154
- @attributes[:ignore]=false
155
- #assign
156
- @attributes[:cmd]=cmd if cmd
157
- @attributes[:text]=txt
158
- @number=0
159
- @attributes[:step_type]="step"
160
- end
161
-
162
- def name
163
- return name_with_parameters
164
- end
165
- def output
166
- return "" unless @attributes[:cmd]
167
- return @attributes[:cmd].output
168
- end
169
- def error
170
- return "no command associated" unless @attributes[:cmd]
171
- return @attributes[:cmd].error
172
- end
173
- def ignore?
174
- return false unless @attributes[:ignore]
175
- return @attributes[:ignore]
176
- end
177
- def exec_time
178
- return 0 unless @attributes[:cmd]
179
- return @attributes[:cmd].exec_time
180
- end
181
- def status
182
- return :warning unless @attributes[:cmd]
183
- return @attributes[:cmd].status
184
- end
185
- def status= st
186
- @attributes[:cmd].status=st if @attributes[:cmd]
187
- end
188
- def run context=nil
189
- return not_executed unless @attributes[:cmd]
190
- return @attributes[:cmd].run(context)
191
- end
192
- def reset
193
- @attributes[:cmd].reset if @attributes[:cmd]
194
- end
195
- def name_with_parameters
196
- param=" - #{self.cmd.to_s}" if self.has_cmd?
197
- return "#{@attributes[:step_type]}#{param}"
198
- end
199
- def to_s#:nodoc:
200
- if self.has_cmd?
201
- msg="#{self.number} - #{self.cmd.to_s}"
202
- else
203
- msg="#{self.number} - #{self.name}"
204
- end
205
- msg<<" in #{self.included_in}" if self.has_included_in?
206
- return msg
207
- end
208
- end
209
-
210
- end
211
-
212
- class Patir::ShellCommand
213
- def to_s#:nodoc:
214
- return @command
215
- end
216
- end
217
-
218
- class Patir::RubyCommand
219
- def to_s#:nodoc:
220
- return @name
221
- end
222
- end
1
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
+
3
+ require 'patir/command'
4
+
5
+ module Rutema
6
+ ##
7
+ # Mix-in module allowing to add attributes to a class on the go
8
+ #
9
+ # This allows to add attributes to classes on the go and makes the accessor
10
+ # methods appear automatically too.
11
+ #
12
+ # It will add a #has_attribute? method too to query if an attribute is part of
13
+ # the object or not.
14
+ module SpecificationElement
15
+ ##
16
+ # Add an attribute with a given value to the class instance
17
+ #
18
+ # * +symbol+ - a symbol or a string (which will be converted to a symbol
19
+ # internally) which shall be the name of the new attribute
20
+ # * +value+ - the initial value of the attribute
21
+ #
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
25
+ case symbol
26
+ when String then @attributes[:"#{symbol}"]=value
27
+ when Symbol then @attributes[symbol]=value
28
+ end
29
+ end
30
+
31
+ ##
32
+ # Method enabling to call object.attribute, object.attribute=, object.attribute? and object.has_attribute?
33
+ #
34
+ # object.attribute and object.attribute? will throw NoMethodError if the
35
+ # attribute is not set on the object instance.
36
+ #
37
+ # object.attribute= will set the attribute to the right operand and
38
+ # object.has_attribute? will return +true+ or +false+ according to the
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}"]
47
+ else
48
+ return false if "has_"+key+"?"==symbol.id2name
49
+ super(symbol,*args)
50
+ end
51
+ end
52
+
53
+ ##
54
+ # 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
63
+ end
64
+ end
65
+
66
+ ##
67
+ # A Rutema::Specification encompasses all elements required to run a test, the builds used, the scenario to run,
68
+ # together with a textual description and information that aids in tracing the test back to the requirements.
69
+ class Specification
70
+ include SpecificationElement
71
+
72
+ attr_accessor :scenario
73
+ ##
74
+ # Expects a Hash of parameters
75
+ #
76
+ # Following keys have meaning in initialization:
77
+ #
78
+ # :name - the name of the testcase. Should uniquely identify the testcase
79
+ #
80
+ # :title - a one liner describing what the testcase does
81
+ #
82
+ # :filename - the filename describing the testcase
83
+ #
84
+ # :description - a full textual description for the testcase. To be used in reports and documents
85
+ #
86
+ # :scenario - An instance of Rutema::Scenario
87
+ #
88
+ # :version - The version of this specification
89
+ #
90
+ # 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]
101
+ end
102
+
103
+ ##
104
+ # Create a concise string representation consisting of +name+ and +title+
105
+ def to_s
106
+ return "#{@attributes[:name]} - #{@attributes[:title]}"
107
+ end
108
+ end
109
+
110
+ #A Rutema::Scenario is a sequence of Rutema::Step instances.
111
+ #
112
+ #Rutema::Step instances are run in the definition sequence and the scenario
113
+ #is succesfull when all steps are succesfull.
114
+ #
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.
117
+ #
118
+ #Failure in a step results in the interruption of execution and the report of the errors.
119
+ class Scenario
120
+ include SpecificationElement
121
+
122
+ attr_reader :steps
123
+
124
+ def initialize steps
125
+ @attributes=Hash.new
126
+ @steps=steps
127
+ @steps||=Array.new
128
+ end
129
+
130
+ #Adds a step at the end of the step sequence
131
+ def add_step step
132
+ @steps<<step
133
+ end
134
+
135
+ #Overwrites the step sequence
136
+ def steps= array_of_steps
137
+ @steps=array_of_steps
138
+ end
139
+ end
140
+
141
+ #Represents a step in a Scenario.
142
+ #
143
+ #Each Rutema::Step can have text and a command associated with it.
144
+ #
145
+ #Step standard attributes are.
146
+ #
147
+ #attended - the step can only run in attended mode, it requires user input.
148
+ #
149
+ #step_type - a string identifying the type of the step. It is "step" by default.
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
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
154
+ # of if indicates test failure, but ensures any further state is carried out as needed
155
+ #
156
+ # skip_on_error - if the test case has been marked a failure, skip steps marked with this attribute
157
+ #
158
+ #number - this is set when the step is assigned to a Scenario and is the sequence number
159
+ #
160
+ #cmd - the command associated with this step. This should quack like Patir::Command.
161
+ #
162
+ #status - one of :not_executed, :success, :warning, :error. Encapsulates the underlying command's status
163
+ #
164
+ #==Dynamic behaviour
165
+ #
166
+ #A Rutema::Step can be queried dynamicaly about the attributes it posesses:
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
169
+ # <test script="some_script"/>
170
+ #will create a Step instance with step_type=="test" and script="some_script". In this case
171
+ #
172
+ # step.has_script? returns true
173
+ # step.script returns "some_script"
174
+ #
175
+ #Just like an OpenStruct, Step attributes will be created by direct assignment:
176
+ # step.script="some_script" creates the script attribute if it does not exist.
177
+ #
178
+ #See Rutema::SpecificationElement for the implementation details.
179
+ class Step
180
+ include SpecificationElement
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
188
+ # continue is off by default
189
+ @attributes[:continue] = false
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"
197
+ end
198
+
199
+ def name
200
+ return name_with_parameters
201
+ end
202
+
203
+ def output
204
+ return "" unless @attributes[:cmd]
205
+ return @attributes[:cmd].output
206
+ end
207
+
208
+ def error
209
+ return "no command associated" unless @attributes[:cmd]
210
+ return @attributes[:cmd].error
211
+ end
212
+
213
+ def backtrace
214
+ return "no backtrace associated" unless @attributes[:cmd]
215
+ return @attributes[:cmd].backtrace if @attributes[:cmd].respond_to?(:backtrace)
216
+ return ""
217
+ end
218
+
219
+ def skip_on_error?
220
+ return false unless @attributes[:skip_on_error]
221
+ return @attributes[:skip_on_error]
222
+ end
223
+
224
+ def ignore?
225
+ return false unless @attributes[:ignore]
226
+ return @attributes[:ignore]
227
+ end
228
+
229
+ def continue?
230
+ return false unless @attributes[:continue]
231
+ return @attributes[:continue]
232
+ end
233
+
234
+ def exec_time
235
+ return 0 unless @attributes[:cmd]
236
+ return @attributes[:cmd].exec_time
237
+ end
238
+
239
+ def status
240
+ return :warning unless @attributes[:cmd]
241
+ return @attributes[:cmd].status
242
+ end
243
+
244
+ def status= st
245
+ @attributes[:cmd].status=st if @attributes[:cmd]
246
+ end
247
+
248
+ def run context=nil
249
+ return not_executed unless @attributes[:cmd]
250
+ return @attributes[:cmd].run(context)
251
+ end
252
+
253
+ def reset
254
+ @attributes[:cmd].reset if @attributes[:cmd]
255
+ end
256
+
257
+ def name_with_parameters
258
+ param=" - #{self.cmd.to_s}" if self.has_cmd?
259
+ return "#{@attributes[:step_type]}#{param}"
260
+ end
261
+
262
+ def to_s#:nodoc:
263
+ if self.has_cmd?
264
+ msg="#{self.number} - #{self.cmd.to_s}"
265
+ else
266
+ msg="#{self.number} - #{self.name}"
267
+ end
268
+ msg<<" in #{self.included_in}" if self.has_included_in?
269
+ return msg
270
+ end
271
+ end
272
+ end
273
+
274
+ class Patir::ShellCommand
275
+ def to_s#:nodoc:
276
+ return @command
277
+ end
278
+ end
279
+
280
+ class Patir::RubyCommand
281
+ def to_s#:nodoc:
282
+ return @name
283
+ end
284
+ end
@@ -1,35 +1,66 @@
1
- # Copyright (c) 2007-2017 Vassilis Rizopoulos. All rights reserved.
1
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
+
2
3
  require_relative 'framework'
3
4
 
4
5
  module Rutema
5
- module Parsers
6
- #Base class that bombs out when used.
6
+ ##
7
+ # Module for the definition of classes for the parsing of test specifications
8
+ module Parsers
9
+ ##
10
+ # Base class for parser implementations
11
+ #
12
+ # This class itself is not operational but only throws exceptions upon
13
+ # invocations of its +parse_*+ methods. Its sole purpose is to define a
14
+ # common interface for parser classes.
7
15
  #
8
- #Derive your parser class from this class and implement parse_specification and validate_configuration
16
+ # Derived classes should implement at least the parse_specification and
17
+ # validate_configuration methods.
9
18
  class SpecificationParser
19
+ ##
20
+ # The Configuration instance passed to and used by the initializer
10
21
  attr_reader :configuration
22
+
23
+ ##
24
+ # Initialize a new instance internally storing and validating the passed
25
+ # Configuration instance
11
26
  def initialize configuration
12
27
  @configuration=configuration
13
28
  @configuration||={}
14
29
  validate_configuration
15
30
  end
16
- #parses a specification
31
+
32
+ ##
33
+ # Parse a test specification
34
+ #
35
+ # The passed argument can either be the path to a test specification file
36
+ # or the test specification itself.
17
37
  def parse_specification param
18
38
  raise ParserError,"not implemented. You should derive a parser implementation from SpecificationParser!"
19
39
  end
20
- #parses the setup script. By default calls parse_specification
40
+
41
+ ##
42
+ # Parse a setup specification
43
+ #
44
+ # This calls #parse_specification by default.
21
45
  def parse_setup param
22
46
  parse_specification(param)
23
47
  end
24
- #parses the teardown script. By default calls parse_specification
48
+
49
+ ##
50
+ # Parse a teardown specification
51
+ #
52
+ # This calls #parse_specification by default.
25
53
  def parse_teardown param
26
54
  parse_specification(param)
27
55
  end
28
- #The parser stores it's configuration in @configuration
56
+
57
+ ##
58
+ # Validate the Configuration instance which is stored by the parser
59
+ # internally
29
60
  #
30
- #To avoid validating the configuration in element_* methods repeatedly, do all configuration validation here
61
+ # To avoid validating the configuration in element_* methods repeatedly, do all configuration validation here
31
62
  def validate_configuration
32
63
  end
33
64
  end
34
65
  end
35
- end
66
+ end