assert-view 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile.lock CHANGED
@@ -1,15 +1,18 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- assert-view (0.1.0)
4
+ assert-view (0.2.0)
5
+ undies (~> 1.1)
5
6
 
6
7
  GEM
7
8
  remote: http://rubygems.org/
8
9
  specs:
9
10
  ansi (1.3.0)
10
- assert (0.3.0)
11
+ assert (0.4.0)
11
12
  ansi (~> 1.3)
13
+ assert-view
12
14
  rake (0.9.2)
15
+ undies (1.1.0)
13
16
 
14
17
  PLATFORMS
15
18
  ruby
data/assert-view.gemspec CHANGED
@@ -19,4 +19,6 @@ Gem::Specification.new do |s|
19
19
 
20
20
  s.add_development_dependency("bundler")
21
21
  s.add_development_dependency("assert")
22
+
23
+ s.add_dependency("undies", ["~> 1.1"])
22
24
  end
@@ -1,4 +1,5 @@
1
1
  require 'assert/options'
2
+ require 'assert/view/renderer'
2
3
 
3
4
  module Assert::View
4
5
 
@@ -12,49 +13,103 @@ module Assert::View
12
13
  default_errored_abbrev 'E'
13
14
  end
14
15
 
15
- attr_reader :suite
16
+ # the Renderer defines the hooks and callbacks needed for the runner to
17
+ # work with the view. It provides:
18
+ # * 'render': called by the runner to render the view
19
+ # * 'self.helper': used to provide helper mixins to the renderer template
20
+ include Renderer
21
+
22
+ attr_accessor :suite, :output_io, :runtime_result_callback
16
23
 
17
24
  def initialize(output_io, suite=Assert.suite)
18
- @suite = suite
19
- @out = output_io
25
+ self.suite = suite
26
+ self.output_io = output_io
20
27
  end
21
28
 
22
- # override this to define how a view calls the runner and renders its results
23
- def render(*args, &runner)
29
+ def view
30
+ self
24
31
  end
25
32
 
26
- def handle_runtime_result(result)
33
+
34
+
35
+ # TODO: look for files in the .assert dir
36
+ # TODO: allow option for specifying which template to use
37
+ # TODO: test
38
+ def template_file
39
+ File.expand_path("./templates/#{self.options.template}.rb", File.dirname(__FILE__))
27
40
  end
28
41
 
29
- protected
30
42
 
31
- def io_puts(msg, opts={})
32
- @out.puts(io_msg(msg, opts={}))
43
+
44
+ # called by the view template
45
+ # store off any result_callback
46
+ # call the runner callback to actually run the tests
47
+ def run_tests(runner_callback, &result_callback)
48
+ self.runtime_result_callback = result_callback
49
+ runner_callback.call if runner_callback
33
50
  end
34
51
 
35
- def io_print(msg, opts={})
36
- @out.print(io_msg(msg, opts={}))
52
+ # callback used by the runner to notify the view of any new results
53
+ # pipes the runtime result to any result callback block
54
+ def handle_runtime_result(result)
55
+ self.runtime_result_callback.call(result) if self.runtime_result_callback
37
56
  end
38
57
 
58
+ # get the formatted suite run time
39
59
  def run_time(format='%.6f')
40
- format % @suite.run_time
60
+ format % self.suite.run_time
41
61
  end
42
62
 
43
63
  def runner_seed
44
- @suite.runner_seed
64
+ self.suite.runner_seed
45
65
  end
46
66
 
47
67
  def count(type)
48
- @suite.count(type)
68
+ self.suite.count(type)
69
+ end
70
+
71
+ # TODO: test
72
+ def tests?
73
+ self.count(:tests) > 0
74
+ end
75
+
76
+ def all_passed?
77
+ self.count(:passed) == self.count(:results)
49
78
  end
50
79
 
51
- private
80
+ # return a list of result symbols that have actually occurred
81
+ def ocurring_result_types
82
+ @result_types ||= [
83
+ :passed, :failed, :ignored, :skipped, :errored
84
+ ].select { |result_sym| self.count(result_sym) > 0 }
85
+ end
86
+
87
+ # print a result summary message for a given result type
88
+ def result_summary_msg(result_type)
89
+ if result_type == :passed && self.all_passed?
90
+ self.all_passed_result_summary_msg
91
+ else
92
+ "#{self.count(result_type)} #{result_type.to_s}"
93
+ end
94
+ end
95
+
96
+ # generate an appropriate result summary msg for all tests passing
97
+ def all_passed_result_summary_msg
98
+ if self.count(:results) < 1
99
+ "uhh..."
100
+ elsif self.count(:results) == 1
101
+ "it passed"
102
+ else
103
+ "all passed"
104
+ end
105
+ end
52
106
 
53
- def io_msg(msg, opts={})
54
- if msg.kind_of?(::Symbol) && self.respond_to?(msg)
55
- self.send(msg).to_s
107
+ # generate a comma-seperated sentence fragment given a list of things
108
+ def to_sentence(things)
109
+ if things.size <= 2
110
+ things.join(things.size == 2 ? ' and ' : '')
56
111
  else
57
- msg.to_s
112
+ [things[0..-2].join(", "), things.last].join(", and ")
58
113
  end
59
114
  end
60
115
 
@@ -0,0 +1,25 @@
1
+ require 'ansi/code'
2
+
3
+ module Assert::View::Helpers
4
+
5
+ module AnsiStyles
6
+
7
+ def result_ansi_styles(result)
8
+ view.options.styled ? view.options.send("#{result.to_sym}_styles") : []
9
+ end
10
+
11
+ def ansi_styled_msg(msg, styles=[])
12
+ if !(style = ansi_style(*styles)).empty?
13
+ style + msg + ANSI.send(:reset)
14
+ else
15
+ msg
16
+ end
17
+ end
18
+
19
+ def ansi_style(*ansi_codes)
20
+ ansi_codes.collect{|code| ANSI.send(code) rescue nil}.compact.join('')
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,45 @@
1
+ require 'undies'
2
+
3
+ module Assert::View
4
+
5
+ # this module is mixed in to the Assert::View::Base class
6
+ # it use Undies to define and render view templates
7
+ module Renderer
8
+
9
+ def self.included(receiver)
10
+ receiver.send(:extend, ClassMethods)
11
+ end
12
+
13
+ # define rendering template class to use for rendering
14
+ # need to overwrite the '_' and '__' meths to add trailing newlines
15
+ # b/c streaming output doesn't add any whitespace
16
+ class Template < ::Undies::Template
17
+
18
+ def _(data="", nl=true); super(data.to_s + (nl ? "\n" : "")); end
19
+ def __(data="", nl=true); super(data.to_s + (nl ? "\n" : "")); end
20
+
21
+ end
22
+
23
+ # this method is required by assert and is called by the test runner
24
+ # use Undies to render the template
25
+ # using the view's template file
26
+ # streaming to the view's output io
27
+ # passing in the view itself and any runner_callback as locals
28
+ def render(*args, &runner_callback)
29
+ Template.new(File.expand_path(self.template_file), self.output_io, {
30
+ :view => self,
31
+ :runner => runner_callback
32
+ })
33
+ end
34
+
35
+ module ClassMethods
36
+
37
+ # make any helper methods available to the template
38
+ def helper(helper_klass)
39
+ Template.send(:include, helper_klass)
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,36 @@
1
+ __
2
+ __ view.loaded_tests_statement
3
+
4
+ if view.tests?
5
+
6
+ __ view.running_tests_statement
7
+
8
+ view.run_tests(runner) do |each_result|
9
+ result_sym = each_result.to_sym
10
+ result_abbrev = view.options.send("#{result_sym}_abbrev")
11
+ __ ansi_styled_msg(result_abbrev, result_ansi_styles(result_sym)), false
12
+ end
13
+ __ "\n" # add a newline after streamed runner output
14
+
15
+ view.detailed_results do |result, output|
16
+ __ ansi_styled_msg(result.to_s, result_ansi_styles(result))
17
+
18
+ if !output.empty?
19
+ __ view.result_output_start_msg
20
+ __ output, false
21
+ __ view.result_output_end_msg
22
+ end
23
+
24
+ __
25
+ end
26
+
27
+ end
28
+
29
+ # build a summary sentence w/ styled results breakdown
30
+ styled_results_breakdown_statement = view.results_breakdown_statement do |msg, result_type|
31
+ ansi_styled_msg(msg, result_ansi_styles(result_type))
32
+ end
33
+
34
+ __ [ view.result_count_statement, ": ", styled_results_breakdown_statement ].join('')
35
+ __
36
+ __ view.run_time_statement
@@ -1,129 +1,64 @@
1
- require 'assert/view/base'
2
1
  require 'assert/result'
3
-
4
- require 'ansi/code'
2
+ require 'assert/options'
3
+ require 'assert/view/base'
5
4
 
6
5
  module Assert::View
7
6
 
8
7
  class Terminal < Base
9
8
 
10
- options do
11
- default_styled false
12
- default_passed_styles :green
13
- default_failed_styles :red, :bold
14
- default_errored_styles :yellow, :bold
15
- default_skipped_styles :cyan
16
- default_ignored_styles :magenta
17
- end
18
-
19
- def render(*args, &runner)
20
- self.io_puts(:load_stmt)
21
-
22
- if count(:tests) > 0
23
- self.io_puts(:run_stmt)
24
- runner.call if runner
25
- self.io_puts(:detailed_results)
26
- end
27
-
28
- self.io_puts(:results_stmt)
9
+ def loaded_tests_statement
10
+ "Loaded suite (#{view.count(:tests)} test#{'s' if view.count(:tests) != 1})"
29
11
  end
30
12
 
31
- def handle_runtime_result(result)
32
- sym = result.to_sym
33
- self.io_print(result_io_msg(self.options.send("#{sym}_abbrev"), sym))
34
- end
35
-
36
- protected
37
-
38
- def load_stmt
39
- tplur = (tcount = count(:tests)) == 1 ? "test": "tests"
40
- "\nLoaded suite (#{tcount} #{tplur})"
13
+ def running_tests_statement
14
+ "Running tests in random order, seeded with: \"#{self.runner_seed}\""
41
15
  end
42
16
 
43
- def run_stmt
44
- "Running tests in random order, seed: '#{self.runner_seed}'"
17
+ # show test details in reverse order from how they were collected (FILO)
18
+ def detailed_tests
19
+ @detailed_tests ||= self.suite.ordered_tests.reverse
45
20
  end
46
21
 
47
- def detailed_results
48
- details = self.suite.ordered_tests.reverse.collect do |test|
49
- test.results.collect do |result|
50
- if show_result_details?(result)
51
- [ result_io_msg(result.to_s, result.to_sym),
52
- output_io_msg(test.output.to_s)
53
- ].join("\n")
54
- end
55
- end
56
- end.flatten.compact
57
- "\n\n" + details.join("\n\n") if !details.empty?
22
+ # get all the results that have details to show
23
+ # in addition, if a block is given...
24
+ # yield each result with its test output
25
+ def detailed_results(test=nil)
26
+ tests = test.nil? ? self.detailed_tests : [test]
27
+ tests.collect do |test|
28
+ test.results.
29
+ select { |result| self.show_result_details?(result) }.
30
+ each {|r| yield r, test.output if block_given?}
31
+ end.compact.flatten
58
32
  end
59
33
 
60
- def results_stmt
61
- rplur = (rcount = count(:results)) == 1 ? "result" : "results"
62
- [ "\n",
63
- "#{rcount} test #{rplur}: ", results_breakdown, "\n\n",
64
- "(#{self.run_time} seconds)"
65
- ].join('')
34
+ # only show result details for failed or errored results
35
+ # show result details if a skip or passed result was issues w/ a message
36
+ def show_result_details?(result)
37
+ ([:failed, :errored].include?(result.to_sym)) ||
38
+ ([:skipped, :ignored].include?(result.to_sym) && result.message)
66
39
  end
67
40
 
68
- def results_breakdown
69
- if count(:passed) == count(:results)
70
- stmnt = if count(:results) < 1
71
- "uhh..."
72
- elsif count(:results) == 1
73
- "it passed"
74
- else
75
- "all passed"
76
- end
77
- result_io_msg(stmnt, :passed)
78
- else
79
- breakdowns = [:passed, :failed, :ignored, :skipped, :errored]
80
- breakdowns = breakdowns.inject([]) do |results, result_sym|
81
- results << (if count(result_sym) > 0
82
- result_io_msg("#{count(result_sym)} #{result_sym}", result_sym)
83
- end)
84
- end.compact
85
- if breakdowns.size < 2
86
- breakdowns.join('')
87
- elsif breakdowns.size == 2
88
- breakdowns.join(" and ")
89
- else
90
- [breakdowns[0..-2].join(", "), breakdowns.last].join(", and ")
91
- end
92
- end
41
+ def result_output_start_msg
42
+ "--- stdout ---"
93
43
  end
94
-
95
- def result_io_msg(msg, result_sym)
96
- term_styles = if self.options.styled
97
- self.options.send("#{result_sym}_styles")
98
- end
99
- io_msg(msg, :term_styles => term_styles)
44
+ def result_output_end_msg
45
+ "--------------"
100
46
  end
101
47
 
102
- def output_io_msg(output)
103
- if output && !output.empty?
104
- [ "--- stdout ---",
105
- io_msg(output),
106
- "--------------"
107
- ].collect{|i| i.strip}.join("\n")
108
- end
48
+ # generate a sentence fragment describing the breakdown of test results
49
+ # if a block is given, yield each msg in the breakdown for custom template formatting
50
+ def results_breakdown_statement
51
+ self.to_sentence(self.ocurring_result_types.collect do |result_type|
52
+ yield(self.result_summary_msg(result_type), result_type) if block_given?
53
+ end)
109
54
  end
110
55
 
111
- def io_msg(msg, opts={})
112
- val = super
113
- if !(style = term_style(*opts[:term_styles])).empty?
114
- val = style + val + ANSI.send(:reset)
115
- else
116
- val
117
- end
56
+ def result_count_statement
57
+ "#{self.count(:results)} test result#{'s' if self.count(:results) != 1}"
118
58
  end
119
59
 
120
- def term_style(*ansi_codes)
121
- ansi_codes.collect{|code| ANSI.send(code) rescue nil}.compact.join('')
122
- end
123
-
124
- def show_result_details?(result)
125
- ([:failed, :errored].include?(result.to_sym)) ||
126
- ([:skipped, :ignored].include?(result.to_sym) && result.message)
60
+ def run_time_statement
61
+ "(#{self.run_time} seconds)"
127
62
  end
128
63
 
129
64
  end
@@ -1,5 +1,5 @@
1
1
  module Assert; end
2
2
 
3
3
  module Assert::View
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/assert/view.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  module Assert; end
2
- module Assert::Views; end
2
+ module Assert::View; end
data/test/base_test.rb CHANGED
@@ -7,16 +7,26 @@ require 'stringio'
7
7
  module Assert::View
8
8
 
9
9
  class BaseTest < Assert::Context
10
- desc "the view base"
10
+ desc "the base view"
11
11
  setup do
12
12
  @view = Assert::View::Base.new(Assert::Suite.new, StringIO.new("", "w+"))
13
13
  end
14
14
  subject{ @view }
15
15
 
16
- should have_reader :suite
17
- should have_instance_methods :render, :handle_runtime_result, :options
16
+ should have_accessors :suite, :output_io, :runtime_result_callback
17
+ should have_instance_methods :template_file, :run_tests, :handle_runtime_result
18
+ should have_instance_methods :run_time, :runner_seed, :count, :tests?, :all_passed?
19
+ should have_instance_methods :ocurring_result_types, :result_summary_msg
20
+ should have_instance_methods :all_passed_result_summary_msg, :to_sentence
21
+
22
+ # options stuff
23
+ should have_instance_method :options
18
24
  should have_class_method :options
19
25
 
26
+ # renderer stuff
27
+ should have_instance_method :render
28
+ should have_class_method :helper
29
+
20
30
  end
21
31
 
22
32
  class BaseOptionsTest < Assert::Context
@@ -39,6 +49,4 @@ module Assert::View
39
49
 
40
50
  end
41
51
 
42
-
43
-
44
52
  end
@@ -1,32 +1,22 @@
1
1
  require 'assert'
2
- require 'assert/options'
3
2
 
4
3
  require 'assert/view/terminal'
4
+ require 'stringio'
5
5
 
6
6
  module Assert::View
7
7
 
8
- class TerminalOptionsTest < Assert::Context
9
- desc "options for the terminal view"
10
- subject do
11
- Assert::View::Terminal.options
8
+ class TerminalTest < Assert::Context
9
+ desc "the terminal view"
10
+ setup do
11
+ @view = Assert::View::Terminal.new(Assert::Suite.new, StringIO.new("", "w+"))
12
12
  end
13
+ subject{ @view }
13
14
 
14
- should "be an Options::Base object" do
15
- assert_kind_of Assert::Options::Base, subject
16
- end
17
-
18
- should "default the styled option" do
19
- assert_equal false, subject.default_styled
20
- end
21
-
22
- should "default its result styles" do
23
- assert_equal :green, subject.default_passed_styles
24
- assert_equal [:red, :bold], subject.default_failed_styles
25
- assert_equal :magenta, subject.default_ignored_styles
26
- assert_equal :cyan, subject.default_skipped_styles
27
- assert_equal [:yellow, :bold], subject.default_errored_styles
28
- end
15
+ should have_instance_methods :loaded_tests_statement, :running_tests_statement
16
+ should have_instance_methods :detailed_tests, :detailed_results, :show_result_details?
17
+ should have_instance_methods :result_output_start_msg, :result_output_end_msg
18
+ should have_instance_methods :results_breakdown_statement, :result_count_statement
19
+ should have_instance_methods :run_time_statement
29
20
 
30
21
  end
31
-
32
22
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: assert-view
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 1
8
+ - 2
9
9
  - 0
10
- version: 0.1.0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Kelly Redding
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-31 00:00:00 Z
18
+ date: 2011-09-08 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  type: :development
@@ -45,6 +45,21 @@ dependencies:
45
45
  version: "0"
46
46
  version_requirements: *id002
47
47
  name: assert
48
+ - !ruby/object:Gem::Dependency
49
+ type: :runtime
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ hash: 13
57
+ segments:
58
+ - 1
59
+ - 1
60
+ version: "1.1"
61
+ version_requirements: *id003
62
+ name: undies
48
63
  description: A collection of views for use in the Assert testing framework
49
64
  email:
50
65
  - kelly@kelredd.com
@@ -63,6 +78,9 @@ files:
63
78
  - assert-view.gemspec
64
79
  - lib/assert/view.rb
65
80
  - lib/assert/view/base.rb
81
+ - lib/assert/view/helpers/ansi.rb
82
+ - lib/assert/view/renderer.rb
83
+ - lib/assert/view/templates/assert.ansi.rb
66
84
  - lib/assert/view/terminal.rb
67
85
  - lib/assert/view/version.rb
68
86
  - test/base_test.rb