tryouts 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +6 -0
- data/LICENSE.txt +19 -0
- data/README.rdoc +122 -0
- data/Rakefile +80 -0
- data/bin/mockout +49 -0
- data/bin/tryouts +39 -0
- data/lib/tryouts/cli/run.rb +94 -0
- data/lib/tryouts/cli.rb +15 -0
- data/lib/tryouts/drill/response.rb +105 -0
- data/lib/tryouts/drill/sergeant/cli.rb +49 -0
- data/lib/tryouts/drill.rb +98 -0
- data/lib/tryouts/mixins/hash.rb +25 -0
- data/lib/tryouts/mixins.rb +2 -0
- data/lib/tryouts/tryout.rb +171 -0
- data/lib/tryouts.rb +386 -0
- data/tryouts/mockoutcli_dreams.rb +19 -0
- data/tryouts/mockoutcli_dreams.yaml +10 -0
- data/tryouts/mockoutcli_tryouts.rb +26 -0
- data/tryouts.gemspec +75 -0
- metadata +117 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
|
2
|
+
class Hash
|
3
|
+
|
4
|
+
# A depth-first look to find the deepest point in the Hash.
|
5
|
+
# The top level Hash is counted in the total so the final
|
6
|
+
# number is the depth of its children + 1. An example:
|
7
|
+
#
|
8
|
+
# ahash = { :level1 => { :level2 => {} } }
|
9
|
+
# ahash.deepest_point # => 3
|
10
|
+
#
|
11
|
+
def deepest_point(h=self, steps=0)
|
12
|
+
if h.is_a?(Hash)
|
13
|
+
steps += 1
|
14
|
+
h.each_pair do |n,possible_h|
|
15
|
+
ret = deepest_point(possible_h, steps)
|
16
|
+
steps = ret if steps < ret
|
17
|
+
end
|
18
|
+
else
|
19
|
+
return 0
|
20
|
+
end
|
21
|
+
steps
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,171 @@
|
|
1
|
+
|
2
|
+
class Tryouts
|
3
|
+
|
4
|
+
# = Tryout
|
5
|
+
#
|
6
|
+
# A Tryout is a set of drills (each drill is a test).
|
7
|
+
#
|
8
|
+
class Tryout
|
9
|
+
|
10
|
+
# The name of this tryout
|
11
|
+
attr_reader :name
|
12
|
+
|
13
|
+
# A Hash of Dream objects for this Tryout. The keys are drill names.
|
14
|
+
attr_accessor :dreams
|
15
|
+
|
16
|
+
# An Array of Drill objects
|
17
|
+
attr_reader :drills
|
18
|
+
|
19
|
+
# A default value for Drill.dtype
|
20
|
+
attr_reader :dtype
|
21
|
+
|
22
|
+
# For drill type :cli, this is the name of the command to test. It
|
23
|
+
# should be a valid method available to a Rye::Box object.
|
24
|
+
# For drill type :api, this attribute is ignored.
|
25
|
+
attr_reader :command
|
26
|
+
|
27
|
+
# A block to executed one time before starting the drills
|
28
|
+
attr_reader :setup
|
29
|
+
|
30
|
+
# A block to executed one time before starting the drills
|
31
|
+
attr_reader :clean
|
32
|
+
|
33
|
+
@@valid_dtypes = [:cli, :api]
|
34
|
+
|
35
|
+
# All :api Drills are run within this context (not used for :cli).
|
36
|
+
# Each Drill is executed in a new instance of this class. That means
|
37
|
+
# instance variables are not carried through, but class variables are.
|
38
|
+
# The before and after blocks are also run in this context.
|
39
|
+
class DrillContext; end
|
40
|
+
|
41
|
+
def initialize(name, dtype, command=nil, *args)
|
42
|
+
raise "Must supply command for dtype :cli" if dtype == :cli && command.nil?
|
43
|
+
raise "#{dtype} is not a valid drill type" if !@@valid_dtypes.member?(dtype)
|
44
|
+
@name, @dtype, @command = name, dtype, command
|
45
|
+
@drills = []
|
46
|
+
@dreams = {}
|
47
|
+
end
|
48
|
+
|
49
|
+
## --------------------------------------- EXTERNAL API -----
|
50
|
+
|
51
|
+
# Populate this Tryout from a block. The block should contain calls to
|
52
|
+
# the external DSL methods: dream, drill, xdrill
|
53
|
+
def from_block(b=nil, &inline)
|
54
|
+
runtime = b.nil? ? inline : b
|
55
|
+
instance_eval &runtime
|
56
|
+
end
|
57
|
+
|
58
|
+
# Execute all Drill objects
|
59
|
+
def run
|
60
|
+
update_drills! # Ensure all drills have all known dreams
|
61
|
+
DrillContext.class_eval &setup if setup.is_a?(Proc)
|
62
|
+
puts Tryouts::TRYOUT_MSG % @name
|
63
|
+
@drills.each do |drill|
|
64
|
+
drill.run(DrillContext.new) # Returns true or false
|
65
|
+
end
|
66
|
+
DrillContext.class_eval &clean if clean.is_a?(Proc)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Prints error output. If there are no errors, it prints nothing.
|
70
|
+
def report
|
71
|
+
return true if success?
|
72
|
+
failed = @drills.select { |d| !d.success? }
|
73
|
+
failed.each_with_index do |drill,index|
|
74
|
+
|
75
|
+
puts '%sERROR %2d/%-2d in "%s"' % [$/, index+1, failed.size, drill.name]
|
76
|
+
|
77
|
+
if drill.dream
|
78
|
+
puts '%24s: %s (expected %s)' % ["response code", drill.reality.rcode, drill.dream.rcode]
|
79
|
+
puts '%24s: %s' % ["expected output", drill.dream.output.inspect]
|
80
|
+
puts '%24s: %s' % ["actual output", drill.reality.output.inspect]
|
81
|
+
if drill.reality.emsg || (drill.reality.emsg != drill.dream.emsg)
|
82
|
+
puts '%24s: %s' % ["expected error msg", drill.dream.emsg.inspect]
|
83
|
+
puts '%24s: %s' % ["actual error msg", drill.reality.emsg.inspect]
|
84
|
+
end
|
85
|
+
else
|
86
|
+
puts '%24s' % ["[nodream]"]
|
87
|
+
if drill.reality.rcode > 0
|
88
|
+
puts '%24s: %s' % ["rcode", drill.reality.rcode.inspect]
|
89
|
+
puts '%24s: %s' % ["msg", drill.reality.emsg.inspect]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
if drill.reality.rcode > 0
|
94
|
+
puts '%24s: ' % ["backtrace"]
|
95
|
+
puts drill.reality.backtrace, $/
|
96
|
+
end
|
97
|
+
end
|
98
|
+
false
|
99
|
+
end
|
100
|
+
|
101
|
+
# Did every Tryout finish successfully?
|
102
|
+
def success?
|
103
|
+
return @success unless @success.nil?
|
104
|
+
# Returns true only when every Tryout result returns true
|
105
|
+
@success = !(@drills.collect { |r| r.success? }.member?(false))
|
106
|
+
end
|
107
|
+
|
108
|
+
# Add a Drill object to the list for this Tryout. If there is a dream
|
109
|
+
# defined with the same name as the Drill, that dream will be given to
|
110
|
+
# the Drill before its added to the list.
|
111
|
+
def add_drill(d)
|
112
|
+
d.add_dream @dreams[d.name] if !@dreams.nil? && @dreams.has_key?(d.name)
|
113
|
+
drills << d if d.is_a?(Tryouts::Drill)
|
114
|
+
d
|
115
|
+
end
|
116
|
+
|
117
|
+
# Goes through the list of Drill objects (@drills) and gives each
|
118
|
+
# one its associated Dream object (if available).
|
119
|
+
#
|
120
|
+
# This method is called before Tryout#run, but is only necessary in
|
121
|
+
# the case where dreams where loaded after the drills were defined.
|
122
|
+
def update_drills!
|
123
|
+
return if @dreams.nil?
|
124
|
+
@drills.each do |drill|
|
125
|
+
next unless @dreams.has_key?(drill.name)
|
126
|
+
drill.add_dream @dreams[drill.name]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
## --------------------------------------- EXTERNAL DSL -----
|
131
|
+
|
132
|
+
# A block to executed one time _before_ starting the drills
|
133
|
+
def setup(&block)
|
134
|
+
return @setup unless block
|
135
|
+
@setup = block
|
136
|
+
end
|
137
|
+
|
138
|
+
# A block to executed one time _after_ the drills
|
139
|
+
def clean(&block)
|
140
|
+
return @clean unless block
|
141
|
+
@clean = block
|
142
|
+
end
|
143
|
+
|
144
|
+
# +name+ of the Drill associated to this Dream
|
145
|
+
# +output+ A String or Array of expected output. A Dream object will be created using this value (optional)
|
146
|
+
# +definition+ is a block which will be run on an instance of Dream
|
147
|
+
#
|
148
|
+
# NOTE: This method is DSL-only. It's not intended to be used in OO syntax.
|
149
|
+
def dream(name, output=nil, format=nil, rcode=0, emsg=nil, &definition)
|
150
|
+
if output.nil?
|
151
|
+
dobj = Tryouts::Drill::Dream.from_block definition
|
152
|
+
else
|
153
|
+
dobj = Tryouts::Drill::Dream.new(output)
|
154
|
+
dobj.format, dobj.rcode, dobj.emsg = format, rcode, emsg
|
155
|
+
end
|
156
|
+
@dreams[name] = dobj
|
157
|
+
dobj
|
158
|
+
end
|
159
|
+
|
160
|
+
# Create and add a Drill object to the list for this Tryout
|
161
|
+
# +name+ is the name of the drill.
|
162
|
+
# +args+ is sent directly to the Drill class. The values are specific on the Sergeant.
|
163
|
+
def drill(name, *args, &definition)
|
164
|
+
args.unshift(@command) if @dtype == :cli
|
165
|
+
drill = Tryouts::Drill.new(name, @dtype, *args, &definition)
|
166
|
+
add_drill drill
|
167
|
+
end
|
168
|
+
def xdrill(*args, &b); end # ignore calls to xdrill
|
169
|
+
|
170
|
+
|
171
|
+
end; end
|
data/lib/tryouts.rb
ADDED
@@ -0,0 +1,386 @@
|
|
1
|
+
|
2
|
+
require 'rubygems'
|
3
|
+
require 'ostruct'
|
4
|
+
require 'rye'
|
5
|
+
require 'yaml'
|
6
|
+
begin; require 'json'; rescue LoadError; end # json may not be installed
|
7
|
+
|
8
|
+
GYMNASIUM_HOME = File.join(Dir.pwd, 'tryouts')
|
9
|
+
GYMNASIUM_GLOB = File.join(GYMNASIUM_HOME, '**', '*_tryouts.rb')
|
10
|
+
|
11
|
+
|
12
|
+
# = Tryouts
|
13
|
+
#
|
14
|
+
# This class has three purposes:
|
15
|
+
# * It represents the Tryouts object which is a group of Tryout objects.
|
16
|
+
# * The tryouts and dreams DSLs are executed within its namespace. In general the
|
17
|
+
# class methods are the handlers for the DSL syntax (some instance getter methods
|
18
|
+
# are modified to support DSL syntax by acting like setters when given arguments)
|
19
|
+
# * It stores all known instances of Tryouts objects in a class variable @@instances.
|
20
|
+
#
|
21
|
+
# ==== Are you ready to run some drills?
|
22
|
+
#
|
23
|
+
# May all your dreams come true!
|
24
|
+
#
|
25
|
+
class Tryouts
|
26
|
+
# = Exception
|
27
|
+
# A generic exception which all other Tryouts exceptions inherit from.
|
28
|
+
class Exception < RuntimeError; end
|
29
|
+
# = BadDreams
|
30
|
+
# Raised when there is a problem loading or parsing a Tryouts::Drill::Dream object
|
31
|
+
class BadDreams < Exception; end
|
32
|
+
|
33
|
+
VERSION = "0.4.0"
|
34
|
+
|
35
|
+
require 'tryouts/mixins'
|
36
|
+
require 'tryouts/tryout'
|
37
|
+
require 'tryouts/drill'
|
38
|
+
|
39
|
+
require 'tryouts/orderedhash'
|
40
|
+
HASH_TYPE = (RUBY_VERSION =~ /1.9/) ? ::Hash : Tryouts::OrderedHash
|
41
|
+
|
42
|
+
TRYOUT_MSG = "\n %s "
|
43
|
+
DRILL_MSG = ' %30s: '
|
44
|
+
DRILL_ERR = ' %s: '
|
45
|
+
|
46
|
+
# An Array of +_tryouts.rb+ file paths that have been loaded.
|
47
|
+
@@loaded_files = []
|
48
|
+
# An Hash of Tryouts instances stored under the name of the Tryouts subclass.
|
49
|
+
@@instances = HASH_TYPE.new
|
50
|
+
|
51
|
+
# The name of this group of Tryout objects
|
52
|
+
attr_accessor :group
|
53
|
+
# A Symbol representing the default drill type. One of: :cli, :api
|
54
|
+
attr_accessor :dtype
|
55
|
+
# An Array of file paths which populated this instance of Tryouts
|
56
|
+
attr_accessor :paths
|
57
|
+
# A Hash of dreams for all tryouts in this class. The keys should
|
58
|
+
# match the names of each tryout. The values are hashes will drill
|
59
|
+
# names as keys and response
|
60
|
+
attr_accessor :dreams
|
61
|
+
# An Array of Tryout objects
|
62
|
+
attr_accessor :tryouts
|
63
|
+
# A Symbol representing the command taking part in the tryouts. For @dtype :cli only.
|
64
|
+
attr_accessor :command
|
65
|
+
# A Symbol representing the name of the library taking part in the tryouts. For @dtype :api only.
|
66
|
+
attr_accessor :library
|
67
|
+
# The name of the most recent dreams group (see self.dream)
|
68
|
+
attr_accessor :dream_pointer
|
69
|
+
|
70
|
+
# Returns +@@instances+
|
71
|
+
def self.instances; @@instances; end
|
72
|
+
|
73
|
+
def initialize(group=nil)
|
74
|
+
@group = group || "Default Group"
|
75
|
+
@tryouts = HASH_TYPE.new
|
76
|
+
@paths = []
|
77
|
+
@command = nil
|
78
|
+
@dreams = HASH_TYPE.new
|
79
|
+
@dream_pointer = nil
|
80
|
+
end
|
81
|
+
|
82
|
+
# Populate this Tryouts from a block. The block should contain calls to
|
83
|
+
# the external DSL methods: tryout, command, dreams
|
84
|
+
def from_block(b, &inline)
|
85
|
+
instance_eval &b
|
86
|
+
end
|
87
|
+
|
88
|
+
# Execute Tryout#report for each Tryout in +@tryouts+
|
89
|
+
def report
|
90
|
+
successes = []
|
91
|
+
@tryouts.each_pair { |n,to| successes << to.report }
|
92
|
+
puts $/, "All your dreams came true" unless successes.member?(false)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Execute Tryout#run for each Tryout in +@tryouts+
|
96
|
+
def run; @tryouts.each_pair { |n,to| to.run }; end
|
97
|
+
|
98
|
+
# Add a shell command to Rye::Cmd and save the command name
|
99
|
+
# in @@commands so it can be used as the default for drills
|
100
|
+
def command(name=nil, path=nil)
|
101
|
+
return @command if name.nil?
|
102
|
+
@command = name.to_sym
|
103
|
+
@dtype = :cli
|
104
|
+
Rye::Cmd.module_eval do
|
105
|
+
define_method(name) do |*args|
|
106
|
+
cmd(path || name, *args)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
@command
|
110
|
+
end
|
111
|
+
# Calls Tryouts#command on the current instance of Tryouts
|
112
|
+
#
|
113
|
+
# NOTE: this is a standalone DSL-syntax method.
|
114
|
+
def self.command(*args)
|
115
|
+
@@instances.last.command(*args)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# Require +name+. If +path+ is supplied, it will "require path".
|
120
|
+
# * +name+ The name of the library in question (required). Stored as a Symbol to +@library+.
|
121
|
+
# * +path+ Add a path to the front of $LOAD_PATH (optional). Use this if you want to load
|
122
|
+
# a specific copy of the library. Otherwise, it loads from the system path.
|
123
|
+
def library(name=nil, path=nil)
|
124
|
+
return @library if name.nil?
|
125
|
+
@library = name.to_sym
|
126
|
+
@dtype = :api
|
127
|
+
$LOAD_PATH.unshift path unless path.nil?
|
128
|
+
require @library.to_s
|
129
|
+
end
|
130
|
+
# Calls Tryouts#library on the current instance of Tryouts
|
131
|
+
#
|
132
|
+
# NOTE: this is a standalone DSL-syntax method.
|
133
|
+
def self.library(*args)
|
134
|
+
@@instances.last.library(*args)
|
135
|
+
end
|
136
|
+
|
137
|
+
def group(name=nil)
|
138
|
+
return @group if name.nil?
|
139
|
+
@group = name unless name.nil?
|
140
|
+
# Preload dreams if possible
|
141
|
+
dfile = self.class.find_dreams_file(GYMNASIUM_HOME, @group)
|
142
|
+
self.load_dreams_file(dfile) if dfile
|
143
|
+
@group
|
144
|
+
end
|
145
|
+
# Raises a Tryouts::Exception. +group+ is not support in the standalone syntax
|
146
|
+
# because the group name is taken from the name of the class. See inherited.
|
147
|
+
#
|
148
|
+
# NOTE: this is a standalone DSL-syntax method.
|
149
|
+
def self.group(*args)
|
150
|
+
raise "Group is already set: #{@@instances.last.group}"
|
151
|
+
end
|
152
|
+
|
153
|
+
# Create a new Tryout object and add it to the list for this Tryouts class.
|
154
|
+
# * +name+ is the name of the Tryout
|
155
|
+
# * +type+ is the default drill type for the Tryout. One of: :cli, :api
|
156
|
+
# * +command+ when type is :cli, this is the name of the Rye::Box method that we're testing. Otherwise ignored.
|
157
|
+
# * +b+ is a block definition for the Tryout. See Tryout#from_block
|
158
|
+
#
|
159
|
+
# NOTE: This is a DSL-only method and is not intended for OO use.
|
160
|
+
def tryout(name, dtype=nil, command=nil, &block)
|
161
|
+
return if name.nil?
|
162
|
+
dtype ||= @dtype
|
163
|
+
command ||= @command if dtype == :cli
|
164
|
+
to = find_tryout(name, dtype)
|
165
|
+
if to.nil?
|
166
|
+
to = Tryouts::Tryout.new(name, dtype, command)
|
167
|
+
@tryouts[name] = to
|
168
|
+
end
|
169
|
+
# Populate the dreams if they've already been loaded
|
170
|
+
to.dreams = @dreams[name] if @dreams.has_key?(name)
|
171
|
+
# Process the rest of the DSL
|
172
|
+
to.from_block block if block
|
173
|
+
to
|
174
|
+
end
|
175
|
+
# Calls Tryouts#tryout on the current instance of Tryouts
|
176
|
+
#
|
177
|
+
# NOTE: this is a standalone DSL-syntax method.
|
178
|
+
def self.tryout(*args, &block)
|
179
|
+
@@instances.last.tryout(*args, &block)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Find matching Tryout objects by +name+ and filter by
|
183
|
+
# +dtype+ if specified. Returns a Tryout object or nil.
|
184
|
+
def find_tryout(name, dtype=nil)
|
185
|
+
by_name = @tryouts.values.select { |t| t.name == name }
|
186
|
+
by_name = by_name.select { |t| t.dtype == dtype } if dtype
|
187
|
+
by_name.first # by_name is an Array. We just want the Object.
|
188
|
+
end
|
189
|
+
|
190
|
+
# This method does nothing. It provides a quick way to disable a tryout.
|
191
|
+
#
|
192
|
+
# NOTE: This is a DSL-only method and is not intended for OO use.
|
193
|
+
def xtryout(*args, &block); end
|
194
|
+
# This method does nothing. It provides a quick way to disable a tryout.
|
195
|
+
#
|
196
|
+
# NOTE: this is a standalone DSL-syntax method.
|
197
|
+
def self.xtryout(*args, &block); end
|
198
|
+
|
199
|
+
# Load dreams from a file or directory or if a block is given
|
200
|
+
# it's processed
|
201
|
+
# Raises a Tryouts::BadDreams exception when something goes awry.
|
202
|
+
#
|
203
|
+
# This method is used in two ways:
|
204
|
+
# * In the dreams file DSL
|
205
|
+
# * As a getter method on a Tryouts object
|
206
|
+
def dreams(tryout_name=nil, &definition)
|
207
|
+
return @dreams unless tryout_name
|
208
|
+
|
209
|
+
#
|
210
|
+
# dreams "path/2/dreams"
|
211
|
+
# OR
|
212
|
+
# dreams "path/2/file_of_dreams.rb"
|
213
|
+
#
|
214
|
+
if File.exists?(tryout_name)
|
215
|
+
dfile = tryout_name
|
216
|
+
# If we're given a directory we'll build the filename using the class name
|
217
|
+
if File.directory?(tryout_name)
|
218
|
+
dfile = self.class.find_dreams_file(tryout_name, @group)
|
219
|
+
end
|
220
|
+
raise BadDreams, "Cannot find dreams file (#{tryout_name})" unless dfile
|
221
|
+
@dreams = load_dreams_file( dfile) || {}
|
222
|
+
|
223
|
+
#
|
224
|
+
# dreams "Tryout Name" do
|
225
|
+
# dream "drill name" ...
|
226
|
+
# end
|
227
|
+
#
|
228
|
+
elsif tryout_name.kind_of?(String) && definition
|
229
|
+
to = find_tryout(tryout_name, @dtype)
|
230
|
+
|
231
|
+
if to.nil?
|
232
|
+
@dream_pointer = tryout_name # Used in Tryouts.dream
|
233
|
+
@dreams[ @dream_pointer ] ||= {}
|
234
|
+
definition.call
|
235
|
+
else
|
236
|
+
to.from_block &definition
|
237
|
+
end
|
238
|
+
else
|
239
|
+
raise BadDreams, tryout_name
|
240
|
+
end
|
241
|
+
@dreams
|
242
|
+
end
|
243
|
+
# Without arguments, returns a Hash of all known dreams.
|
244
|
+
# With arguments, it calls Tryouts#dreams on the current instance of Tryouts.
|
245
|
+
#
|
246
|
+
# NOTE: this is a standalone DSL-syntax method.
|
247
|
+
def self.dreams(*args, &block)
|
248
|
+
if args.empty? && block.nil?
|
249
|
+
dreams = {}
|
250
|
+
@@instances.each_pair do |name,inst|
|
251
|
+
dreams[name] = inst.dreams
|
252
|
+
end
|
253
|
+
return dreams
|
254
|
+
else
|
255
|
+
# Call the Tryouts#dreams instance method
|
256
|
+
@@instances.last.dreams(*args, &block)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# +name+ of the Drill associated to this Dream
|
261
|
+
# +output+ A String or Array of expected output. A Dream object will be created using this value (optional)
|
262
|
+
# +definition+ is a block which will be run on an instance of Dream
|
263
|
+
#
|
264
|
+
# This method is different than Tryout#dream because this one stores
|
265
|
+
# dreams inside an instance variable of the current Tryouts object.
|
266
|
+
# This allows for the situation where the dreams block appears before
|
267
|
+
# the tryout block. See Tryouts#tryout
|
268
|
+
#
|
269
|
+
# NOTE: This method is DSL-only. It's not intended to be used in OO syntax.
|
270
|
+
def dream(name, output=nil, format=nil, rcode=0, emsg=nil, &definition)
|
271
|
+
to = find_tryout(@dream_pointer, @dtype)
|
272
|
+
if to.nil?
|
273
|
+
if output.nil?
|
274
|
+
dobj = Tryouts::Drill::Dream.from_block definition
|
275
|
+
else
|
276
|
+
dobj = Tryouts::Drill::Dream.new(output)
|
277
|
+
dobj.format, dobj.rcode, dobj.emsg = format, rcode, emsg
|
278
|
+
end
|
279
|
+
@dreams[@dream_pointer][name] = dobj
|
280
|
+
else
|
281
|
+
# Let the Tryout object process the dream DSL.
|
282
|
+
# We'll get here if the dream is placed after
|
283
|
+
# the drill with the same name in the same block.
|
284
|
+
to.dream name, output, format, rcode, emsg, &definition
|
285
|
+
end
|
286
|
+
end
|
287
|
+
# Calls Tryouts#dream on the current instance of Tryouts
|
288
|
+
#
|
289
|
+
# NOTE: this is a standalone DSL-syntax method.
|
290
|
+
def self.dream(*args, &block)
|
291
|
+
@@instances.last.dream(*args, &block)
|
292
|
+
end
|
293
|
+
|
294
|
+
# Populate @@dreams with the content of the file +dpath+.
|
295
|
+
#
|
296
|
+
# NOTE: this is an OO syntax method
|
297
|
+
def load_dreams_file(dpath)
|
298
|
+
type = File.extname dpath
|
299
|
+
if type == ".yaml" || type == ".yml"
|
300
|
+
@dreams = YAML.load_file dpath
|
301
|
+
elsif type == ".json" || type == ".js"
|
302
|
+
@dreams = JSON.load_file dpath
|
303
|
+
elsif type == ".rb"
|
304
|
+
@dreams = instance_eval File.read(dpath)
|
305
|
+
else
|
306
|
+
raise BadDreams, "Unknown kind of dream: #{dpath}"
|
307
|
+
end
|
308
|
+
@dreams
|
309
|
+
end
|
310
|
+
|
311
|
+
# Parse a +_tryouts.rb+ file. See Tryouts::CLI::Run for an example.
|
312
|
+
#
|
313
|
+
# NOTE: this is an OO syntax method
|
314
|
+
def self.parse_file(fpath)
|
315
|
+
raise "No such file: #{fpath}" unless File.exists?(fpath)
|
316
|
+
file_content = File.read(fpath)
|
317
|
+
to = Tryouts.new
|
318
|
+
to.instance_eval file_content, fpath
|
319
|
+
if @@instances.has_key? to.group
|
320
|
+
to = @@instances[to.group]
|
321
|
+
to.instance_eval file_content, fpath
|
322
|
+
end
|
323
|
+
to.paths << fpath
|
324
|
+
@@instances[to.group] = to
|
325
|
+
end
|
326
|
+
|
327
|
+
# Run all Tryout objects in +@tryouts+
|
328
|
+
#
|
329
|
+
# NOTE: this is an OO syntax method
|
330
|
+
def self.run
|
331
|
+
@@instances.each_pair do |group, inst|
|
332
|
+
inst.tryouts.each_pair do |name,to|
|
333
|
+
to.run
|
334
|
+
to.report
|
335
|
+
STDOUT.flush
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
# Called when a new class inherits from Tryouts. This creates a new instance
|
341
|
+
# of Tryouts, sets group to the name of the new class, and adds the instance
|
342
|
+
# to +@@instances+.
|
343
|
+
#
|
344
|
+
# NOTE: this is a standalone DSL-syntax method.
|
345
|
+
def self.inherited(klass)
|
346
|
+
to = @@instances[ klass ]
|
347
|
+
to ||= Tryouts.new
|
348
|
+
to.paths << __FILE__
|
349
|
+
to.group = klass
|
350
|
+
@@instances[to.group] = to
|
351
|
+
end
|
352
|
+
|
353
|
+
|
354
|
+
##---
|
355
|
+
## Is this wacky syntax useful for anything?
|
356
|
+
## t2 :set .
|
357
|
+
## run = "poop"
|
358
|
+
## def self.t2(*args)
|
359
|
+
## OpenStruct.new
|
360
|
+
## end
|
361
|
+
##+++
|
362
|
+
|
363
|
+
# Find a dreams file in the directory +dir+ based on the current group name.
|
364
|
+
# The expected filename format is: groupname_dreams.ext where "groupname" is
|
365
|
+
# the lowercase name of the Tryouts group (spaces removed) and "ext" is one
|
366
|
+
# of: yaml, js, json, rb.
|
367
|
+
#
|
368
|
+
# e.g.
|
369
|
+
# Tryouts.find_dreams_file "dirpath" # => dirpath/tryouts_dreams.rb
|
370
|
+
#
|
371
|
+
def self.find_dreams_file(dir, group=nil)
|
372
|
+
dpath = nil
|
373
|
+
group ||= @@instances.last.group
|
374
|
+
group = group.to_s.downcase.tr(' ', '')
|
375
|
+
[:rb, :yaml].each do |ext|
|
376
|
+
tmp = File.join(dir, "#{group}_dreams.#{ext}")
|
377
|
+
if File.exists?(tmp)
|
378
|
+
dpath = tmp
|
379
|
+
break
|
380
|
+
end
|
381
|
+
end
|
382
|
+
dpath
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
dreams "Common Usage" do
|
3
|
+
dream "No args" do
|
4
|
+
output inline(%Q{
|
5
|
+
Date: 2009-02-16
|
6
|
+
Owners: greg, rupaul, telly, prince kinko
|
7
|
+
Players: d-bam, alberta, birds, condor man
|
8
|
+
})
|
9
|
+
end
|
10
|
+
dream "YAML Output" do
|
11
|
+
format :yaml
|
12
|
+
output ({
|
13
|
+
"Date" => "2009-02-16",
|
14
|
+
"Players" => ["d-bam", "alberta", "birds", "condor man"],
|
15
|
+
"Owners" => ["greg", "rupaul", "telly", "prince kinko"]
|
16
|
+
})
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
TRYOUTS_HOME = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
3
|
+
MOCKOUT_PATH = File.join(TRYOUTS_HOME, "bin", "mockout")
|
4
|
+
|
5
|
+
group "mockout cli"
|
6
|
+
command :mockout, MOCKOUT_PATH
|
7
|
+
|
8
|
+
tryout "Common Usage" do
|
9
|
+
drill "No Command"
|
10
|
+
drill "No args", :info
|
11
|
+
drill "YAML Output", :f, :yaml, :info
|
12
|
+
drill "JSON Output", :f, :json, :info
|
13
|
+
end
|
14
|
+
|
15
|
+
tryout "inline dream that passes", :cli, :mockout do
|
16
|
+
output = ["we expect mockout to", "echo these lines back"]
|
17
|
+
|
18
|
+
# $ bin/mockout sergeant -e "we expect mockout to" "echo these lines back"
|
19
|
+
drill "echo arguments", :info, :e, output[0], output[1]
|
20
|
+
dream "echo arguments", output
|
21
|
+
end
|
22
|
+
|
23
|
+
tryout "inline dream that fails", :cli, :mockout do
|
24
|
+
dream "echo arguments", "The dream does"
|
25
|
+
drill "echo arguments", :info, :e, "not match reality"
|
26
|
+
end
|