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 CHANGED
@@ -1,6 +1,11 @@
1
1
  TRYOUTS, CHANGES
2
2
 
3
3
 
4
+ #### 0.4.1 (2009-06-07) ###############################
5
+
6
+ * CHANGE: The CLI output is no longer terrifyingly ugly.
7
+
8
+
4
9
  #### 0.4.0 (2009-06-05) ###############################
5
10
 
6
11
  NOTE: Initial public release
data/README.rdoc CHANGED
@@ -1,11 +1,7 @@
1
- = Tryouts - v0.5 ALPHA
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", :cli do
26
+ tryout "Common Usage" do
31
27
  drill "No Command"
32
- drill "YAML Output", :f, "yaml"
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", :api do
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 :on
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
@@ -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
- Tryouts.run
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 > 0
38
- puts Tryouts.instances.to_yaml
39
- else
40
- Tryouts.instances.each_pair do |n,tryouts|
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
- tryouts.tryouts.each do |tryout|
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
- if @argv.files
57
- @argv.files.each do |file|
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.uniq!
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
- @format ||= :string
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
- return true if @output == other.output
43
-
44
- if @format == :class
45
- if @output.is_a?(Class)
46
- klass, payload = @output, other.output
47
- elsif other.output.is_a?(Class)
48
- klass, payload = other.output, @output
49
- end
50
- return payload.is_a?(klass)
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
- if @output.kind_of?(Array) && other.kind_of?(Array)
54
- return false unless @output.size == other.output.size
55
-
56
- if @output.first.is_a?(Regexp)
57
- expressions, strings = @output, other.output
58
- elsif other.output.first.is_a?(Regexp)
59
- expressions, strings = other.output, @output
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($/) || []).collect { |line| line.strip }
98
- lines.reject! { |line| line == "" }
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 this Sergeant.
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(*drill_args)
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
- context ||= Class.new
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 @dream.output != @reality.output
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.to_s == "yaml"
89
+ if @dream.format == :to_yaml
88
90
  @reality.output = YAML.load(@reality.output.join("\n"))
89
- elsif @dream.format.to_s == "json"
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
 
@@ -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
- @dreams = {}
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
- instance_eval &b
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.new.instance_eval &setup if setup.is_a?(Proc)
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.new.instance_eval &clean if clean.is_a?(Proc)
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
- puts $/, "All your dreams came true"
72
- return
73
- end
74
- puts $/, "ERRORS:"
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.discrepency.each do |d|
85
- puts '%24s: %s' % ["dream #{d}", drill.dream.send(d).inspect]
86
- puts '%24s: %s' % ["reality #{d}", drill.reality.send(d).inspect]
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: %s' % ["backtrace", drill.reality.backtrace.inspect]
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=:string, rcode=0, emsg=nil, &definition)
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, &b)
163
+ def drill(name, *args, &definition)
165
164
  args.unshift(@command) if @dtype == :cli
166
- drill = Tryouts::Drill.new(name, @dtype, *args, &b)
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.0"
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
- TRYOUT_MSG = "\n %s "
40
- DRILL_MSG = ' %20s: '
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
- # The most recent tryouts name specified in the DSL
45
- @@instance_pointer = nil
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
- @map = {}
79
+ @tryouts = HASH_TYPE.new
80
+ @paths = []
74
81
  @command = nil
75
- @dtype = :cli
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; @tryouts.each { |to| to.report }; end
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.each { |to| to.run }; end
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[ @@instance_pointer ].command(*args)
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[ @@instance_pointer ].library(*args)
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 take from the name of the class. See inherited.
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[ @@instance_pointer ].group}"
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, type=nil, command=nil, &block)
164
+ def tryout(name, dtype=nil, command=nil, &block)
153
165
  return if name.nil?
154
- type ||= @dtype
155
- command ||= @command if type == :cli
156
- to = Tryouts::Tryout.new(name, type, command)
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[ @@instance_pointer ].tryout(*args, &block)
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, or Hash.
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 Tryout object
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
- elsif tryout_name.kind_of?(Hash)
198
- @dreams = tryout_name
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
- @dream_pointer = tryout_name # Used in Tryouts.dream
201
- @dreams[ @dream_pointer ] ||= {}
202
- definition.call
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
- @@instances[ @@instance_pointer ].dreams(*args, &block)
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=:string, rcode=0, emsg=nil, &definition)
231
- if output.nil?
232
- dobj = Tryouts::Drill::Dream.from_block definition
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
- dobj = Tryouts::Drill::Dream.new(output)
235
- dobj.format, dobj.rcode, dobj.emsg = format, rcode, emsg
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[ @@instance_pointer ].dream(*args, &block)
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(File.read(fpath), fpath)
270
- @@instance_pointer = to.group
271
- @@instances[ @@instance_pointer ] = to
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
- puts "-"*60
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 = Tryouts.new
350
+ to = @@instances[ klass ]
351
+ to ||= Tryouts.new
352
+ to.paths << __FILE__
296
353
  to.group = klass
297
- @@instance_pointer = to.group
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 ||= @@instance_pointer
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
- Date: 2009-02-16
6
- Owners: greg, rupaul, telly, prince kinko
7
- Players: d-bam, alberta, birds, condor man
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 :yaml
11
+ format :to_yaml
12
12
  output ({
13
13
  "Date" => "2009-02-16",
14
14
  "Players" => ["d-bam", "alberta", "birds", "condor man"],
@@ -3,7 +3,6 @@ common usage:
3
3
  :format: :yaml
4
4
  :rcode: 0
5
5
  no args:
6
- :format: :string
7
6
  :rcode: 0
8
7
  :output:
9
8
  - " Date: 2009-02-16\n"
@@ -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", :info
11
- drill "YAML Output", :f, "yaml", :info
12
- drill "JSON Output", :f, "json", :info
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.0"
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"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delano-tryouts
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum