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 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