delano-tryouts 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|