delano-tryouts 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +5 -0
- data/README.rdoc +4 -8
- data/bin/tryouts +3 -2
- data/lib/tryouts/cli/run.rb +66 -16
- data/lib/tryouts/drill/response.rb +25 -29
- data/lib/tryouts/drill/sergeant/cli.rb +1 -1
- data/lib/tryouts/drill.rb +9 -14
- data/lib/tryouts/tryout.rb +41 -64
- data/lib/tryouts.rb +118 -62
- data/tryouts/mockoutcli_dreams.rb +4 -4
- data/tryouts/mockoutcli_dreams.yaml +0 -1
- data/tryouts/mockoutcli_tryouts.rb +4 -3
- data/tryouts.gemspec +1 -1
- metadata +1 -1
data/CHANGES.txt
CHANGED
data/README.rdoc
CHANGED
@@ -1,11 +1,7 @@
|
|
1
|
-
= Tryouts - v0.
|
1
|
+
= Tryouts - v0.4 BETA
|
2
2
|
|
3
3
|
Tryouts is a high-level testing library for your command-line applications and Ruby codes.
|
4
4
|
|
5
|
-
*WORK IN PROGRESS*
|
6
|
-
|
7
|
-
2009-05-24 - A BBQ started nearby as I was writing this documentation. It's incomplete and I'm sorry about that but I can tell you that this BBQ smells really, really good.
|
8
|
-
|
9
5
|
|
10
6
|
== Terminology
|
11
7
|
|
@@ -27,9 +23,9 @@ The tryout definition would look like this:
|
|
27
23
|
|
28
24
|
command :executable, "path/2/executable"
|
29
25
|
|
30
|
-
tryout "Common Usage"
|
26
|
+
tryout "Common Usage" do
|
31
27
|
drill "No Command"
|
32
|
-
drill "YAML Output", :f,
|
28
|
+
drill "YAML Output", :f, 'yaml'
|
33
29
|
end
|
34
30
|
|
35
31
|
And the expected output would be defined like this:
|
@@ -56,7 +52,7 @@ Tryouts employs the same approach for testing Ruby codes. The return value of th
|
|
56
52
|
|
57
53
|
library :caesars, LIBRARY_PATH
|
58
54
|
|
59
|
-
tryout "Common Usage"
|
55
|
+
tryout "Common Usage" do
|
60
56
|
dream "Some Maths", 3
|
61
57
|
drill "Some Maths" do
|
62
58
|
12 / 4
|
data/bin/tryouts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/ruby
|
1
|
+
#!/usr/local/bin/ruby
|
2
2
|
|
3
3
|
TRYOUTS_HOME = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
4
4
|
|
@@ -15,9 +15,10 @@ require 'tryouts/cli'
|
|
15
15
|
module TryoutsCLI
|
16
16
|
extend Drydock
|
17
17
|
|
18
|
-
debug :
|
18
|
+
debug :off
|
19
19
|
default :run, :with_args
|
20
20
|
|
21
|
+
global :q, :quiet, "Decrease output"
|
21
22
|
global :v, :verbose, "Increase output" do
|
22
23
|
@verbose ||= 0
|
23
24
|
@verbose += 1
|
data/lib/tryouts/cli/run.rb
CHANGED
@@ -28,47 +28,97 @@ class Tryouts; module CLI
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def run
|
31
|
+
if @global.verbose > 0
|
32
|
+
puts "#{Tryouts.sysinfo.to_s} (#{RUBY_VERSION})"
|
33
|
+
end
|
34
|
+
|
31
35
|
load_available_tryouts_files
|
32
|
-
|
36
|
+
|
37
|
+
passed, failed = 0, 0
|
38
|
+
Tryouts.instances.each_pair do |group,tryouts_inst|
|
39
|
+
puts '', ' %-60s'.att(:reverse) % group
|
40
|
+
puts " #{tryouts_inst.paths.join("\n ")}" if @global.verbose > 0
|
41
|
+
tryouts_inst.tryouts.each_pair do |name,to|
|
42
|
+
to.run
|
43
|
+
to.report
|
44
|
+
STDOUT.flush
|
45
|
+
passed += to.passed
|
46
|
+
failed += to.failed
|
47
|
+
end
|
48
|
+
end
|
49
|
+
unless @global.quiet
|
50
|
+
if failed == 0
|
51
|
+
puts MOOKIE if @global.verbose > 5
|
52
|
+
puts $/, " All #{passed+failed} dreams came true ".att(:reverse).color(:green)
|
53
|
+
else
|
54
|
+
puts $/, " #{passed} of #{passed+failed} dreams came true ".att(:reverse).color(:red)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
33
58
|
end
|
34
59
|
|
35
60
|
def list
|
36
61
|
load_available_tryouts_files
|
37
|
-
if @global.verbose >
|
38
|
-
|
39
|
-
else
|
40
|
-
Tryouts.instances.each_pair do |n,
|
62
|
+
##if @global.verbose > 2
|
63
|
+
## puts Tryouts.instances.to_yaml # BUG: Raises "can't dump anonymous class Class"
|
64
|
+
##else
|
65
|
+
Tryouts.instances.each_pair do |n,tryouts_inst|
|
41
66
|
puts n
|
42
|
-
|
67
|
+
if @global.verbose > 0
|
68
|
+
puts " #{tryouts_inst.paths.join("\n ")}"
|
69
|
+
end
|
70
|
+
tryouts_inst.tryouts.each_pair do |t2,tryout|
|
43
71
|
puts " " << tryout.name
|
44
72
|
tryout.drills.each do |drill|
|
45
73
|
puts " " << drill.name
|
46
74
|
end
|
47
75
|
end
|
48
76
|
end
|
49
|
-
end
|
77
|
+
##end
|
50
78
|
end
|
51
79
|
|
52
80
|
private
|
53
81
|
def load_available_tryouts_files
|
54
82
|
@tryouts_files = []
|
55
|
-
|
56
|
-
|
57
|
-
@argv.
|
83
|
+
# If file paths were given, check those only.
|
84
|
+
unless @argv.empty?
|
85
|
+
@argv.each do |file|
|
58
86
|
file = File.join(file, '**', '*_tryouts.rb') if File.directory?(file)
|
59
87
|
@tryouts_files += Dir.glob file
|
60
88
|
end
|
89
|
+
# Otherwise check the default globs
|
61
90
|
else
|
62
91
|
@tryouts_globs.each do |glob|
|
63
92
|
@tryouts_files += Dir.glob glob
|
64
93
|
end
|
65
94
|
end
|
66
|
-
|
67
|
-
@tryouts_files.
|
68
|
-
|
69
|
-
puts "FOUND:", @tryouts_files if @global.verbose > 0
|
70
|
-
|
95
|
+
@tryouts_files.uniq! # Don't load the same file twice
|
96
|
+
@tryouts_files.each { |f| puts "LOADING: #{f}"} if @global.verbose > 0
|
71
97
|
@tryouts_files.each { |file| Tryouts.parse_file file }
|
72
98
|
end
|
73
99
|
end
|
74
|
-
end; end
|
100
|
+
end; end
|
101
|
+
|
102
|
+
MOOKIE = %q{
|
103
|
+
__,-----._ ,-.
|
104
|
+
,' ,-. \`---. ,-----<._/
|
105
|
+
(,.-. o:.` )),"\\\-._ ,' `.
|
106
|
+
('"-` .\ \`:_ )\ `-;'-._ \
|
107
|
+
,,-. \` ; : \( `-' ) -._ : `:
|
108
|
+
( \ `._\\\ ` ; ; ` : )
|
109
|
+
\`. `-. __ , / \ ;, (
|
110
|
+
`.`-.___--' `- / ; | : |
|
111
|
+
`-' `-.`--._ ' ; |
|
112
|
+
(`--._`. ; /\ |
|
113
|
+
\ ' \ , ) :
|
114
|
+
| `--::---- \' ; ;|
|
115
|
+
\ .__,- ( ) : :|
|
116
|
+
\ : `------; \ | | ;
|
117
|
+
\ : / , ) | | (
|
118
|
+
-hrr- \ \ `-^-| | / , ,\
|
119
|
+
) ) | -^- ; `-^-^'
|
120
|
+
_,' _ ; | |
|
121
|
+
/ , , ,' /---. :
|
122
|
+
`-^-^' ( : :,'
|
123
|
+
`-^--'
|
124
|
+
}
|
@@ -8,8 +8,7 @@ class Tryouts::Drill
|
|
8
8
|
attr_accessor :output, :format, :rcode, :emsg, :backtrace
|
9
9
|
def initialize(output=nil, format=nil, rcode=0)
|
10
10
|
@output, @format, @rcode = output, format, (rcode || 0)
|
11
|
-
@
|
12
|
-
@output ||= []
|
11
|
+
@output = nil if @output.nil?
|
13
12
|
normalize!
|
14
13
|
end
|
15
14
|
|
@@ -39,35 +38,31 @@ class Tryouts::Drill
|
|
39
38
|
@format = @format.to_sym if @format.is_a?(String)
|
40
39
|
end
|
41
40
|
def compare_output(other)
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
41
|
+
#
|
42
|
+
# The dream is always on the left (Does your dream match reality?)
|
43
|
+
# This check is important so we can support both:
|
44
|
+
# @dream == @reality
|
45
|
+
# AND
|
46
|
+
# @reality == @dream
|
47
|
+
#
|
48
|
+
if self.is_a? Tryouts::Drill::Dream
|
49
|
+
dream, reality = self, other
|
50
|
+
elsif self.is_a? Tryouts::Drill::Reality
|
51
|
+
dream, reality = other, self
|
52
|
+
else
|
53
|
+
# If self isn't a Dream or a Reality, then we have a problem
|
54
|
+
return false
|
51
55
|
end
|
52
56
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
if !expressions.nil? && !strings.nil?
|
63
|
-
expressions.each_with_index do |regex, index|
|
64
|
-
return false unless strings[index] =~ regex
|
65
|
-
end
|
66
|
-
return true
|
67
|
-
end
|
57
|
+
# The matching statement will be the return value.
|
58
|
+
if dream.format.nil? || (dream.class == reality.class)
|
59
|
+
dream.output == reality.output
|
60
|
+
elsif reality.respond_to? dream.format
|
61
|
+
reality.output.send(dream.format) == dream.output
|
62
|
+
else
|
63
|
+
false
|
68
64
|
end
|
69
65
|
|
70
|
-
false
|
71
66
|
end
|
72
67
|
|
73
68
|
end
|
@@ -94,8 +89,9 @@ class Tryouts::Drill
|
|
94
89
|
# Takes a String +val+ and splits the lines into an Array. Each line
|
95
90
|
# has
|
96
91
|
def inline(val=nil)
|
97
|
-
lines = (val.split($/) || [])
|
98
|
-
lines.
|
92
|
+
lines = (val.split($/) || [])
|
93
|
+
lines.shift if lines.first.strip == ""
|
94
|
+
lines.pop if lines.last.strip == ""
|
99
95
|
lines
|
100
96
|
end
|
101
97
|
end
|
@@ -18,7 +18,7 @@ class Tryouts; class Drill; module Sergeant
|
|
18
18
|
@rbox = Rye::Box.new
|
19
19
|
end
|
20
20
|
|
21
|
-
# NOTE: Context is ignored for
|
21
|
+
# NOTE: Context is ignored for the CLI Sergeant.
|
22
22
|
def run(block, context=nil, &inline)
|
23
23
|
# A Proc object takes precedence over an inline block.
|
24
24
|
runtime = (block.nil? ? inline : block)
|
data/lib/tryouts/drill.rb
CHANGED
@@ -32,36 +32,38 @@ class Tryouts
|
|
32
32
|
@name, @dtype, @drill = name, dtype, drill
|
33
33
|
@sergeant = hire_sergeant *drill_args
|
34
34
|
# For CLI drills, a block takes precedence over inline args.
|
35
|
+
# A block will contain multiple shell commands (see Rye::Box#batch)
|
35
36
|
drill_args = [] if dtype == :cli && drill.is_a?(Proc)
|
37
|
+
@reality = Tryouts::Drill::Reality.new
|
36
38
|
end
|
37
39
|
|
38
40
|
def hire_sergeant(*drill_args)
|
39
41
|
if @dtype == :cli
|
40
42
|
Tryouts::Drill::Sergeant::CLI.new(*drill_args)
|
41
43
|
elsif @dtype == :api
|
42
|
-
Tryouts::Drill::Sergeant::API.new(
|
44
|
+
Tryouts::Drill::Sergeant::API.new(drill_args.first)
|
43
45
|
else
|
44
46
|
raise NoSergeant, "What is #{@dtype}?"
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
50
|
def run(context=nil)
|
49
|
-
|
51
|
+
return false if @dream.nil?
|
50
52
|
begin
|
51
53
|
print Tryouts::DRILL_MSG % @name
|
52
54
|
@reality = @sergeant.run @drill, context
|
53
55
|
process_reality
|
54
56
|
rescue => ex
|
55
|
-
@reality = Tryouts::Drill::Reality.new
|
56
57
|
@reality.rcode = -2
|
57
58
|
@reality.emsg, @reality.backtrace = ex.message, ex.backtrace
|
58
59
|
end
|
59
60
|
note = @dream ? discrepency.join(', ') : 'nodream'
|
60
|
-
puts self.success? ? "PASS" : "FAIL (#{note})"
|
61
|
+
puts self.success? ? "PASS".color(:green) : "FAIL (#{note})".color(:red)
|
61
62
|
self.success?
|
62
63
|
end
|
63
64
|
|
64
65
|
def success?
|
66
|
+
return false if @dream.nil? || @reality.nil?
|
65
67
|
@dream == @reality
|
66
68
|
end
|
67
69
|
|
@@ -69,7 +71,7 @@ class Tryouts
|
|
69
71
|
diffs = []
|
70
72
|
if @dream
|
71
73
|
diffs << "rcode" if @dream.rcode != @reality.rcode
|
72
|
-
diffs << "output" if
|
74
|
+
diffs << "output" if !@dream.compare_output(@reality)
|
73
75
|
diffs << "emsg" if @dream.emsg != @reality.emsg
|
74
76
|
end
|
75
77
|
diffs
|
@@ -84,19 +86,12 @@ class Tryouts
|
|
84
86
|
def process_reality
|
85
87
|
@reality.normalize!
|
86
88
|
return unless @dream && @dream.format
|
87
|
-
if @dream.format
|
89
|
+
if @dream.format == :to_yaml
|
88
90
|
@reality.output = YAML.load(@reality.output.join("\n"))
|
89
|
-
elsif @dream.format
|
91
|
+
elsif @dream.format == :to_json
|
90
92
|
@reality.output = JSON.load(@reality.output.join("\n"))
|
91
93
|
end
|
92
94
|
|
93
|
-
if @reality.output.is_a?(Array)
|
94
|
-
# Remove new lines from String output
|
95
|
-
@reality.output = @reality.output.collect do |line|
|
96
|
-
line.is_a?(String) ? line.strip : line
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
95
|
#p [:process, @name, @dream.format, @reality.output]
|
101
96
|
end
|
102
97
|
|
data/lib/tryouts/tryout.rb
CHANGED
@@ -9,26 +9,24 @@ class Tryouts
|
|
9
9
|
|
10
10
|
# The name of this tryout
|
11
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
12
|
# A default value for Drill.dtype
|
20
13
|
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
14
|
# A block to executed one time before starting the drills
|
28
15
|
attr_reader :setup
|
29
|
-
|
30
16
|
# A block to executed one time before starting the drills
|
31
17
|
attr_reader :clean
|
18
|
+
# An Array of Drill objects
|
19
|
+
attr_reader :drills
|
20
|
+
# The number of dreams that came true (successful drills)
|
21
|
+
attr_reader :passed
|
22
|
+
# The number of dreams that did not come true (failed drills)
|
23
|
+
attr_reader :failed
|
24
|
+
# For drill type :cli, this is the name of the command to test. It
|
25
|
+
# should be a valid method available to a Rye::Box object.
|
26
|
+
# For drill type :api, this attribute is ignored.
|
27
|
+
attr_reader :command
|
28
|
+
# A Hash of Dream objects for this Tryout. The keys are drill names.
|
29
|
+
attr_accessor :dreams
|
32
30
|
|
33
31
|
@@valid_dtypes = [:cli, :api]
|
34
32
|
|
@@ -42,48 +40,46 @@ class Tryouts
|
|
42
40
|
raise "Must supply command for dtype :cli" if dtype == :cli && command.nil?
|
43
41
|
raise "#{dtype} is not a valid drill type" if !@@valid_dtypes.member?(dtype)
|
44
42
|
@name, @dtype, @command = name, dtype, command
|
45
|
-
@drills = []
|
46
|
-
@
|
43
|
+
@drills, @dreams = [], {}
|
44
|
+
@passed, @failed = 0, 0
|
47
45
|
end
|
48
46
|
|
49
47
|
## --------------------------------------- EXTERNAL API -----
|
50
48
|
|
51
49
|
# Populate this Tryout from a block. The block should contain calls to
|
52
50
|
# the external DSL methods: dream, drill, xdrill
|
53
|
-
def from_block(b, &inline)
|
54
|
-
|
51
|
+
def from_block(b=nil, &inline)
|
52
|
+
runtime = b.nil? ? inline : b
|
53
|
+
instance_eval &runtime
|
55
54
|
end
|
56
55
|
|
57
56
|
# Execute all Drill objects
|
58
57
|
def run
|
59
58
|
update_drills! # Ensure all drills have all known dreams
|
60
|
-
DrillContext.
|
61
|
-
puts Tryouts::TRYOUT_MSG % @name
|
59
|
+
DrillContext.class_eval &setup if setup.is_a?(Proc)
|
60
|
+
puts Tryouts::TRYOUT_MSG.bright % @name
|
62
61
|
@drills.each do |drill|
|
63
62
|
drill.run(DrillContext.new) # Returns true or false
|
63
|
+
drill.success? ? @passed += 1 : @failed += 1
|
64
64
|
end
|
65
|
-
DrillContext.
|
65
|
+
DrillContext.class_eval &clean if clean.is_a?(Proc)
|
66
66
|
end
|
67
67
|
|
68
68
|
# Prints error output. If there are no errors, it prints nothing.
|
69
69
|
def report
|
70
|
-
if success?
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
@drills.each do |drill|
|
76
|
-
next if drill.success?
|
77
|
-
puts Tryouts::DRILL_MSG % drill.name
|
78
|
-
if drill.reality.rcode < 0
|
79
|
-
puts '%24s' % drill.reality.emsg
|
80
|
-
next
|
81
|
-
end
|
70
|
+
return true if success?
|
71
|
+
failed = @drills.select { |d| !d.success? }
|
72
|
+
failed.each_with_index do |drill,index|
|
73
|
+
title = ' %-59s' % %Q{ERROR #{index+1}/#{failed.size} in "#{drill.name}"}
|
74
|
+
puts $/, ' ' << title.color(:red).att(:reverse)
|
82
75
|
|
83
76
|
if drill.dream
|
84
|
-
drill.
|
85
|
-
|
86
|
-
|
77
|
+
puts '%24s: %s (expected %s)' % ["response code", drill.reality.rcode, drill.dream.rcode]
|
78
|
+
puts '%24s: %s' % ["expected output", drill.dream.output.inspect]
|
79
|
+
puts '%24s: %s' % ["actual output", drill.reality.output.inspect]
|
80
|
+
if drill.reality.emsg || (drill.reality.emsg != drill.dream.emsg)
|
81
|
+
puts '%24s: %s' % ["expected error msg", drill.dream.emsg.inspect]
|
82
|
+
puts '%24s: %s' % ["actual error msg", drill.reality.emsg.inspect]
|
87
83
|
end
|
88
84
|
else
|
89
85
|
puts '%24s' % ["[nodream]"]
|
@@ -94,15 +90,19 @@ class Tryouts
|
|
94
90
|
end
|
95
91
|
|
96
92
|
if drill.reality.rcode > 0
|
97
|
-
puts '%24s:
|
93
|
+
puts '%24s: ' % ["backtrace"]
|
94
|
+
puts drill.reality.backtrace, $/
|
98
95
|
end
|
96
|
+
|
99
97
|
end
|
98
|
+
false
|
100
99
|
end
|
101
100
|
|
102
101
|
# Did every Tryout finish successfully?
|
103
102
|
def success?
|
103
|
+
return @success unless @success.nil?
|
104
104
|
# Returns true only when every Tryout result returns true
|
105
|
-
!(@drills.collect { |r| r.success? }.member?(false))
|
105
|
+
@success = !(@drills.collect { |r| r.success? }.member?(false))
|
106
106
|
end
|
107
107
|
|
108
108
|
# Add a Drill object to the list for this Tryout. If there is a dream
|
@@ -146,7 +146,7 @@ class Tryouts
|
|
146
146
|
# +definition+ is a block which will be run on an instance of Dream
|
147
147
|
#
|
148
148
|
# NOTE: This method is DSL-only. It's not intended to be used in OO syntax.
|
149
|
-
def dream(name, output=nil, format
|
149
|
+
def dream(name, output=nil, format=nil, rcode=0, emsg=nil, &definition)
|
150
150
|
if output.nil?
|
151
151
|
dobj = Tryouts::Drill::Dream.from_block definition
|
152
152
|
else
|
@@ -154,41 +154,18 @@ class Tryouts
|
|
154
154
|
dobj.format, dobj.rcode, dobj.emsg = format, rcode, emsg
|
155
155
|
end
|
156
156
|
@dreams[name] = dobj
|
157
|
-
|
158
157
|
dobj
|
159
158
|
end
|
160
159
|
|
161
160
|
# Create and add a Drill object to the list for this Tryout
|
162
161
|
# +name+ is the name of the drill.
|
163
162
|
# +args+ is sent directly to the Drill class. The values are specific on the Sergeant.
|
164
|
-
def drill(name, *args, &
|
163
|
+
def drill(name, *args, &definition)
|
165
164
|
args.unshift(@command) if @dtype == :cli
|
166
|
-
drill = Tryouts::Drill.new(name, @dtype, *args, &
|
165
|
+
drill = Tryouts::Drill.new(name, @dtype, *args, &definition)
|
167
166
|
add_drill drill
|
168
167
|
end
|
169
168
|
def xdrill(*args, &b); end # ignore calls to xdrill
|
170
169
|
|
171
170
|
|
172
|
-
|
173
|
-
|
174
|
-
private
|
175
|
-
|
176
|
-
# Convert every Hash of dream params into a Tryouts::Drill::Dream object.
|
177
|
-
# DEPRECATED: This is not used anymore since we have the dreams DSL syntax.
|
178
|
-
def parse_dreams!
|
179
|
-
if @dreams.kind_of?(Hash)
|
180
|
-
#raise BadDreams, 'Not deep enough' unless @@dreams.deepest_point == 2
|
181
|
-
@dreams.each_pair do |tname, drills|
|
182
|
-
drills.each_pair do |dname, dream_params|
|
183
|
-
next if dream_params.is_a?(Tryouts::Drill::Dream)
|
184
|
-
dream = Tryouts::Drill::Dream.new
|
185
|
-
dream_params.each_pair { |n,v| dream.send("#{n}=", v) }
|
186
|
-
@dreams[tname][dname] = dream
|
187
|
-
end
|
188
|
-
end
|
189
|
-
else
|
190
|
-
raise BadDreams, 'Not a kind of Hash'
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
171
|
end; end
|
data/lib/tryouts.rb
CHANGED
@@ -30,50 +30,56 @@ class Tryouts
|
|
30
30
|
# Raised when there is a problem loading or parsing a Tryouts::Drill::Dream object
|
31
31
|
class BadDreams < Exception; end
|
32
32
|
|
33
|
-
VERSION = "0.4.
|
33
|
+
VERSION = "0.4.1"
|
34
34
|
|
35
35
|
require 'tryouts/mixins'
|
36
36
|
require 'tryouts/tryout'
|
37
37
|
require 'tryouts/drill'
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
require 'tryouts/orderedhash'
|
40
|
+
HASH_TYPE = (RUBY_VERSION =~ /1.9/) ? ::Hash : Tryouts::OrderedHash
|
41
41
|
|
42
|
+
TRYOUT_MSG = "\n %s "
|
43
|
+
DRILL_MSG = ' %-50s '
|
44
|
+
DRILL_ERR = ' %s: '
|
45
|
+
|
46
|
+
# An Array of +_tryouts.rb+ file paths that have been loaded.
|
47
|
+
@@loaded_files = []
|
42
48
|
# An Hash of Tryouts instances stored under the name of the Tryouts subclass.
|
43
|
-
@@instances =
|
44
|
-
#
|
45
|
-
@@
|
49
|
+
@@instances = HASH_TYPE.new
|
50
|
+
# An instance of SysInfo
|
51
|
+
@@sysinfo = SysInfo.new
|
52
|
+
|
53
|
+
# Returns +@@instances+
|
54
|
+
def self.instances; @@instances; end
|
55
|
+
# Returns +@@sysinfo+
|
56
|
+
def self.sysinfo; @@sysinfo; end
|
46
57
|
|
47
58
|
# The name of this group of Tryout objects
|
48
59
|
attr_accessor :group
|
49
|
-
# An Array of Tryout objects
|
50
|
-
attr_accessor :tryouts
|
51
|
-
# A Hash of Tryout names pointing to index values of :tryouts
|
52
|
-
attr_accessor :map
|
53
|
-
# A Symbol representing the command taking part in the tryouts. For @dtype :cli only.
|
54
|
-
attr_accessor :command
|
55
|
-
# A Symbol representing the name of the library taking part in the tryouts. For @dtype :api only.
|
56
|
-
attr_accessor :library
|
57
60
|
# A Symbol representing the default drill type. One of: :cli, :api
|
58
61
|
attr_accessor :dtype
|
59
|
-
|
62
|
+
# An Array of file paths which populated this instance of Tryouts
|
63
|
+
attr_accessor :paths
|
60
64
|
# A Hash of dreams for all tryouts in this class. The keys should
|
61
65
|
# match the names of each tryout. The values are hashes will drill
|
62
66
|
# names as keys and response
|
63
67
|
attr_accessor :dreams
|
68
|
+
# An Array of Tryout objects
|
69
|
+
attr_accessor :tryouts
|
70
|
+
# A Symbol representing the command taking part in the tryouts. For @dtype :cli only.
|
71
|
+
attr_accessor :command
|
72
|
+
# A Symbol representing the name of the library taking part in the tryouts. For @dtype :api only.
|
73
|
+
attr_accessor :library
|
64
74
|
# The name of the most recent dreams group (see self.dream)
|
65
75
|
attr_accessor :dream_pointer
|
66
|
-
|
67
|
-
# Returns +@@instances+
|
68
|
-
def self.instances; @@instances; end
|
69
76
|
|
70
77
|
def initialize(group=nil)
|
71
78
|
@group = group || "Default Group"
|
72
|
-
@tryouts =
|
73
|
-
@
|
79
|
+
@tryouts = HASH_TYPE.new
|
80
|
+
@paths = []
|
74
81
|
@command = nil
|
75
|
-
@
|
76
|
-
@dreams = {}
|
82
|
+
@dreams = HASH_TYPE.new
|
77
83
|
@dream_pointer = nil
|
78
84
|
end
|
79
85
|
|
@@ -84,16 +90,21 @@ class Tryouts
|
|
84
90
|
end
|
85
91
|
|
86
92
|
# Execute Tryout#report for each Tryout in +@tryouts+
|
87
|
-
def report
|
93
|
+
def report
|
94
|
+
successes = []
|
95
|
+
@tryouts.each_pair { |n,to| successes << to.report }
|
96
|
+
puts $/, "All your dreams came true" unless successes.member?(false)
|
97
|
+
end
|
88
98
|
|
89
99
|
# Execute Tryout#run for each Tryout in +@tryouts+
|
90
|
-
def run; @tryouts.
|
100
|
+
def run; @tryouts.each_pair { |n,to| to.run }; end
|
91
101
|
|
92
102
|
# Add a shell command to Rye::Cmd and save the command name
|
93
103
|
# in @@commands so it can be used as the default for drills
|
94
104
|
def command(name=nil, path=nil)
|
95
105
|
return @command if name.nil?
|
96
106
|
@command = name.to_sym
|
107
|
+
@dtype = :cli
|
97
108
|
Rye::Cmd.module_eval do
|
98
109
|
define_method(name) do |*args|
|
99
110
|
cmd(path || name, *args)
|
@@ -105,7 +116,7 @@ class Tryouts
|
|
105
116
|
#
|
106
117
|
# NOTE: this is a standalone DSL-syntax method.
|
107
118
|
def self.command(*args)
|
108
|
-
@@instances
|
119
|
+
@@instances.last.command(*args)
|
109
120
|
end
|
110
121
|
|
111
122
|
|
@@ -116,6 +127,7 @@ class Tryouts
|
|
116
127
|
def library(name=nil, path=nil)
|
117
128
|
return @library if name.nil?
|
118
129
|
@library = name.to_sym
|
130
|
+
@dtype = :api
|
119
131
|
$LOAD_PATH.unshift path unless path.nil?
|
120
132
|
require @library.to_s
|
121
133
|
end
|
@@ -123,7 +135,7 @@ class Tryouts
|
|
123
135
|
#
|
124
136
|
# NOTE: this is a standalone DSL-syntax method.
|
125
137
|
def self.library(*args)
|
126
|
-
@@instances
|
138
|
+
@@instances.last.library(*args)
|
127
139
|
end
|
128
140
|
|
129
141
|
def group(name=nil)
|
@@ -135,11 +147,11 @@ class Tryouts
|
|
135
147
|
@group
|
136
148
|
end
|
137
149
|
# Raises a Tryouts::Exception. +group+ is not support in the standalone syntax
|
138
|
-
# because the group name is
|
150
|
+
# because the group name is taken from the name of the class. See inherited.
|
139
151
|
#
|
140
152
|
# NOTE: this is a standalone DSL-syntax method.
|
141
153
|
def self.group(*args)
|
142
|
-
raise "Group is already set: #{@@instances
|
154
|
+
raise "Group is already set: #{@@instances.last.group}"
|
143
155
|
end
|
144
156
|
|
145
157
|
# Create a new Tryout object and add it to the list for this Tryouts class.
|
@@ -149,24 +161,34 @@ class Tryouts
|
|
149
161
|
# * +b+ is a block definition for the Tryout. See Tryout#from_block
|
150
162
|
#
|
151
163
|
# NOTE: This is a DSL-only method and is not intended for OO use.
|
152
|
-
def tryout(name,
|
164
|
+
def tryout(name, dtype=nil, command=nil, &block)
|
153
165
|
return if name.nil?
|
154
|
-
|
155
|
-
command ||= @command if
|
156
|
-
to =
|
166
|
+
dtype ||= @dtype
|
167
|
+
command ||= @command if dtype == :cli
|
168
|
+
to = find_tryout(name, dtype)
|
169
|
+
if to.nil?
|
170
|
+
to = Tryouts::Tryout.new(name, dtype, command)
|
171
|
+
@tryouts[name] = to
|
172
|
+
end
|
157
173
|
# Populate the dreams if they've already been loaded
|
158
174
|
to.dreams = @dreams[name] if @dreams.has_key?(name)
|
159
175
|
# Process the rest of the DSL
|
160
176
|
to.from_block block if block
|
161
|
-
@tryouts << to
|
162
|
-
@map[name] = @tryouts.size - 1
|
163
177
|
to
|
164
178
|
end
|
165
179
|
# Calls Tryouts#tryout on the current instance of Tryouts
|
166
180
|
#
|
167
181
|
# NOTE: this is a standalone DSL-syntax method.
|
168
182
|
def self.tryout(*args, &block)
|
169
|
-
@@instances
|
183
|
+
@@instances.last.tryout(*args, &block)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Find matching Tryout objects by +name+ and filter by
|
187
|
+
# +dtype+ if specified. Returns a Tryout object or nil.
|
188
|
+
def find_tryout(name, dtype=nil)
|
189
|
+
by_name = @tryouts.values.select { |t| t.name == name }
|
190
|
+
by_name = by_name.select { |t| t.dtype == dtype } if dtype
|
191
|
+
by_name.first # by_name is an Array. We just want the Object.
|
170
192
|
end
|
171
193
|
|
172
194
|
# This method does nothing. It provides a quick way to disable a tryout.
|
@@ -178,28 +200,45 @@ class Tryouts
|
|
178
200
|
# NOTE: this is a standalone DSL-syntax method.
|
179
201
|
def self.xtryout(*args, &block); end
|
180
202
|
|
181
|
-
# Load dreams from a file
|
203
|
+
# Load dreams from a file or directory or if a block is given
|
204
|
+
# it's processed
|
182
205
|
# Raises a Tryouts::BadDreams exception when something goes awry.
|
183
206
|
#
|
184
207
|
# This method is used in two ways:
|
185
208
|
# * In the dreams file DSL
|
186
|
-
# * As a getter method on a
|
209
|
+
# * As a getter method on a Tryouts object
|
187
210
|
def dreams(tryout_name=nil, &definition)
|
188
211
|
return @dreams unless tryout_name
|
212
|
+
|
213
|
+
#
|
214
|
+
# dreams "path/2/dreams"
|
215
|
+
# OR
|
216
|
+
# dreams "path/2/file_of_dreams.rb"
|
217
|
+
#
|
189
218
|
if File.exists?(tryout_name)
|
190
219
|
dfile = tryout_name
|
191
220
|
# If we're given a directory we'll build the filename using the class name
|
192
221
|
if File.directory?(tryout_name)
|
193
|
-
dfile = self.class.find_dreams_file(tryout_name, group)
|
222
|
+
dfile = self.class.find_dreams_file(tryout_name, @group)
|
194
223
|
end
|
195
224
|
raise BadDreams, "Cannot find dreams file (#{tryout_name})" unless dfile
|
196
|
-
@dreams = load_dreams_file dfile
|
197
|
-
|
198
|
-
|
225
|
+
@dreams = load_dreams_file( dfile) || {}
|
226
|
+
|
227
|
+
#
|
228
|
+
# dreams "Tryout Name" do
|
229
|
+
# dream "drill name" ...
|
230
|
+
# end
|
231
|
+
#
|
199
232
|
elsif tryout_name.kind_of?(String) && definition
|
200
|
-
|
201
|
-
|
202
|
-
|
233
|
+
to = find_tryout(tryout_name, @dtype)
|
234
|
+
|
235
|
+
if to.nil?
|
236
|
+
@dream_pointer = tryout_name # Used in Tryouts.dream
|
237
|
+
@dreams[ @dream_pointer ] ||= {}
|
238
|
+
definition.call
|
239
|
+
else
|
240
|
+
to.from_block &definition
|
241
|
+
end
|
203
242
|
else
|
204
243
|
raise BadDreams, tryout_name
|
205
244
|
end
|
@@ -217,7 +256,8 @@ class Tryouts
|
|
217
256
|
end
|
218
257
|
return dreams
|
219
258
|
else
|
220
|
-
|
259
|
+
# Call the Tryouts#dreams instance method
|
260
|
+
@@instances.last.dreams(*args, &block)
|
221
261
|
end
|
222
262
|
end
|
223
263
|
|
@@ -225,22 +265,34 @@ class Tryouts
|
|
225
265
|
# +output+ A String or Array of expected output. A Dream object will be created using this value (optional)
|
226
266
|
# +definition+ is a block which will be run on an instance of Dream
|
227
267
|
#
|
268
|
+
# This method is different than Tryout#dream because this one stores
|
269
|
+
# dreams inside an instance variable of the current Tryouts object.
|
270
|
+
# This allows for the situation where the dreams block appears before
|
271
|
+
# the tryout block. See Tryouts#tryout
|
228
272
|
#
|
229
273
|
# NOTE: This method is DSL-only. It's not intended to be used in OO syntax.
|
230
|
-
def dream(name, output=nil, format
|
231
|
-
|
232
|
-
|
274
|
+
def dream(name, output=nil, format=nil, rcode=0, emsg=nil, &definition)
|
275
|
+
to = find_tryout(@dream_pointer, @dtype)
|
276
|
+
if to.nil?
|
277
|
+
if output.nil?
|
278
|
+
dobj = Tryouts::Drill::Dream.from_block definition
|
279
|
+
else
|
280
|
+
dobj = Tryouts::Drill::Dream.new(output)
|
281
|
+
dobj.format, dobj.rcode, dobj.emsg = format, rcode, emsg
|
282
|
+
end
|
283
|
+
@dreams[@dream_pointer][name] = dobj
|
233
284
|
else
|
234
|
-
|
235
|
-
|
285
|
+
# Let the Tryout object process the dream DSL.
|
286
|
+
# We'll get here if the dream is placed after
|
287
|
+
# the drill with the same name in the same block.
|
288
|
+
to.dream name, output, format, rcode, emsg, &definition
|
236
289
|
end
|
237
|
-
@dreams[@dream_pointer][name] = dobj
|
238
290
|
end
|
239
291
|
# Calls Tryouts#dream on the current instance of Tryouts
|
240
292
|
#
|
241
293
|
# NOTE: this is a standalone DSL-syntax method.
|
242
294
|
def self.dream(*args, &block)
|
243
|
-
@@instances
|
295
|
+
@@instances.last.dream(*args, &block)
|
244
296
|
end
|
245
297
|
|
246
298
|
# Populate @@dreams with the content of the file +dpath+.
|
@@ -265,10 +317,15 @@ class Tryouts
|
|
265
317
|
# NOTE: this is an OO syntax method
|
266
318
|
def self.parse_file(fpath)
|
267
319
|
raise "No such file: #{fpath}" unless File.exists?(fpath)
|
320
|
+
file_content = File.read(fpath)
|
268
321
|
to = Tryouts.new
|
269
|
-
to.instance_eval
|
270
|
-
@@
|
271
|
-
|
322
|
+
to.instance_eval file_content, fpath
|
323
|
+
if @@instances.has_key? to.group
|
324
|
+
to = @@instances[to.group]
|
325
|
+
to.instance_eval file_content, fpath
|
326
|
+
end
|
327
|
+
to.paths << fpath
|
328
|
+
@@instances[to.group] = to
|
272
329
|
end
|
273
330
|
|
274
331
|
# Run all Tryout objects in +@tryouts+
|
@@ -276,9 +333,7 @@ class Tryouts
|
|
276
333
|
# NOTE: this is an OO syntax method
|
277
334
|
def self.run
|
278
335
|
@@instances.each_pair do |group, inst|
|
279
|
-
|
280
|
-
puts "Tryouts for #{group}"
|
281
|
-
inst.tryouts.each do |to|
|
336
|
+
inst.tryouts.each_pair do |name,to|
|
282
337
|
to.run
|
283
338
|
to.report
|
284
339
|
STDOUT.flush
|
@@ -292,10 +347,11 @@ class Tryouts
|
|
292
347
|
#
|
293
348
|
# NOTE: this is a standalone DSL-syntax method.
|
294
349
|
def self.inherited(klass)
|
295
|
-
to =
|
350
|
+
to = @@instances[ klass ]
|
351
|
+
to ||= Tryouts.new
|
352
|
+
to.paths << __FILE__
|
296
353
|
to.group = klass
|
297
|
-
@@
|
298
|
-
@@instances[ @@instance_pointer ] = to
|
354
|
+
@@instances[to.group] = to
|
299
355
|
end
|
300
356
|
|
301
357
|
|
@@ -318,7 +374,7 @@ class Tryouts
|
|
318
374
|
#
|
319
375
|
def self.find_dreams_file(dir, group=nil)
|
320
376
|
dpath = nil
|
321
|
-
group ||= @@
|
377
|
+
group ||= @@instances.last.group
|
322
378
|
group = group.to_s.downcase.tr(' ', '')
|
323
379
|
[:rb, :yaml].each do |ext|
|
324
380
|
tmp = File.join(dir, "#{group}_dreams.#{ext}")
|
@@ -2,13 +2,13 @@
|
|
2
2
|
dreams "Common Usage" do
|
3
3
|
dream "No args" do
|
4
4
|
output inline(%Q{
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
Date: 2009-02-16
|
6
|
+
Owners: greg, rupaul, telly, prince kinko
|
7
|
+
Players: d-bam, alberta, birds, condor man
|
8
8
|
})
|
9
9
|
end
|
10
10
|
dream "YAML Output" do
|
11
|
-
format :
|
11
|
+
format :to_yaml
|
12
12
|
output ({
|
13
13
|
"Date" => "2009-02-16",
|
14
14
|
"Players" => ["d-bam", "alberta", "birds", "condor man"],
|
@@ -4,12 +4,13 @@ MOCKOUT_PATH = File.join(TRYOUTS_HOME, "bin", "mockout")
|
|
4
4
|
|
5
5
|
group "mockout cli"
|
6
6
|
command :mockout, MOCKOUT_PATH
|
7
|
+
dreams File.join(GYMNASIUM_HOME, 'mockoutcli_dreams.rb')
|
7
8
|
|
8
9
|
tryout "Common Usage" do
|
9
10
|
drill "No Command"
|
10
|
-
drill "No args",
|
11
|
-
drill "YAML Output", :f,
|
12
|
-
drill "JSON Output", :f,
|
11
|
+
drill "No args", :info
|
12
|
+
drill "YAML Output", :f, :yaml, :info
|
13
|
+
drill "JSON Output", :f, :json, :info
|
13
14
|
end
|
14
15
|
|
15
16
|
tryout "inline dream that passes", :cli, :mockout do
|
data/tryouts.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
@spec = Gem::Specification.new do |s|
|
2
2
|
s.name = "tryouts"
|
3
3
|
s.rubyforge_project = "tryouts"
|
4
|
-
s.version = "0.4.
|
4
|
+
s.version = "0.4.1"
|
5
5
|
s.summary = "Tryouts are high-level tests for your Ruby code. May all your dreams come true!"
|
6
6
|
s.description = s.summary
|
7
7
|
s.author = "Delano Mandelbaum"
|