tryouts 0.4.0
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.
- 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
|