rutema 1.3.0 → 2.0.0.pre
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 +7 -0
- data/History.txt +204 -194
- data/Manifest.txt +15 -48
- data/README.md +55 -61
- data/bin/rutema +7 -7
- data/lib/rutema/application.rb +61 -0
- data/lib/rutema/core/configuration.rb +195 -0
- data/lib/rutema/core/engine.rb +186 -0
- data/lib/rutema/core/framework.rb +28 -0
- data/lib/rutema/{objectmodel.rb → core/objectmodel.rb} +43 -48
- data/lib/rutema/core/parser.rb +35 -0
- data/lib/rutema/core/reporter.rb +105 -0
- data/lib/rutema/core/runner.rb +83 -0
- data/lib/rutema/elements/minimal.rb +47 -44
- data/lib/rutema/parsers/xml.rb +154 -186
- data/lib/rutema/version.rb +9 -0
- metadata +39 -108
- data/README.txt +0 -44
- data/Rakefile +0 -30
- data/examples/README.md +0 -17
- data/examples/config/database.rutema +0 -17
- data/examples/config/full.rutema +0 -27
- data/examples/config/minimal.rutema +0 -10
- data/examples/specs/T001.spec +0 -8
- data/examples/specs/T002.spec +0 -8
- data/examples/specs/T003.spec +0 -8
- data/examples/specs/T004.spec +0 -8
- data/examples/specs/T005.spec +0 -10
- data/examples/specs/T006.spec +0 -9
- data/examples/specs/check.spec +0 -8
- data/examples/specs/fail.spec +0 -9
- data/examples/specs/include.scenario +0 -5
- data/examples/specs/rutema.spec +0 -10
- data/examples/specs/setup.spec +0 -8
- data/examples/specs/teardown.spec +0 -8
- data/lib/rutema/configuration.rb +0 -173
- data/lib/rutema/models/activerecord.rb +0 -159
- data/lib/rutema/models/base.rb +0 -5
- data/lib/rutema/parsers/base.rb +0 -45
- data/lib/rutema/rake.rb +0 -62
- data/lib/rutema/reporters/activerecord.rb +0 -82
- data/lib/rutema/reporters/base.rb +0 -23
- data/lib/rutema/reporters/email.rb +0 -84
- data/lib/rutema/reporters/text.rb +0 -77
- data/lib/rutema/runners/default.rb +0 -157
- data/lib/rutema/runners/step.rb +0 -23
- data/lib/rutema/system.rb +0 -302
- data/test/data/duplicate_name.spec +0 -8
- data/test/data/no_title.spec +0 -5
- data/test/data/sample.spec +0 -8
- data/test/data/test_identifiers.rutema +0 -7
- data/test/test_activerecord.rb +0 -0
- data/test/test_configuration.rb +0 -43
- data/test/test_objectmodel.rb +0 -82
- data/test/test_parsers.rb +0 -131
- data/test/test_reporters.rb +0 -115
- data/test/test_runners.rb +0 -70
- data/test/test_system.rb +0 -45
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rutema
|
2
|
+
module Messaging
|
3
|
+
def error identifier,message
|
4
|
+
message(:test=>identifier,:error=>message)
|
5
|
+
end
|
6
|
+
def message message
|
7
|
+
msg=message
|
8
|
+
if message.is_a?(String)
|
9
|
+
msg={:message=>message,:timestamp=>Time.now}
|
10
|
+
elsif message.is_a?(Hash)
|
11
|
+
msg[:timestamp]=Time.now
|
12
|
+
end
|
13
|
+
@queue.push(msg)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
#Generic error class for errors in the engine
|
17
|
+
class RutemaError<RuntimeError
|
18
|
+
end
|
19
|
+
#Is raised when an error is found in a specification
|
20
|
+
class ParserError<RutemaError
|
21
|
+
end
|
22
|
+
#Is raised on an unexpected error during execution
|
23
|
+
class RunnerError<RutemaError
|
24
|
+
end
|
25
|
+
#Errors in reporters should use this class
|
26
|
+
class ReportError<RutemaError
|
27
|
+
end
|
28
|
+
end
|
@@ -1,5 +1,4 @@
|
|
1
|
-
# Copyright (c) 2007-
|
2
|
-
$:.unshift File.join(File.dirname(__FILE__),"..")
|
1
|
+
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
3
2
|
require 'patir/command'
|
4
3
|
|
5
4
|
module Rutema
|
@@ -7,9 +6,10 @@ module Rutema
|
|
7
6
|
#arbitrarily add attributes to a class and then have
|
8
7
|
#the accessor methods for these attributes appear automagically.
|
9
8
|
#
|
10
|
-
#It will also add a has_attribute? method to query if
|
9
|
+
#It will also add a has_attribute? method to query if _attribute_ is part of the object or not.
|
11
10
|
module SpecificationElement
|
12
|
-
#adds an attribute to the class with the given __value__. __symbol__ can be a Symbol or a String,
|
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
13
|
def attribute symbol,value
|
14
14
|
@attributes||=Hash.new
|
15
15
|
case symbol
|
@@ -35,12 +35,24 @@ module Rutema
|
|
35
35
|
super(symbol,*args)
|
36
36
|
end
|
37
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
|
38
48
|
end
|
39
|
-
#A
|
49
|
+
#A Rutema::Specification encompasses all elements required to run a test, the builds used, the scenario to run,
|
40
50
|
#together with a textual description and information that aids in tracing the test back to the requirements.
|
41
|
-
class
|
51
|
+
class Specification
|
42
52
|
include SpecificationElement
|
43
|
-
attr_accessor :scenario
|
53
|
+
attr_accessor :scenario
|
54
|
+
#Expects a Hash of parameters
|
55
|
+
#
|
44
56
|
#Following keys have meaning in initialization:
|
45
57
|
#
|
46
58
|
#:name - the name of the testcase. Should uniquely identify the testcase
|
@@ -51,15 +63,12 @@ module Rutema
|
|
51
63
|
#
|
52
64
|
#:description - a full textual description for the testcase. To be used in reports and documents
|
53
65
|
#
|
54
|
-
#:scenario - An instance of
|
55
|
-
#
|
56
|
-
#:requirements - An Array of String. The idea is that the strings can lead you back to the requirements specification that is tested here.
|
66
|
+
#:scenario - An instance of Rutema::Scenario
|
57
67
|
#
|
58
68
|
#:version - The version of this specification
|
59
69
|
#
|
60
70
|
#Default values are empty strings and arrays. (scenario is nil)
|
61
|
-
def initialize
|
62
|
-
params=args[0] if args
|
71
|
+
def initialize params
|
63
72
|
begin
|
64
73
|
@attributes=params
|
65
74
|
end if params
|
@@ -68,59 +77,44 @@ module Rutema
|
|
68
77
|
@attributes[:title]||=""
|
69
78
|
@attributes[:filename]||=""
|
70
79
|
@attributes[:description]||=""
|
71
|
-
@scenario
|
72
|
-
@requirements||=Array.new
|
80
|
+
@scenario=@attributes[:scenario]
|
73
81
|
end
|
74
82
|
def to_s#:nodoc:
|
75
83
|
return "#{@attributes[:name]} - #{@attributes[:title]}"
|
76
84
|
end
|
77
85
|
end
|
78
|
-
#A
|
86
|
+
#A Rutema::Scenario is a sequence of Rutema::Step instances.
|
79
87
|
#
|
80
|
-
#
|
88
|
+
#Rutema::Step instances are run in the definition sequence and the scenario
|
81
89
|
#is succesfull when all steps are succesfull.
|
82
90
|
#
|
83
91
|
#From the execution point of view each step is either succesfull or failed and it depends on
|
84
92
|
#the exit code of the step's command.
|
85
93
|
#
|
86
94
|
#Failure in a step results in the interruption of execution and the report of the errors.
|
87
|
-
class
|
95
|
+
class Scenario
|
88
96
|
include SpecificationElement
|
89
97
|
attr_reader :steps
|
90
98
|
|
91
|
-
def initialize
|
99
|
+
def initialize steps
|
92
100
|
@attributes=Hash.new
|
93
|
-
|
94
|
-
@
|
95
|
-
@version=version
|
96
|
-
@steps=Array.new
|
101
|
+
@steps=steps
|
102
|
+
@steps||=Array.new
|
97
103
|
end
|
98
|
-
|
99
|
-
def attended?
|
100
|
-
ret=@attributes[:attended]
|
101
|
-
@steps.each do |step|
|
102
|
-
ret=true if step.attended?
|
103
|
-
end
|
104
|
-
return ret
|
105
|
-
end
|
106
|
-
|
104
|
+
#Adds a step at the end of the step sequence
|
107
105
|
def add_step step
|
108
106
|
@steps<<step
|
109
|
-
@attended=true if step.attended?
|
110
107
|
end
|
111
|
-
|
108
|
+
#Overwrites the step sequence
|
112
109
|
def steps= array_of_steps
|
113
110
|
@steps=array_of_steps
|
114
|
-
@steps.each do |step|
|
115
|
-
@attributes[:attended]=true if step.attended?
|
116
|
-
end
|
117
111
|
end
|
118
112
|
end
|
119
|
-
#Represents a step in a
|
113
|
+
#Represents a step in a Scenario.
|
120
114
|
#
|
121
|
-
#Each
|
115
|
+
#Each Rutema::Step can have text and a command associated with it.
|
122
116
|
#
|
123
|
-
#
|
117
|
+
#Step standard attributes are.
|
124
118
|
#
|
125
119
|
#attended - the step can only run in attended mode, it requires user input.
|
126
120
|
#
|
@@ -136,20 +130,20 @@ module Rutema
|
|
136
130
|
#
|
137
131
|
#==Dynamic behaviour
|
138
132
|
#
|
139
|
-
#A
|
133
|
+
#A Rutema::Step can be queried dynamicaly about the attributes it posesses:
|
140
134
|
# step.has_script? - will return true if script is step's attribute.
|
141
135
|
#Attribute's are mostly assigned by the parser, i.e. the Rutema::BaseXMLParser from the XML element
|
142
136
|
# <test script="some_script"/>
|
143
|
-
#will create a
|
137
|
+
#will create a Step instance with step_type=="test" and script="some_script". In this case
|
144
138
|
#
|
145
139
|
# step.has_script? returns true
|
146
140
|
# step.script returns "some_script"
|
147
141
|
#
|
148
|
-
#Just like an OpenStruct,
|
142
|
+
#Just like an OpenStruct, Step attributes will be created by direct assignment:
|
149
143
|
# step.script="some_script" creates the script attribute if it does not exist.
|
150
144
|
#
|
151
145
|
#See Rutema::SpecificationElement for the implementation details.
|
152
|
-
class
|
146
|
+
class Step
|
153
147
|
include SpecificationElement
|
154
148
|
include Patir::Command
|
155
149
|
|
@@ -158,8 +152,6 @@ module Rutema
|
|
158
152
|
@attributes=Hash.new
|
159
153
|
#ignore is off by default
|
160
154
|
@attributes[:ignore]=false
|
161
|
-
#attended is off by default
|
162
|
-
@attributes[:attended]=false
|
163
155
|
#assign
|
164
156
|
@attributes[:cmd]=cmd if cmd
|
165
157
|
@attributes[:text]=txt
|
@@ -206,9 +198,12 @@ module Rutema
|
|
206
198
|
end
|
207
199
|
def to_s#:nodoc:
|
208
200
|
param=""
|
209
|
-
|
210
|
-
|
211
|
-
|
201
|
+
if self.has_cmd?
|
202
|
+
msg="#{self.number} - #{self.cmd.to_s}"
|
203
|
+
else
|
204
|
+
msg="#{self.number} - #{self.name}"
|
205
|
+
end
|
206
|
+
msg<<" in #{self.included_in}" if self.has_included_in?
|
212
207
|
return msg
|
213
208
|
end
|
214
209
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
2
|
+
require_relative 'framework'
|
3
|
+
|
4
|
+
module Rutema
|
5
|
+
module Parsers
|
6
|
+
#Base class that bombs out when used.
|
7
|
+
#
|
8
|
+
#Derive your parser class from this class and implement parse_specification and validate_configuration
|
9
|
+
class SpecificationParser
|
10
|
+
attr_reader :configuration
|
11
|
+
def initialize configuration
|
12
|
+
@configuration=configuration
|
13
|
+
@configuration||={}
|
14
|
+
validate_configuration
|
15
|
+
end
|
16
|
+
#parses a specification
|
17
|
+
def parse_specification param
|
18
|
+
raise ParserError,"not implemented. You should derive a parser implementation from SpecificationParser!"
|
19
|
+
end
|
20
|
+
#parses the setup script. By default calls parse_specification
|
21
|
+
def parse_setup param
|
22
|
+
parse_specification(param)
|
23
|
+
end
|
24
|
+
#parses the teardown script. By default calls parse_specification
|
25
|
+
def parse_teardown param
|
26
|
+
parse_specification(param)
|
27
|
+
end
|
28
|
+
#The parser stores it's configuration in @configuration
|
29
|
+
#
|
30
|
+
#To avoid validating the configuration in element_* methods repeatedly, do all configuration validation here
|
31
|
+
def validate_configuration
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
2
|
+
module Rutema
|
3
|
+
#Rutema supports two kinds of reporters.
|
4
|
+
#
|
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
|
+
#
|
8
|
+
#Nothing prevents you from creating a class that implements both behaviours
|
9
|
+
module Reporters
|
10
|
+
class BlockReporter
|
11
|
+
def initialize configuration,dispatcher
|
12
|
+
@configuration=configuration
|
13
|
+
end
|
14
|
+
def report specifications,states,errors
|
15
|
+
end
|
16
|
+
end
|
17
|
+
class EventReporter
|
18
|
+
def initialize configuration,dispatcher
|
19
|
+
@configuration=configuration
|
20
|
+
@queue=dispatcher.subscribe(self.object_id)
|
21
|
+
end
|
22
|
+
|
23
|
+
def run!
|
24
|
+
@thread=Thread.new do
|
25
|
+
while true do
|
26
|
+
if @queue.size>0
|
27
|
+
data=@queue.pop
|
28
|
+
update(data) if data
|
29
|
+
end
|
30
|
+
sleep 0.1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def update data
|
36
|
+
end
|
37
|
+
|
38
|
+
def exit
|
39
|
+
if @thread
|
40
|
+
while @queue.size>0 do
|
41
|
+
sleep 0.1
|
42
|
+
end
|
43
|
+
Thread.kill(@thread)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Collector<EventReporter
|
49
|
+
attr_reader :errors,:states
|
50
|
+
def initialize params,dispatcher
|
51
|
+
super(params,dispatcher)
|
52
|
+
@errors=[]
|
53
|
+
@states={}
|
54
|
+
end
|
55
|
+
|
56
|
+
def update data
|
57
|
+
if data[:error]
|
58
|
+
@errors<<data
|
59
|
+
elsif data[:test] && data['status']
|
60
|
+
@states[data[:test]]||=[]
|
61
|
+
@states[data[:test]]<<data
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Console<EventReporter
|
67
|
+
def initialize configuration,dispatcher
|
68
|
+
super(configuration,dispatcher)
|
69
|
+
@silent=configuration.reporters.fetch(self.class,{})["silent"]
|
70
|
+
end
|
71
|
+
def update data
|
72
|
+
if data[:error]
|
73
|
+
puts ">ERROR: #{data[:error]}"
|
74
|
+
elsif data[:test]
|
75
|
+
if data["phase"]
|
76
|
+
puts ">#{data["phase"]} #{data[:test]}" unless @silent
|
77
|
+
elsif data[:message]
|
78
|
+
puts ">#{data[:test]} #{data[:message]}" unless @silent
|
79
|
+
elsif data["status"]==:error
|
80
|
+
puts ">FATAL: #{data[:test]}(#{data["number"]}) failed"
|
81
|
+
puts data.fetch("out","")
|
82
|
+
puts data.fetch("error","")
|
83
|
+
end
|
84
|
+
elsif data[:message]
|
85
|
+
puts ">#{data[:message]}" unless @silent
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Summary<BlockReporter
|
91
|
+
def initialize configuration,dispatcher
|
92
|
+
super(configuration,dispatcher)
|
93
|
+
@silent=configuration.reporters.fetch(self.class,{})["silent"]
|
94
|
+
end
|
95
|
+
def report specs,states,errors
|
96
|
+
failures=0
|
97
|
+
states.each do |k,v|
|
98
|
+
failures+=1 if v.last['status']==:error
|
99
|
+
end
|
100
|
+
puts "#{errors.size} errors. #{states.size} test cases executed. #{failures} failed" unless @silent
|
101
|
+
return failures
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
2
|
+
|
3
|
+
require_relative "framework"
|
4
|
+
|
5
|
+
module Rutema
|
6
|
+
module Runners
|
7
|
+
class Default
|
8
|
+
include Rutema::Messaging
|
9
|
+
attr_reader :context
|
10
|
+
attr_accessor :setup,:teardown
|
11
|
+
def initialize context,queue
|
12
|
+
@setup=nil
|
13
|
+
@teardown=nil
|
14
|
+
@context=context || Hash.new
|
15
|
+
@queue = queue
|
16
|
+
@number_of_runs=0
|
17
|
+
end
|
18
|
+
|
19
|
+
def run spec
|
20
|
+
state={'start_time'=>Time.now, "sequence_id"=>@number_of_runs,:test=>spec.name}
|
21
|
+
steps=[]
|
22
|
+
status=:success
|
23
|
+
message(:test=>spec.name,'phase'=>'started')
|
24
|
+
if @setup
|
25
|
+
message(:test=>spec.name,'phase'=>'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,'phase'=>'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,'phase'=>'teardown')
|
39
|
+
executed_steps,status=run_scenario("_teardown_",@teardown.scenario,@context)
|
40
|
+
end
|
41
|
+
message(:test=>spec.name,'phase'=>'finished')
|
42
|
+
state["stop_time"]=Time.now
|
43
|
+
state['steps']=steps
|
44
|
+
@number_of_runs+=1
|
45
|
+
return state
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
def run_scenario name,scenario,meta
|
50
|
+
executed_steps=[]
|
51
|
+
status=:warning
|
52
|
+
begin
|
53
|
+
stps=scenario.steps
|
54
|
+
if stps.empty?
|
55
|
+
error(name,"Scenario #{name} contains no steps")
|
56
|
+
status=:error
|
57
|
+
else
|
58
|
+
stps.each do |s|
|
59
|
+
message(:test=>name,:message=>s.to_s)
|
60
|
+
executed_steps<<run_step(s,meta)
|
61
|
+
message(:test=>name,'number'=>s.number,'status'=>s.status,'out'=>s.output,'err'=>s.error,'duration'=>s.exec_time)
|
62
|
+
status=s.status
|
63
|
+
break if :error==s.status
|
64
|
+
end
|
65
|
+
end
|
66
|
+
rescue
|
67
|
+
error(name,$!.message)
|
68
|
+
status=:error
|
69
|
+
end
|
70
|
+
return executed_steps,status
|
71
|
+
end
|
72
|
+
def run_step step,meta
|
73
|
+
if step.has_cmd? && step.cmd.respond_to?(:run)
|
74
|
+
step.cmd.run(meta)
|
75
|
+
else
|
76
|
+
message("No command associated with step '#{step.step_type}'. Step number is #{step.number}")
|
77
|
+
end
|
78
|
+
step.status=:success if step.status==:error && step.ignore?
|
79
|
+
return step
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -1,45 +1,48 @@
|
|
1
|
-
# Copyright (c) 2007-
|
2
|
-
|
3
|
-
module Rutema
|
4
|
-
#The Elements module provides the namespace for the various modules adding parser functionality
|
5
|
-
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
|
12
|
-
module Minimal
|
13
|
-
#echo prints a message on the screen:
|
14
|
-
# <echo text="A meaningful message"/>
|
15
|
-
# <echo>A meaningful message</echo>
|
16
|
-
def element_echo step
|
17
|
-
step.cmd=Patir::RubyCommand.new("echo"){|cmd| cmd.error="";cmd.output="#{step.text}";$stdout.puts(cmd.output) ;:success}
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
step.
|
26
|
-
|
27
|
-
cmd.
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
1
|
+
# Copyright (c) 2007-2015 Vassilis Rizopoulos. All rights reserved.
|
2
|
+
require 'highline'
|
3
|
+
module Rutema
|
4
|
+
#The Elements module provides the namespace for the various modules adding parser functionality
|
5
|
+
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
|
12
|
+
module Minimal
|
13
|
+
#echo prints a message on the screen:
|
14
|
+
# <echo text="A meaningful message"/>
|
15
|
+
# <echo>A meaningful message</echo>
|
16
|
+
def element_echo step
|
17
|
+
step.cmd=Patir::RubyCommand.new("echo"){|cmd| cmd.error="";cmd.output="#{step.text}";$stdout.puts(cmd.output) ;:success}
|
18
|
+
return step
|
19
|
+
end
|
20
|
+
#prompt asks the user a yes/no question. Answering yes means the step is succesful.
|
21
|
+
# <prompt text="Do you want fries with that?"/>
|
22
|
+
#
|
23
|
+
#A prompt element automatically makes a specification "attended"
|
24
|
+
def element_prompt step
|
25
|
+
step.attended=true
|
26
|
+
step.cmd=Patir::RubyCommand.new("prompt") do |cmd|
|
27
|
+
cmd.output=""
|
28
|
+
cmd.error=""
|
29
|
+
if HighLine.new.agree("#{step.text}")
|
30
|
+
step.output="y"
|
31
|
+
else
|
32
|
+
raise "n"
|
33
|
+
end#if
|
34
|
+
end#do rubycommand
|
35
|
+
return step
|
36
|
+
end
|
37
|
+
#command executes a shell command
|
38
|
+
# <command cmd="useful_command.exe with parameters", working_directory="some/directory"/>
|
39
|
+
def element_command step
|
40
|
+
raise ParserError,"missing required attribute cmd in #{step}" unless step.has_cmd?
|
41
|
+
wd=Dir.pwd
|
42
|
+
wd=step.working_directory if step.has_working_directory?
|
43
|
+
step.cmd=Patir::ShellCommand.new(:cmd=>step.cmd,:working_directory=>File.expand_path(wd))
|
44
|
+
return step
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
45
48
|
end
|