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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a5e0e4c18d2eab07c25f48a69bcdc1b107be341d
4
- data.tar.gz: 2c7b678e57ff73713a0aa1dda240144650203351
2
+ SHA256:
3
+ metadata.gz: b7b895aa680e7df981e4915c65427164a6c0f3e423d7381adcb286c8c625ee11
4
+ data.tar.gz: eb6409e8c312f835dedd4f5f35588113a870b166eef9d73a8f7a84f4ae4c5101
5
5
  SHA512:
6
- metadata.gz: 60f93501c1a3c659effff6f8c3eed6bd2f9e0b1384df14629c92b599d6c2ce57dede0491de2679ca7231a42a77e61269ed822e9531d69815a2ccdc4a6e02f87a
7
- data.tar.gz: ec9a4ab8dd76ef4dcd606008d02cd9e00bd7786948b44a860ae45f4676c9128c2802418b3ea0566a7ea24c63d3d17cca33e8c18cdc874ad0ab06f5c5fb2f3624
6
+ metadata.gz: 3f7af65c99c671f3622287ed11ea0cd6fdd95539e339a0cf52561a974cd08f60fd9d57ae9f92328c45d3eb5ba26e37b99ff2d2a6309cee7c14c323cff16567e6
7
+ data.tar.gz: 0f5a684b9fca67d3b9cb6fed542996e27dc43229f77b87154da5d41bb27d88085f5d3335c747cdab6671e2a69eca929d768cf2a4f4730235db1127d05f94069f
data/History.txt CHANGED
@@ -1,3 +1,5 @@
1
+ == 2.0.1 2026-03-02
2
+ * Release the 10 year old changes that fix handling of execution context within steps
1
3
  == 2.0.0/ 2017-09-23
2
4
  * Parsing behaviour has changed, parsing errors are not accepted and the run fails immediately
3
5
  == 2.0.0.pre15 /2017-02-08
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  ## rutema
2
- [![Build Status](https://secure.travis-ci.org/damphyr/rutema.png)](http://travis-ci.org/damphyr/rutema) [![Coverage Status](https://coveralls.io/repos/damphyr/rutema/badge.svg)](https://coveralls.io/r/damphyr/rutema) [![Code Climate](https://codeclimate.com/github/damphyr/rutema.png)](https://codeclimate.com/github/damphyr/rutema) ![doc status](http://inch-ci.org/github/damphyr/rutema.svg?branch=master)
2
+ [![Build Status](https://secure.travis-ci.org/damphyr/rutema.png)](http://travis-ci.org/damphyr/rutema) [![Coverage Status](https://coveralls.io/repos/damphyr/rutema/badge.svg)](https://coveralls.io/r/damphyr/rutema) [![Code Climate](https://codeclimate.com/github/damphyr/rutema.png)](https://codeclimate.com/github/damphyr/rutema) ![doc status](http://inch-ci.org/github/damphyr/rutema.svg?branch=master) [![Gem Version](https://badge.fury.io/rb/rutema.svg)](https://badge.fury.io/rb/rutema)
3
3
 
4
4
  rutema [http://github.com/damphyr/rutema](http://github.com/damphyr/rutema)
5
5
 
@@ -31,7 +31,7 @@ Rutema core provides a reference implementation of a parser for a simple but ext
31
31
  * An [example](doc/EXAMPLE.md) of a (very simple) testing DSL with rutema
32
32
  * High level [description](README.md) of the concepts behind rutema
33
33
 
34
- ## Installation:
34
+ ## Installation
35
35
 
36
36
  * gem install rutema
37
37
 
@@ -41,7 +41,7 @@ The core functionality of rutema depends on the following gems:
41
41
  * [patir](http://github.com/damphyr/patir)
42
42
  * [highline](http://highline.rubyforge.org/)
43
43
 
44
- ## License:
44
+ ## License
45
45
 
46
46
  (The MIT License)
47
47
 
data/bin/rutema CHANGED
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
- # Copyright (c) 2007-2017 Vassilis Rizopoulos. All rights reserved.
2
+
3
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
4
+
3
5
  require 'rutema/application'
4
6
  begin
5
7
  Rutema::App.new(ARGV)
6
8
  rescue Rutema::RutemaError
7
9
  puts $!.message
8
10
  exit 1
9
- end
11
+ end
@@ -1,10 +1,20 @@
1
+ # Copyright (c) 2021 Vassilis Rizopoulos. All rights reserved.
2
+
1
3
  require 'optparse'
4
+
2
5
  require_relative "core/configuration"
3
6
  require_relative "core/engine"
4
7
 
5
8
  module Rutema
6
- #Parses the commandline, sets up the configuration and launches Rutema::Engine
9
+ ##
10
+ # Entry-point class for rutema
11
+ #
12
+ # This class parses the commandline, sets up the internal configuration of
13
+ # rutema accordingly and starts the application flow.
7
14
  class App
15
+ ##
16
+ # Configure and start the application flow according to the passed
17
+ # commandline options
8
18
  def initialize command_line_args
9
19
  parse_command_line(command_line_args)
10
20
  @configuration=Rutema::Configuration.new(@config_file)
@@ -18,7 +28,12 @@ module Rutema
18
28
  @engine=Rutema::Engine.new(@configuration)
19
29
  application_flow
20
30
  end
31
+
21
32
  private
33
+
34
+ ##
35
+ # Define the available commandline options and parse the given commandline
36
+ # accordingly
22
37
  def parse_command_line args
23
38
  args.options do |opt|
24
39
  opt.on("rutema v#{Version::STRING}")
@@ -45,18 +60,21 @@ module Rutema
45
60
  end
46
61
  end
47
62
  end
63
+
64
+ ##
65
+ # Start the application flow
48
66
  def application_flow
49
67
  if @check
50
- #run just the suite setup test
68
+ # run just the suite setup test if requested
51
69
  if @configuration.suite_setup
52
70
  exit @engine.run(@configuration.suite_setup)
53
71
  else
54
72
  raise Rutema::RutemaError,"There is no suite setup test defined in the configuration."
55
73
  end
56
74
  else
57
- #run everything
75
+ # run everything
58
76
  exit @engine.run(@test_identifier)
59
77
  end
60
78
  end
61
79
  end
62
- end
80
+ end
@@ -1,131 +1,260 @@
1
- # Copyright (c) 2007-2017 Vassilis Rizopoulos. All rights reserved.
1
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
+
2
3
  require 'ostruct'
3
4
  require_relative 'parser'
4
5
  require_relative 'reporter'
5
6
  module Rutema
6
- #This module defines the "configuration directives" used in the configuration of Rutema
7
+ ##
8
+ # Mix-in module defining all configuration directives available for rutema
9
+ #
10
+ # === Example
11
+ #
12
+ # A configuration file needs at least definitions of which parser to utilize
13
+ # and which tests to run.
14
+ #
15
+ # rutema configuration files are valid Ruby code and can use the full power of
16
+ # the language including _require_ directives.
17
+ #
18
+ # require "rake/file_list"
19
+ #
20
+ # configure do |cfg|
21
+ # cfg.parser = { :class => Rutema::Parsers::XML }
22
+ # cfg.tests = FileList['all/of/the/tests/**/*.*']
23
+ # end
24
+ module ConfigurationDirectives
25
+ ##
26
+ # Hash of context data which may be utilized throughout test runs
7
27
  #
8
- #Example
9
- #A configuration file needs as a minimum to define which parser to use and which tests to run.
28
+ # This could be used for e.g. tester names, version numbers, etc.
29
+ attr_reader :context
30
+
31
+ ##
32
+ # Parser class which shall be used to parse test specifications
33
+ attr_reader :parser
34
+
35
+ ##
36
+ # A hash of supplementary paths identified by representative names
37
+ attr_reader :paths
38
+
39
+ ##
40
+ # A hash mapping reporter classes to supplementary definitions
41
+ attr_accessor :reporters
42
+
43
+ ##
44
+ # Runner class which shall be used to execute the tests
45
+ attr_reader :runner
46
+
47
+ ##
48
+ # Path to a setup specification which will be run before every test
49
+ # specification (optional)
50
+ attr_reader :setup
51
+
52
+ ##
53
+ # Path to a suite setup specification (optional)
10
54
  #
11
- #Since rutema configuration files are valid Ruby code, you can use the full power of the Ruby language including require directives
55
+ # This will be run before all other test specifications. If it fails no
56
+ # other specifications will be executed.
57
+ attr_reader :suite_setup
58
+
59
+ ##
60
+ # Path to a suite teardown specification (optional)
12
61
  #
13
- # require 'rake'
14
- # configuration.parser={:class=>Rutema::MinimalXMLParser}
15
- # configuration.tests=FileList['all/of/the/tests/**/*.*']
16
- module ConfigurationDirectives
17
- attr_reader :parser,:runner,:tools,:paths,:tests,:context,:setup,:teardown,:suite_setup,:suite_teardown
18
- attr_accessor :reporters
19
- #Adds a hash of values to the tools hash of the configuration
20
- #
21
- #This hash is then accessible in the parser and reporters as a property of the configuration instance
22
- #
23
- #Required keys:
24
- # :name - the name to use for accessing the path in code
25
- #Example:
26
- # configure do |cfg|
27
- # cfg.tool={:name=>"nunit",:path=>"/bin/nunit",:configuration=>{:important=>"info"}}
28
- # end
29
- #
30
- #The path to nunit can then be accessed in the parser as
31
- # @configuration.tools.nunit[:path]
32
- #
33
- #This way you can pass configuration information for the tools you use
62
+ # This will be run after all other test specifications
63
+ attr_reader :suite_teardown
64
+
65
+ ##
66
+ # Path to a teardown specification which will be run after every test
67
+ # specification (optional)
68
+ attr_reader :teardown
69
+
70
+ ##
71
+ # Array of (most probably the paths to) the specifications of the tests to
72
+ # be executed
73
+ #
74
+ # In nearly all cases this would contain only paths but generally this can
75
+ # contain any data intelligible by the test specification parser.
76
+ attr_reader :tests
77
+
78
+ ##
79
+ # Hash containing data for tools indexed by their names
80
+ attr_reader :tools
81
+
82
+ ##
83
+ # Add a hash with arbitrary data concerning one particular tool which can be
84
+ # utilized throughout testing by accessing the +tools+ attribute of classes
85
+ # including this module
86
+ #
87
+ # The hash must include a +:name+ key which will define the key under which
88
+ # the entire passed hash will be stored.
89
+ #
90
+ # New calls only add to the hash. Later calls containing the same +:name+
91
+ # key as earlier ones replace the data these set.
92
+ #
93
+ # === Example
94
+ #
95
+ # configure do |cfg|
96
+ # cfg.tool = { :name => "nunit", :path => "/bin/nunit", :configuration => { :important=>"info" } }
97
+ # end
98
+ #
99
+ # The path to NUnit can be accessed the following way:
100
+ #
101
+ # @configuration.tools["nunit"][:path]
34
102
  def tool= definition
35
103
  raise ConfigurationException,"required key :name is missing from #{definition}" unless definition[:name]
36
104
  @tools[definition[:name]]=definition
37
105
  end
38
- #Adds a path to the paths hash of the configuration
39
- #
40
- #Required keys:
41
- # :name - the name to use for accessing the path in code
42
- # :path - the path
43
- #Example:
44
- # cfg.path={:name=>"sources",:path=>"/src"}
106
+
107
+ ##
108
+ # Add a path indexed by a representative name to the paths attribute
109
+ #
110
+ # A hash is expected which contains a representative name under the +:name+
111
+ # key and the path itself under the +:path+ key.
112
+ #
113
+ # New calls only add to the hash. Later calls containing the same +:name+
114
+ # key as earlier ones replace the data these set.
115
+ #
116
+ # === Example
117
+ #
118
+ # configure do |cfg|
119
+ # cfg.path = { :name => "doc", :path => "/usr/local/share/doc" }
120
+ # end
45
121
  def path= definition
46
122
  raise ConfigurationException,"required key :name is missing from #{definition}" unless definition[:name]
47
123
  raise ConfigurationException,"required key :path is missing from #{definition}" unless definition[:path]
48
124
  @paths[definition[:name]]=definition[:path]
49
125
  end
50
- #Path to the setup specification. (optional)
51
- #
52
- #The setup test runs before every test.
126
+
127
+ ##
128
+ # Path to a setup specification (optional)
129
+ #
130
+ # This setup specification will be run before every test specification.
131
+ #
132
+ # Later calls override earlier ones.
53
133
  def setup= path
54
134
  @setup=check_path(path)
55
135
  end
56
- #Path to the teardown specification. (optional)
57
- #
58
- #The teardown test runs after every test.
136
+
137
+ ##
138
+ # Path to a teardown specification (optional)
139
+ #
140
+ # This teardown specification will be run after every test specification.
141
+ #
142
+ # Later calls override earlier ones.
59
143
  def teardown= path
60
144
  @teardown=check_path(path)
61
145
  end
62
- #Path to the suite setup specification. (optional)
63
- #
64
- #The suite setup test runs once in the beginning of a test run before all the tests.
65
- #
66
- #If it fails no tests are run.
67
- #
68
- #This is also aliased as check= for backwards compatibility
146
+
147
+ ##
148
+ # Path to a suite setup specification (optional)
149
+ #
150
+ # This suite setup specification is executed once in the beginning of a test
151
+ # run before any other specifications. If it fails no other test
152
+ # specifications are executed.
153
+ #
154
+ # This is aliased as #check= for backwards compatibility.
155
+ #
156
+ # Later calls override earlier ones.
69
157
  def suite_setup= path
70
158
  @suite_setup=check_path(path)
71
159
  end
72
160
 
73
161
  alias_method :check,:suite_setup
74
162
  alias_method :check=,:suite_setup=
75
- #Path to the suite teardown specification. (optional)
76
- #
77
- #The suite teardown test runs after all the tests.
163
+
164
+ ##
165
+ # Path to a suite teardown specification (optional)
166
+ #
167
+ # This suite teardown specification is executed once after all other test
168
+ # specifications have been executed.
169
+ #
170
+ # Later calls override earlier ones.
78
171
  def suite_teardown= path
79
172
  @suite_teardown=check_path(path)
80
173
  end
81
- #Hash values for passing data to the system. It's supposed to be used in the reporters and contain
82
- #values such as version numbers, tester names etc.
174
+
175
+ ##
176
+ # Context information which shall be accessible during test execution
177
+ #
178
+ # Data must be passed in form of a hash. In case of key collisions later
179
+ # calls override existing data of colliding keys.
180
+ #
181
+ # This could be used e.g. to pass data as tester names, version numbers,
182
+ # etc. to the reporters.
83
183
  def context= definition
84
184
  @context||=Hash.new
85
185
  raise ConfigurationException,"Only accepting hash values as context_data" unless definition.kind_of?(Hash)
86
186
  @context.merge!(definition)
87
187
  end
88
- #Adds the specification identifiers available to this instance of Rutema
89
- #
90
- #These will usually be files, but they can be anything.
91
- #Essentially this is an Array of strings that mean something to your parser
188
+
189
+ ##
190
+ # Add an array of (paths of) test specifications to be executed
191
+ #
192
+ # Usually an array of file paths would be given. Generally the passed array
193
+ # can contain anything intelligible for the parser.
92
194
  def tests= array_of_identifiers
93
195
  @tests+=array_of_identifiers.map{|f| full_path(f)}
94
196
  end
95
- #A hash defining the parser to use.
96
- #
97
- #The hash is passed as is to the parser constructor and each parser should define the necessary configuration keys.
98
- #
99
- #The only required key from the configurator's point fo view is :class which should be set to the fully qualified name of the class to use.
100
- #
101
- #Example:
102
- # cfg.parser={:class=>Rutema::MinimalXMLParser}
197
+
198
+ ##
199
+ # Set the parser class which shall be used to parse test specifications
200
+ #
201
+ # The only required key is +:class+ which should be set to the fully
202
+ # qualified name of the class to be used for parsing.
203
+ #
204
+ # Later calls overwrite earlier ones.
205
+ #
206
+ # === Example
207
+ #
208
+ # configure do |cfg|
209
+ # cfg.parser = { :class => Rutema::Parsers::XML }
210
+ # end
103
211
  def parser= definition
104
212
  raise ConfigurationException,"required key :class is missing from #{definition}" unless definition[:class]
105
213
  @parser=definition
106
214
  end
107
- #A hash defining the runner to use.
108
- #
109
- #The hash is passed as is to the runner constructor and each runner should define the necessary configuration keys.
110
- #
111
- #The only required key from the configurator's point fo view is :class which should be set to the fully qualified name of the class to use.
112
- #
113
- #Example:
114
- # cfg.runner={:class=>Rutema::Runners::NoOp}
215
+
216
+ ##
217
+ # Set the runner which shall be used to execute the tests
218
+ #
219
+ # Upon construction of the runner the context set through the configuration
220
+ # is being passed to the initializer.
221
+ #
222
+ # The only required key is +:class+ which should be set to the fully
223
+ # qualified name of the class as runner.
224
+ #
225
+ # Later calls overwrite earlier ones.
226
+ #
227
+ # === Example
228
+ #
229
+ # configure do |cfg|
230
+ # cfg.runner = { :class => Rutema::Runners::Default }
231
+ # end
115
232
  def runner= definition
116
233
  raise ConfigurationException,"required key :class is missing from #{definition}" unless definition[:class]
117
234
  @runner=definition
118
235
  end
119
- #Adds a reporter to the configuration.
120
- #
121
- #As with the parser, the only required configuration key is :class and the definition hash is passed to the class' constructor.
122
- #
123
- #Unlike the parser, you can define multiple reporters.
236
+
237
+ ##
238
+ # Add a reporter for the test execution
239
+ #
240
+ # The only required key is +:class+ which should be set to the fully
241
+ # qualified name of the class to be used for reporting.
242
+ #
243
+ # Multiple reporter classes can be set simultaneously.
244
+ #
245
+ # === Example
246
+ #
247
+ # configure do |cfg|
248
+ # cfg.reporters = { :class => Rutema::Reporters::Console }
249
+ # cfg.reporters = { :class => Rutema::Reporters::JUnit }
250
+ # end
124
251
  def reporter= definition
125
252
  raise ConfigurationException,"required key :class is missing from #{definition}" unless definition[:class]
126
253
  @reporters[definition[:class]]=definition
127
254
  end
128
- #:stopdoc
255
+
256
+ ##
257
+ # Initialize member variables which are needed to process a configuration
129
258
  def init
130
259
  @reporters={}
131
260
  @context={}
@@ -133,54 +262,97 @@
133
262
  @tools=OpenStruct.new
134
263
  @paths=OpenStruct.new
135
264
  end
136
- #:startdoc
137
- private
138
- #Checks if a path exists and raises a ConfigurationException if not
265
+
266
+ private
267
+
268
+ ##
269
+ # Check if the given path exists and raise a ConfigurationException if not
139
270
  def check_path path
140
271
  path=File.expand_path(path)
141
272
  raise ConfigurationException,"#{path} does not exist" unless File.exist?(path)
142
273
  return path
143
274
  end
144
- #Gives back a string of key=value,key=value for a hash
275
+
276
+ ##
277
+ # Return a string in the form of "key=value,key=value" for a given hash
145
278
  def definition_string definition
146
279
  msg=Array.new
147
280
  definition.each{|k,v| msg<<"#{k}=#{v}"}
148
281
  return msg.join(",")
149
282
  end
150
283
 
284
+ ##
285
+ # Convert the given filename to an absolute path if the file exists or
286
+ # otherwise return the passed filename as is
151
287
  def full_path filename
152
288
  return File.expand_path(filename) if File.exist?(filename)
153
289
  return filename
154
290
  end
155
291
  end
156
292
 
293
+ ##
294
+ # Exception which is being raised upon errors concerning configurations passed
295
+ # to rutema
296
+ #
297
+ # This may be caused by e.g.:
298
+ #
299
+ # * a file or path could not be found/does not exist
300
+ # * passed hash arguments being of an unexpected/unhandled type
301
+ # * passed hash arguments missing required keys
157
302
  class ConfigurationException<RuntimeError
158
303
  end
159
- #The object we pass around after we load the configuration from file
160
- #
161
- #All relevant methods are in Rutema::ConfigurationDirectives
304
+
305
+ ##
306
+ # Class for reading, parsing and representing the configuration for a rutema
307
+ # test run
308
+ #
309
+ # The instance will be passed around during testing and instruct each
310
+ # component which tests to execute how.
311
+ #
312
+ # Rutema::ConfigurationDirectives defines all relevant methods and attributes.
162
313
  class Configuration
163
314
  include ConfigurationDirectives
315
+
316
+ ##
317
+ # The filename of the root configuration file from which the Configuration
318
+ # instance was built
164
319
  attr_reader :filename
320
+
321
+ ##
322
+ # Create a new instance by parsing the given configuration file
323
+ #
324
+ # * +config_file+ - the configuration file which shall be parsed on
325
+ # initializing the new instance
165
326
  def initialize config_file
166
327
  @filename=config_file
167
328
  init
168
329
  load_configuration(@filename)
169
330
  end
170
331
 
332
+ ##
333
+ # Yield the instance itself if a block is given
334
+ #
335
+ # This can be used e.g. in configuration files to execute a block on the
336
+ # Configuration instance itself (e.g. to modify it through the setter
337
+ # methods of the ConfigurationDirectives module).
171
338
  def configure
172
339
  if block_given?
173
340
  yield self
174
341
  end
175
342
  end
176
- #Loads the configuration from a file
177
- #
178
- #Use this to chain configuration files together
179
- #==Example
180
- #Say you have on configuration file "first.rutema" that contains all the generic directives and several others that change only one or two things.
181
- #
182
- #You can import the first.rutema file in the other configurations with
183
- # import("first.rutema")
343
+
344
+ ##
345
+ # Load and import the configuration from a file
346
+ #
347
+ # This method can be used to chain configuration files together.
348
+ #
349
+ # === Example
350
+ #
351
+ # If there is a configuration file "main.rutema" which contains all the
352
+ # generic directives and several others which modify specific aspects, then
353
+ # the specialized configurations can import the "main.rutema" as follows:
354
+ #
355
+ # import("main.rutema")
184
356
  def import filename
185
357
  fnm = File.expand_path(filename)
186
358
  if File.exist?(fnm)
@@ -189,27 +361,34 @@
189
361
  raise ConfigurationException, "Import error: Can't find #{fnm}"
190
362
  end
191
363
  end
364
+
192
365
  private
366
+
367
+ ##
368
+ # Load the configuration from the file given by +filename+
369
+ #
370
+ # On many common parsing errors a ConfigurationException is being raised.
193
371
  def load_configuration filename
194
372
  begin
195
373
  cfg_txt=File.read(filename)
196
374
  cwd=File.expand_path(File.dirname(filename))
197
- #WORKAROUND for ruby 2.3.1
375
+ # WORKAROUND for ruby 2.3.1
198
376
  fname=File.basename(filename)
199
- #evaluate in the working directory to enable relative paths in configuration
377
+ # evaluate in the working directory to enable relative paths in
378
+ # configuration
200
379
  Dir.chdir(cwd){eval(cfg_txt,binding(),fname,__LINE__)}
201
380
  rescue ConfigurationException
202
- #pass it on, do not wrap again
381
+ # pass it on, do not wrap again
203
382
  raise
204
383
  rescue SyntaxError
205
- #Just wrap the exception so we can differentiate
384
+ # just wrap the exception so we can differentiate
206
385
  raise ConfigurationException.new,"Syntax error in the configuration file '#{filename}':\n#{$!.message}"
207
386
  rescue NoMethodError
208
387
  raise ConfigurationException.new,"Encountered an unknown directive in configuration file '#{filename}':\n#{$!.message}"
209
388
  rescue
210
- #Just wrap the exception so we can differentiate
389
+ # just wrap the exception so we can differentiate
211
390
  raise ConfigurationException.new,"#{$!.message}"
212
391
  end
213
392
  end
214
393
  end
215
- end
394
+ end