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,19 +1,42 @@
1
- # Copyright (c) 2007-2017 Vassilis Rizopoulos. All rights reserved.
1
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
+
2
3
  module Rutema
3
- #Rutema supports two kinds of reporters.
4
+ ##
5
+ # Module for the definition of reporter classes
4
6
  #
5
- #Block (from en bloc) reporters receive data via the report() method at the end of a Rutema run
6
- #while event reporters receive events continuously during a run via the update() method
7
+ # rutema supports two kinds of reporters. Reporters derived from BlockReporter
8
+ # are supposed to receive data via the #report method at the end of a Rutema
9
+ # run. Reporters derived from EventReporter are intended to receive events
10
+ # continuously during a run via the #update method.
7
11
  #
8
- #Nothing prevents you from creating a class that implements both behaviours
12
+ # Nothing permits implementing a reporter class which supports both
13
+ # behaviours.
9
14
  module Reporters
15
+ ##
16
+ # Base class for block reporters
17
+ #
18
+ # Block reporters are invoked at the end/after a test run. They offer means
19
+ # to e.g. print a summary after a test run or create a test report file for
20
+ # CI integration (see Reporters::JUnit as an example).
10
21
  class BlockReporter
22
+ ##
23
+ # Initialize a new instance from the given configuration
24
+ #
25
+ # * +configuration+ - the Configuration instance of the test run
26
+ # * +dispatcher+ - unused
11
27
  def initialize configuration,dispatcher
12
28
  @configuration=configuration
13
29
  end
30
+
31
+ ##
32
+ #
14
33
  def report specifications,states,errors
15
34
  end
16
35
  end
36
+
37
+ ##
38
+ # Event reporters receive and process information continually during a test
39
+ # run
17
40
  class EventReporter
18
41
  def initialize configuration,dispatcher
19
42
  @configuration=configuration
@@ -23,16 +46,13 @@ module Rutema
23
46
  def run!
24
47
  @thread=Thread.new do
25
48
  while true do
26
- if @queue.size>0
27
- data=@queue.pop
28
- begin
29
- update(data) if data
30
- rescue
31
- puts "#{self.class} failed with #{$!.message}"
32
- raise
33
- end
49
+ data=@queue.pop
50
+ begin
51
+ update(data) if data
52
+ rescue
53
+ puts "#{self.class} failed with #{$!.message}"
54
+ raise
34
55
  end
35
- sleep 0.1
36
56
  end
37
57
  end
38
58
  end
@@ -94,8 +114,10 @@ module Rutema
94
114
  when RunnerMessage
95
115
  if message.status == :error
96
116
  puts "FATAL|#{message.to_s}"
117
+ elsif message.status == :warning
118
+ puts "WARNING|#{message.to_s}"
97
119
  else
98
- puts message.to_s if @mode=="verbose"
120
+ puts "#{message.to_s} #{message.status}." if @mode=="verbose"
99
121
  end
100
122
  when ErrorMessage
101
123
  puts message.to_s
@@ -116,7 +138,8 @@ module Rutema
116
138
  states.each{|k,v| failures<<v.test if v.status==:error}
117
139
 
118
140
  unless @silent
119
- puts "#{errors.size} errors. #{states.size} test cases executed. #{failures.size} failed"
141
+ count_tests_run = states.select { |name, state| !state.is_special }.count
142
+ puts "#{errors.size} errors. #{count_tests_run} test cases executed. #{failures.size} failed"
120
143
  unless failures.empty?
121
144
  puts "Failures:"
122
145
  puts specs.map{|spec| " #{spec.name} - #{spec.filename}" if failures.include?(spec.name)}.compact.join("\n")
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2007-2017 Vassilis Rizopoulos. All rights reserved.
1
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
2
 
3
3
  require_relative "framework"
4
4
 
@@ -6,6 +6,7 @@ module Rutema
6
6
  module Runners
7
7
  class Default
8
8
  include Rutema::Messaging
9
+
9
10
  attr_reader :context
10
11
  attr_accessor :setup,:teardown
11
12
  def initialize context,queue
@@ -14,41 +15,67 @@ module Rutema
14
15
  @context=context || Hash.new
15
16
  @queue = queue
16
17
  @number_of_runs=0
18
+ @cleanup_blocks = []
17
19
  end
18
20
 
19
- def run spec
20
- steps=[]
21
- status=:success
22
- state={'start_time'=>Time.now, "sequence_id"=>@number_of_runs,:test=>spec.name}
23
- message(:test=>spec.name,:text=>'started')
24
- if @setup
25
- message(:test=>spec.name,:text=>'setup')
26
- executed_steps,status=run_scenario("_setup_",@setup.scenario,@context)
27
- steps+=executed_steps
28
- end
29
- if status!=:error
30
- message(:test=>spec.name,:text=>'running')
31
- executed_steps,status=run_scenario(spec.name,spec.scenario,@context)
32
- steps+=executed_steps
33
- else
34
- message(:test=>spec.name,'number'=>0,'status'=>:error,'out'=>"Setup failed",'err'=>"",'duration'=>0)
35
- end
36
- state['status']=status
37
- if @teardown
38
- message(:test=>spec.name,:text=>'teardown')
39
- executed_steps,status=run_scenario("_teardown_",@teardown.scenario,@context)
21
+ def run(spec, is_special = false)
22
+ begin
23
+ @context["spec_name"]=spec.name
24
+ steps=[]
25
+ status=:success
26
+ state={'start_time'=>Time.now, "sequence_id"=>@number_of_runs,:test=>spec.name}
27
+ message(:test=>spec.name,:text=>'started')
28
+ if @setup
29
+ message(:test=>spec.name,:text=>'setup')
30
+ executed_steps,setup_status = run_scenario("_setup_", @setup.scenario, @context, true)
31
+ status=setup_status unless STATUS_CODES.find_index(setup_status) < STATUS_CODES.find_index(status)
32
+ steps+=executed_steps
33
+ end
34
+ if status!=:error
35
+ message(:test=>spec.name,:text=>'running')
36
+ executed_steps,testspec_status = run_scenario(spec.name, spec.scenario, @context, is_special)
37
+ status=testspec_status unless STATUS_CODES.find_index(testspec_status) < STATUS_CODES.find_index(status)
38
+ steps+=executed_steps
39
+ else
40
+ message(:test=>spec.name,'number'=>0,'status'=>:error,'out'=>"Setup failed",'err'=>"",'duration'=>0)
41
+ end
42
+ @context['rutema_status']=status
43
+ if @teardown
44
+ message(:test=>spec.name,:text=>'teardown')
45
+ executed_steps,teardown_status = run_scenario("_teardown_", @teardown.scenario, @context, true)
46
+ status=teardown_status unless STATUS_CODES.find_index(teardown_status) < STATUS_CODES.find_index(status)
47
+ end
48
+ @context['rutema_status']=status
49
+ message(:test=>spec.name,:text=>'finished')
50
+ state['status']=status
51
+ state["stop_time"]=Time.now
52
+ state['steps']=steps
53
+ @number_of_runs+=1
54
+ return state
55
+ ensure
56
+ begin
57
+ cleanup_exception = nil
58
+ @cleanup_blocks.each do |cleanup_block|
59
+ # Try all blocks
60
+ begin
61
+ cleanup_block.run(@context) if cleanup_block.respond_to?(:run)
62
+ rescue Exception => e
63
+ # Ignore errors, ensure all cleanup steps are attempted
64
+ cleanup_exception = e
65
+ end
66
+ end
67
+ raise cleanup_exception if !cleanup_exception.nil?
68
+ ensure
69
+ @cleanup_blocks = []
70
+ end
40
71
  end
41
- message(:test=>spec.name,:text=>'finished')
42
- state["stop_time"]=Time.now
43
- state['steps']=steps
44
- @number_of_runs+=1
45
- return state
46
72
  end
47
73
 
48
74
  private
49
- def run_scenario name,scenario,meta
75
+
76
+ def run_scenario(name, scenario, meta, is_special)
50
77
  executed_steps=[]
51
- status=:warning
78
+ status=:skipped
52
79
  begin
53
80
  stps=scenario.steps
54
81
  if stps.empty?
@@ -56,18 +83,45 @@ module Rutema
56
83
  status=:error
57
84
  else
58
85
  stps.each do |s|
59
- executed_steps<<run_step(s,meta)
60
- message(:test=>name,:text=>s.to_s,'number'=>s.number,'status'=>s.status,'out'=>s.output,'err'=>s.error,'duration'=>s.exec_time)
61
- status=s.status
62
- break if :error==s.status
86
+ if status == :error && s.skip_on_error?
87
+ message(:test=>name,:text=>s.to_s,'number'=>s.number,'status'=>:skipped,'is_special'=>is_special)
88
+ else
89
+ message(
90
+ :test => name, :text => s.to_s, 'number' => s.number,
91
+ 'status' => :started, 'is_special' => is_special
92
+ )
93
+ sleep 0.05
94
+ begin
95
+ cache_cleanup(s)
96
+ executed_steps << run_step(s, meta)
97
+ rescue Exception => e
98
+ throw e unless s.continue?
99
+ s.status = :error
100
+ end
101
+ message(
102
+ :test => name, :text => s.to_s, 'number' => s.number,
103
+ 'status' => s.status, 'out' => s.output, 'err' => s.error,
104
+ 'backtrace' => s.backtrace, 'duration' => s.exec_time,
105
+ 'is_special' => is_special
106
+ )
107
+ status=s.status unless STATUS_CODES.find_index(s.status) < STATUS_CODES.find_index(status)
108
+ break if :error == s.status and !s.continue?
109
+ end
63
110
  end
64
111
  end
65
- rescue
112
+ rescue
66
113
  error(name,$!.message)
67
114
  status=:error
68
115
  end
69
116
  return executed_steps,status
70
117
  end
118
+
119
+ def cache_cleanup(step)
120
+ if step.has_cleanup? && step.cleanup.respond_to?(:run)
121
+ @cleanup_blocks << step.cleanup
122
+ end
123
+ end
124
+
71
125
  def run_step step,meta
72
126
  if step.has_cmd? && step.cmd.respond_to?(:run)
73
127
  step.cmd.run(meta)
@@ -80,7 +134,21 @@ module Rutema
80
134
  end
81
135
  end
82
136
 
137
+ ##
138
+ # Fake runner which does not run the passed steps but just sets their
139
+ # execution status to +:success+
140
+ #
141
+ # Steps that do not respond to +:run+ have their status set to +:warning+.
142
+ #
143
+ # Returns the step after "executing" it successfully
83
144
  class NoOp<Default
145
+ ##
146
+ # Simulate running the step by setting its status to +:success+
147
+ #
148
+ # If the step does not respond to +:run+ then +:warning+ is set as its
149
+ # status.
150
+ #
151
+ # * +step+ -
84
152
  def run_step step,meta
85
153
  unless step.has_cmd? && step.cmd.respond_to?(:run)
86
154
  message("No command associated with step '#{step.step_type}'. Step number is #{step.number}")
@@ -91,4 +159,4 @@ module Rutema
91
159
  end
92
160
  end
93
161
  end
94
- end
162
+ end
@@ -1,14 +1,15 @@
1
- # Copyright (c) 2007-2017 Vassilis Rizopoulos. All rights reserved.
1
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
+
2
3
  require 'highline'
4
+
3
5
  module Rutema
4
- #The Elements module provides the namespace for the various modules adding parser functionality
6
+ ##
7
+ # Module providing a namespace for modules which are used to add to a parsers
8
+ # functionality which can then be utilized in test specifications
5
9
  module Elements
6
- #Minimal offers a minimal(chic) set of elements for use in specifications
7
- #
8
- #These are:
9
- # echo
10
- # command
11
- # prompt
10
+ ##
11
+ # Module offering an examplary minimal set of elements for use as steps in
12
+ # test specifications
12
13
  module Minimal
13
14
  #echo prints a message on the screen:
14
15
  # <echo text="A meaningful message"/>
@@ -17,6 +18,7 @@ module Rutema
17
18
  step.cmd=Patir::RubyCommand.new("echo"){|cmd| cmd.error="";cmd.output="#{step.text}";$stdout.puts(cmd.output) ;:success}
18
19
  return step
19
20
  end
21
+
20
22
  #prompt asks the user a yes/no question. Answering yes means the step is succesful.
21
23
  # <prompt text="Do you want fries with that?"/>
22
24
  #
@@ -34,6 +36,7 @@ module Rutema
34
36
  end#do rubycommand
35
37
  return step
36
38
  end
39
+
37
40
  #command executes a shell command
38
41
  # <command cmd="useful_command.exe with parameters", working_directory="some/directory"/>
39
42
  def element_command step
@@ -45,4 +48,4 @@ module Rutema
45
48
  end
46
49
  end
47
50
  end
48
- end
51
+ end
@@ -1,4 +1,5 @@
1
- # Copyright (c) 2007-2017 Vassilis Rizopoulos. All rights reserved.
1
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
+
2
3
  require 'rexml/document'
3
4
  require 'patir/command'
4
5
  require_relative '../core/parser'
@@ -7,14 +8,17 @@ require_relative '../elements/minimal'
7
8
 
8
9
  module Rutema
9
10
  module Parsers
10
- #Rutema::Parsers::XML is a basic XML parser that is easily extended
11
+ ##
12
+ # Basic and easily extendable parser for test specifications in XML format
11
13
  #
12
- #Derive your parser from this class and define for each element 'foo' that you want to parse
13
- #a method element_foo(step)
14
+ # Actual XML specification parsers should be derived from this class and
15
+ # define for each specification element +foo+ to be parsed a method
16
+ # +element_foo+.
14
17
  #
15
- #The method will receive a Rutema::Step instance as a parameter which it should return
18
+ # The method will receive a Rutema::Step instance as a parameter which it should return
16
19
  class XML<SpecificationParser
17
20
  include Rutema::Elements::Minimal
21
+
18
22
  #:nodoc:
19
23
  ELEM_SPEC="specification"
20
24
  #:nodoc:
@@ -23,11 +27,15 @@ module Rutema
23
27
  ELEM_TITLE="specification/title"
24
28
  #:nodoc:
25
29
  ELEM_SCENARIO="specification/scenario"
26
- #Parses __param__ and returns the Rutema::Specification instance
30
+
31
+ ##
32
+ # Pass the given test specification and return a corresponding
33
+ # Specification instance
27
34
  #
28
- #param can be the filename of the specification or the contents of that file.
35
+ # The passed argument can either be the path to a test specification file
36
+ # or the test specification itself.
29
37
  #
30
- #Will throw Rutema::ParserError if something goes wrong
38
+ # This will raise ParserError if an error occurs during parsing.
31
39
  def parse_specification param
32
40
  @parsed||=[]
33
41
  begin
@@ -47,8 +55,17 @@ module Rutema
47
55
  raise Rutema::ParserError,$!.message
48
56
  end
49
57
  end
58
+
50
59
  private
51
- #Parses the XML specification of a testcase and creates the corresponding Rutema::Specification instance
60
+
61
+ ##
62
+ # Parse the XML specification of a testcase and create a corresponding
63
+ # Rutema::Specification instance
64
+ #
65
+ # * +xmltext+ - the actual test specification text which must be an XML
66
+ # document
67
+ # * +filename+ - the filename of the test specification file or the
68
+ # current working directory of the test execution (this
52
69
  def parse_case xmltxt,filename
53
70
  spec=Rutema::Specification.new({})
54
71
  xmldoc=REXML::Document.new( xmltxt )
@@ -71,12 +88,21 @@ module Rutema
71
88
  spec.filename=filename
72
89
  return spec
73
90
  end
74
- #Validates the XML file from our point of view.
91
+
92
+ ##
93
+ # Conduct a simple validation of the XML document by checking if it
94
+ # contains all necessary elements
95
+ #
96
+ # ParserError is being raised if any of the necessary elements is missing.
97
+ #
98
+ # * +xmldoc+ - the text of the XML document to be checked for the
99
+ # necessary elements
75
100
  def validate_case xmldoc
76
101
  raise Rutema::ParserError,"missing #{ELEM_SPEC} element in #{xmldoc}" unless xmldoc.elements[ELEM_SPEC]
77
102
  raise Rutema::ParserError,"missing #{ELEM_DESC} element in #{xmldoc}" unless xmldoc.elements[ELEM_DESC]
78
103
  raise Rutema::ParserError,"missing #{ELEM_TITLE} element in #{xmldoc}" unless xmldoc.elements[ELEM_TITLE]
79
104
  end
105
+
80
106
  #Parses the 'scenario' XML element and returns the Rutema::Scenario instance
81
107
  def parse_scenario xmltxt
82
108
  scenario=Rutema::Scenario.new([])
@@ -103,12 +129,14 @@ module Rutema
103
129
  end
104
130
  return scenario
105
131
  end
132
+
106
133
  #Parses xml and returns the Rutema::Step instance
107
134
  def parse_step xmltxt
108
135
  xmldoc=REXML::Document.new( xmltxt )
109
136
  #any step element
110
137
  step=Rutema::Step.new()
111
138
  step.ignore=false
139
+ step.continue=false
112
140
  xmldoc.root.attributes.each do |attr,value|
113
141
  add_attribute(step,attr,value)
114
142
  end
@@ -116,17 +144,38 @@ module Rutema
116
144
  step.step_type=xmldoc.root.name
117
145
  return step
118
146
  end
147
+
148
+ ##
149
+ # Add an attribute of a given name with the given value to a specification
150
+ # element
151
+ #
152
+ # * +element+ - the specification element the attribute shall be added to
153
+ # * +attr+ - the name of the attribute which shall either be created or
154
+ # whose current value will be overridden
155
+ # * +value+ - the value which shall be set for the attribute
119
156
  def add_attribute element,attr,value
157
+ # If the string is a textual representation of a boolean value ...
120
158
  if boolean?(value)
159
+ # ... convert it to a boolean value
121
160
  element.attribute(attr,eval(value))
122
161
  else
123
162
  element.attribute(attr,value)
124
163
  end
125
164
  end
165
+
166
+ ##
167
+ # Check if attribute_value is a string representing a boolean value
168
+ #
169
+ # This returns +true+ if the string is "true" or "false" or +false+
170
+ # otherwise.
171
+ #
172
+ # * +attribute_value+ - the entity which shall be checked if it's a string
173
+ # representing a boolean value
126
174
  def boolean? attribute_value
127
175
  return true if attribute_value=="true" || attribute_value=="false"
128
176
  return false
129
177
  end
178
+
130
179
  #handles <include_scenario> elements, adding the steps to the current scenario
131
180
  def include_scenario step
132
181
  raise Rutema::ParserError,"missing required attribute file in #{step}" unless step.has_file?
@@ -135,6 +184,9 @@ module Rutema
135
184
  include_content=File.read(step.file)
136
185
  return parse_scenario(include_content)
137
186
  end
187
+
188
+ ##
189
+ #
138
190
  def extension_handling spec
139
191
  #change into the directory the spec is in to handle relative paths correctly
140
192
  Dir.chdir(File.dirname(File.expand_path(spec.filename))) do |path|
@@ -144,7 +196,7 @@ module Rutema
144
196
  begin
145
197
  self.send(:"element_#{step.step_type}",step)
146
198
  rescue
147
- raise ParserError, $!.message
199
+ raise ParserError, ($!.message + "\n" + $@.join("\n"))
148
200
  end#begin
149
201
  elsif @configuration.parser["strict_mode"]
150
202
  raise ParserError,"No command element associated with #{step.step_type}. Missing element_#{step.step_type}"
@@ -1,4 +1,5 @@
1
- # Copyright (c) 2007-2010 Vassilis Rizopoulos. All rights reserved.
1
+ # Copyright (c) 2007-2021 Vassilis Rizopoulos. All rights reserved.
2
+
2
3
  require 'json'
3
4
  require_relative "../core/reporter"
4
5
 
@@ -12,11 +13,12 @@ module Rutema
12
13
  class JSON<Rutema::Reporters::BlockReporter
13
14
  #Default report filename
14
15
  DEFAULT_FILENAME="rutema.results.json"
15
-
16
+
16
17
  def initialize configuration,dispatcher
17
18
  super(configuration,dispatcher)
18
19
  @filename=configuration.reporters.fetch(self.class,{}).fetch("filename",DEFAULT_FILENAME)
19
20
  end
21
+
20
22
  #We get all the data from a test run in here.
21
23
  def report specs,states,errors
22
24
  run_entry={}
@@ -1,4 +1,5 @@
1
- # Copyright (c) 2015 Vassilis Rizopoulos. All rights reserved.
1
+ # Copyright (c) 2015-2021 Vassilis Rizopoulos. All rights reserved.
2
+
2
3
  require 'rexml/document'
3
4
  require_relative "../core/reporter"
4
5
 
@@ -18,16 +19,18 @@ module Rutema
18
19
  # cfg.reporter={:class=>Rutema::Reporters::JUnit,"filename"=>"rutema.junit.xml"}
19
20
  class JUnit<BlockReporter
20
21
  DEFAULT_FILENAME="rutema.results.junit.xml"
21
-
22
+
22
23
  def initialize configuration,dispatcher
23
24
  super(configuration,dispatcher)
24
25
  @filename=configuration.reporters.fetch(self.class,{}).fetch("filename",DEFAULT_FILENAME)
25
26
  end
27
+
26
28
  #We get all the data from a test run in here.
27
29
  def report specs,states,errors
28
30
  cnt=process_data(specs,states,errors)
29
31
  Rutema::Utilities.write_file(@filename,cnt)
30
32
  end
33
+
31
34
  def process_data specs,states,errors
32
35
  tests=[]
33
36
  number_of_failed=0
@@ -49,7 +52,9 @@ module Rutema
49
52
  }
50
53
  return junit_content(tests,attributes,errors)
51
54
  end
55
+
52
56
  private
57
+
53
58
  def test_case name,state
54
59
  #<testcase name="" time=""> => the results from executing a test method
55
60
  # <system-out> => data written to System.out during the test run
@@ -61,19 +66,35 @@ module Rutema
61
66
  element_test=REXML::Element.new("testcase")
62
67
  element_test.add_attributes("name"=>name,"time"=>state.duration,"classname"=>@configuration.context[:config_name])
63
68
  if state.status!=:success
64
- fail=REXML::Element.new("failure")
65
- fail.add_attribute("message","Step #{state.steps.last.number} failed.")
66
- fail.add_text "Step #{state.steps.last.number} failed."
67
- element_test.add_element(fail)
68
- out=REXML::Element.new("system-out")
69
- out.add_text state.steps.last.out
70
- element_test.add_element(out)
71
- err=REXML::Element.new("system-err")
72
- err.add_text state.steps.last.err
73
- element_test.add_element(err)
69
+ failed_steps = state.steps.select {|step| !step.status.nil? && STATUS_CODES.find_index(:success) < STATUS_CODES.find_index(step.status)}
70
+ if !failed_steps.empty?
71
+ failed_steps.each do |step|
72
+ fail=REXML::Element.new("failure")
73
+ fail.add_attribute("message","Step: #{step.text} reported non-success status: #{step.status}.")
74
+ fail.add_text "Step #{step.number} failed."
75
+ element_test.add_element(fail)
76
+ out=REXML::Element.new("system-out")
77
+ out.add_text step.out
78
+ element_test.add_element(out)
79
+ err=REXML::Element.new("system-err")
80
+ err.add_text step.err
81
+ element_test.add_element(err)
82
+ end
83
+ else
84
+ fail.add_attribute("message","Case reported non-success status: #{state.status} without a matching step state.")
85
+ fail.add_text "Case with #{state.steps.last.number} steps failed with no matching failed step."
86
+ element_test.add_element(fail)
87
+ out=REXML::Element.new("system-out")
88
+ out.add_text state.steps.last.out
89
+ element_test.add_element(out)
90
+ err=REXML::Element.new("system-err")
91
+ err.add_text state.steps.last.err
92
+ element_test.add_element(err)
93
+ end
74
94
  end
75
95
  return element_test
76
96
  end
97
+
77
98
  def crash name,message
78
99
  failed=REXML::Element.new("testcase")
79
100
  failed.add_attributes("name"=>name,"classname"=>@configuration.context[:config_name],"time"=>0)
@@ -83,6 +104,7 @@ module Rutema
83
104
  failed.add_element(msg)
84
105
  return failed
85
106
  end
107
+
86
108
  def junit_content tests,attributes,errors
87
109
  element_suite=REXML::Element.new("testsuite")
88
110
  element_suite.add_attributes(attributes)
@@ -90,6 +112,7 @@ module Rutema
90
112
  tests.each{|t| element_suite.add_element(t)}
91
113
  return document(element_suite).to_s
92
114
  end
115
+
93
116
  def document suite
94
117
  xmldoc=REXML::Document.new
95
118
  xmldoc<<REXML::XMLDecl.new
@@ -1,9 +1,24 @@
1
+ # Copyright (c) 2021 Vassilis Rizopoulos. All rights reserved.
2
+
3
+ # frozen_string_literal: true
4
+
5
+ ##
6
+ # The top-level module of rutema encompassing all its functionality.
1
7
  module Rutema
2
- #This module defines the version numbers for the library
8
+ ##
9
+ # Version information of the rutema gem
3
10
  module Version
4
- MAJOR=2
5
- MINOR=0
6
- TINY=0
7
- STRING=[ MAJOR, MINOR, TINY ].join( "." )
11
+ ##
12
+ # The major version of the rutema gem
13
+ MAJOR = 2
14
+ ##
15
+ # The minor version of the rutema gem
16
+ MINOR = 0
17
+ ##
18
+ # The tiny version of the rutema gem
19
+ TINY = 1
20
+ ##
21
+ # The version information of the rutema gem as a string
22
+ STRING = [MAJOR, MINOR, TINY].join(".")
8
23
  end
9
- end
24
+ end