lemon 0.8.1 → 0.8.2

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.
Files changed (79) hide show
  1. data/HISTORY.rdoc +15 -0
  2. data/README.rdoc +32 -14
  3. data/bin/lemon +3 -2
  4. data/demo/case_example_fail.rb +15 -0
  5. data/demo/case_example_pass.rb +32 -0
  6. data/demo/case_example_pending.rb +14 -0
  7. data/demo/case_example_untested.rb +10 -0
  8. data/demo/fixture/example-use.rb +5 -0
  9. data/demo/fixture/example.rb +20 -0
  10. data/lib/lemon.rb +2 -2
  11. data/lib/lemon/cli.rb +281 -0
  12. data/lib/lemon/controller/coverage_analyzer.rb +343 -0
  13. data/lib/lemon/controller/scaffold_generator.rb +110 -0
  14. data/lib/lemon/controller/test_runner.rb +284 -0
  15. data/lib/lemon/meta/data.rb +29 -0
  16. data/lib/lemon/meta/gemfile +24 -0
  17. data/{PROFILE → lib/lemon/meta/profile} +6 -5
  18. data/lib/lemon/model/ae.rb +4 -0
  19. data/lib/lemon/model/cover_unit.rb +75 -0
  20. data/lib/lemon/{dsl.rb → model/main.rb} +22 -28
  21. data/lib/lemon/model/pending.rb +10 -0
  22. data/lib/lemon/model/snapshot.rb +203 -0
  23. data/lib/lemon/model/source_parser.rb +198 -0
  24. data/lib/lemon/model/test_case.rb +221 -0
  25. data/lib/lemon/model/test_context.rb +90 -0
  26. data/lib/lemon/model/test_suite.rb +216 -0
  27. data/lib/lemon/{test/unit.rb → model/test_unit.rb} +40 -28
  28. data/lib/lemon/{coversheet → view/cover_reports}/abstract.rb +19 -20
  29. data/lib/lemon/view/cover_reports/compact.rb +37 -0
  30. data/lib/lemon/view/cover_reports/outline.rb +45 -0
  31. data/lib/lemon/view/cover_reports/verbose.rb +51 -0
  32. data/lib/lemon/view/cover_reports/yaml.rb +15 -0
  33. data/lib/lemon/view/test_reports/abstract.rb +149 -0
  34. data/lib/lemon/view/test_reports/dotprogress.rb +73 -0
  35. data/lib/lemon/view/test_reports/html.rb +146 -0
  36. data/lib/lemon/view/test_reports/outline.rb +118 -0
  37. data/lib/lemon/view/test_reports/summary.rb +131 -0
  38. data/lib/lemon/view/test_reports/tap.rb +49 -0
  39. data/lib/lemon/view/test_reports/verbose.rb +197 -0
  40. data/meta/data.rb +29 -0
  41. data/meta/gemfile +24 -0
  42. data/meta/profile +17 -0
  43. data/test/api/applique/fs.rb +18 -0
  44. data/test/api/coverage/complete.rdoc +136 -0
  45. data/test/api/coverage/extensions.rdoc +61 -0
  46. data/test/api/coverage/incomplete.rdoc +97 -0
  47. data/{features → test/cli}/coverage.feature +4 -4
  48. data/{features → test/cli}/generate.feature +2 -2
  49. data/{features → test/cli}/step_definitions/coverage_steps.rb +0 -0
  50. data/{features → test/cli}/support/ae.rb +0 -0
  51. data/{features → test/cli}/support/aruba.rb +0 -0
  52. data/{features → test/cli}/test.feature +0 -0
  53. data/test/fixtures/case_complete.rb +17 -4
  54. data/test/fixtures/case_inclusion.rb +18 -0
  55. data/test/fixtures/case_incomplete.rb +4 -4
  56. data/test/fixtures/example.rb +5 -0
  57. data/test/fixtures/helper.rb +13 -0
  58. data/test/runner +3 -0
  59. data/test/unit/case_coverage_analyzer.rb +25 -0
  60. data/test/unit/case_test_case_dsl.rb +46 -0
  61. metadata +87 -42
  62. data/REQUIRE +0 -9
  63. data/VERSION +0 -6
  64. data/lib/lemon/command.rb +0 -184
  65. data/lib/lemon/coverage.rb +0 -260
  66. data/lib/lemon/coversheet/outline.rb +0 -47
  67. data/lib/lemon/kernel.rb +0 -24
  68. data/lib/lemon/reporter.rb +0 -22
  69. data/lib/lemon/reporter/abstract.rb +0 -97
  70. data/lib/lemon/reporter/dotprogress.rb +0 -68
  71. data/lib/lemon/reporter/outline.rb +0 -105
  72. data/lib/lemon/reporter/verbose.rb +0 -143
  73. data/lib/lemon/runner.rb +0 -308
  74. data/lib/lemon/snapshot.rb +0 -185
  75. data/lib/lemon/test/case.rb +0 -139
  76. data/lib/lemon/test/concern.rb +0 -52
  77. data/lib/lemon/test/suite.rb +0 -229
  78. data/test/case_coverage.rb +0 -26
  79. data/test/case_testcase.rb +0 -58
@@ -0,0 +1,37 @@
1
+ require 'lemon/view/cover_reports/abstract'
2
+
3
+ module Lemon::CoverReports
4
+
5
+ class Compact < Abstract
6
+
7
+ #
8
+ def render
9
+
10
+ unless covered_units.empty?
11
+ puts "\nCovered Units: "
12
+ puts covered_units.map{ |u| u.to_s.ansi(:green) }.sort.join(', ')
13
+ end
14
+
15
+ unless undefined_units.empty?
16
+ puts "\nOvercovered Units:"
17
+ puts undefined_units.map{ |u| u.to_s.ansi(:cyan) }.sort.join(', ')
18
+ end
19
+
20
+ unless uncovered_units.empty?
21
+ puts "\nUncovered Units: "
22
+ puts uncovered_units.map{ |u| u.to_s.ansi(:yellow) }.sort.join(', ')
23
+ end
24
+
25
+ unless uncovered_cases.empty?
26
+ puts "\nUncovered Cases: "
27
+ puts uncovered_cases.map{ |m| m.name.ansi(:red) }.sort.join(', ')
28
+ end
29
+
30
+ puts
31
+ puts tally
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+
@@ -0,0 +1,45 @@
1
+ require 'lemon/view/cover_reports/abstract'
2
+
3
+ module Lemon::CoverReports
4
+
5
+ class Outline < Abstract
6
+
7
+ #
8
+ def render
9
+
10
+ unless covered_units.empty?
11
+ puts "\nCovered Units:"
12
+ covered_units.map do |unit|
13
+ puts "* #{unit.to_s.ansi(:green)}"
14
+ end.join(", ")
15
+ end
16
+
17
+ unless uncovered_units.empty?
18
+ puts "\nUncovered Units:"
19
+ uncovered_units.map do |unit|
20
+ puts "* #{unit.to_s.ansi(:yellow)}"
21
+ end
22
+ end
23
+
24
+ unless undefined_units.empty?
25
+ puts "\nUndefined Units:"
26
+ unc = undefined_units.map do |unit|
27
+ puts "* #{unit.to_s.ansi(:red)}"
28
+ end
29
+ end
30
+
31
+ unless uncovered_cases.empty?
32
+ puts "\nUncovered Cases:"
33
+ uncovered_cases.map do |mod|
34
+ puts "* #{mod.name.ansi(:cyan)}"
35
+ end
36
+ end
37
+
38
+ puts
39
+ puts tally
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
@@ -0,0 +1,51 @@
1
+ require 'lemon/view/cover_reports/abstract'
2
+
3
+ module Lemon::CoverReports
4
+
5
+ class Verbose < Abstract
6
+
7
+ #
8
+ def render
9
+
10
+ unless covered_units.empty?
11
+ puts "\nCovered Cases: "
12
+ covered_units.map do |unit|
13
+ puts unit_line(unit, :green)
14
+ end
15
+ end
16
+
17
+ unless uncovered_units.empty?
18
+ puts "\nUncovered Units: "
19
+ uncovered_units.map do |unit|
20
+ puts unit_line(unit, :yellow)
21
+ end
22
+ end
23
+
24
+ unless undefined_units.empty?
25
+ puts "\nUndefined Units: "
26
+ undefined_units.map do |unit|
27
+ puts unit_line(unit, :red)
28
+ end
29
+ end
30
+
31
+ unless uncovered_cases.empty?
32
+ puts "\nUncovered Cases: "
33
+ uncovered_cases.map do |mod|
34
+ puts "* " + mod.name.to_s.ansi(:yellow)
35
+ end
36
+ end
37
+
38
+ puts
39
+ puts tally
40
+ end
41
+
42
+ #
43
+ def unit_line(unit, color)
44
+ data = [unit.to_s.ansi(color), unit.access.to_s, unit.function? ? 'function' : 'instance method']
45
+ "* %s %s %s" % data
46
+ end
47
+
48
+ end
49
+
50
+ end
51
+
@@ -0,0 +1,15 @@
1
+ require 'lemon/view/cover_reports/abstract'
2
+
3
+ module Lemon::CoverReports
4
+
5
+ class Yaml < Abstract
6
+
7
+ #
8
+ def render
9
+ puts checklist.to_yaml
10
+ end
11
+
12
+ end
13
+
14
+ end
15
+
@@ -0,0 +1,149 @@
1
+ module Lemon::TestReports
2
+
3
+ # Test Reporter Base Class
4
+ class Abstract
5
+
6
+ require 'ansi/code'
7
+
8
+ #
9
+ def self.inherited(base)
10
+ registry << base
11
+ end
12
+
13
+ #
14
+ def self.registry
15
+ @registry ||= []
16
+ end
17
+
18
+ #
19
+ def initialize(runner)
20
+ @runner = runner
21
+ @source = {}
22
+ end
23
+
24
+ #
25
+ attr :runner
26
+
27
+ #
28
+ def start_suite(suite)
29
+ end
30
+
31
+ #
32
+ def start_case(instance)
33
+ end
34
+
35
+ #
36
+ #def instance(instance)
37
+ #end
38
+
39
+ #
40
+ def start_unit(unit)
41
+ end
42
+
43
+ # Report an omitted unit test.
44
+ def omit(unit)
45
+ end
46
+
47
+ #
48
+ def pass(unit)
49
+ end
50
+
51
+ #
52
+ def fail(unit, exception)
53
+ end
54
+
55
+ #
56
+ def error(unit, exception)
57
+ end
58
+
59
+ #
60
+ def finish_unit(testunit)
61
+ end
62
+
63
+ #
64
+ def finish_case(instance)
65
+ end
66
+
67
+ #
68
+ def finish_suite(suite)
69
+ end
70
+
71
+ private
72
+
73
+ def record ; runner.record ; end
74
+
75
+ # Is coverage information requested?
76
+ #def cover? ; runner.cover? ; end
77
+
78
+ #
79
+ def total
80
+ %w{pending pass fail error omit}.inject(0){ |s,r| s += record[r.to_sym].size; s }
81
+ end
82
+
83
+ #
84
+ def tally
85
+ sizes = %w{pending fail error omit pass}.map{ |r| record[r.to_sym].size }
86
+ data = [total] + sizes
87
+ s = "%s tests: %s pending, %s fail, %s err, %s omit, %s pass " % data
88
+ #s += "(#{uncovered_units.size} uncovered, #{undefined_units.size} undefined)" if cover?
89
+ s
90
+ end
91
+
92
+ #FILE_SEPARATOR = Regexp.escape(File::SEPARATOR)
93
+
94
+ #
95
+ INTERNALS = /(lib|bin)[\\\/]lemon/
96
+
97
+ # Clean the backtrace of any reference to ko/ paths and code.
98
+ def clean_backtrace(backtrace)
99
+ trace = backtrace.reject{ |bt| bt =~ INTERNALS }
100
+ trace.map do |bt|
101
+ if i = bt.index(':in')
102
+ bt[0...i]
103
+ else
104
+ bt
105
+ end
106
+ end
107
+ end
108
+
109
+ # Have to thank Suraj N. Kurapati for the crux of this code.
110
+ def code_snippet(exception, bredth=3)
111
+ backtrace = exception.backtrace.reject{ |bt| bt =~ INTERNALS }
112
+ backtrace.first =~ /(.+?):(\d+(?=:|\z))/ or return ""
113
+ source_file, source_line = $1, $2.to_i
114
+
115
+ source = source(source_file)
116
+
117
+ radius = bredth # number of surrounding lines to show
118
+ region = [source_line - radius, 1].max ..
119
+ [source_line + radius, source.length].min
120
+
121
+ # ensure proper alignment by zero-padding line numbers
122
+ format = " %2s %0#{region.last.to_s.length}d %s"
123
+
124
+ pretty = region.map do |n|
125
+ format % [('=>' if n == source_line), n, source[n-1].chomp]
126
+ end #.unshift "[#{region.inspect}] in #{source_file}"
127
+
128
+ pretty
129
+ end
130
+
131
+ #
132
+ def source(file)
133
+ @source[file] ||= (
134
+ File.readlines(file)
135
+ )
136
+ end
137
+
138
+ # TODO: Show more of the file name than just the basename.
139
+ def file_and_line(exception)
140
+ line = exception.backtrace[0]
141
+ return "" unless line
142
+ i = line.rindex(':in')
143
+ line = i ? line[0...i] : line
144
+ File.basename(line)
145
+ end
146
+
147
+ end
148
+
149
+ end
@@ -0,0 +1,73 @@
1
+ require 'lemon/view/test_reports/abstract'
2
+
3
+ module Lemon::TestReports
4
+
5
+ # Simple Dot-Progress Reporter
6
+ class Dotprogress < Abstract
7
+
8
+ def omit(unit)
9
+ print "O"; $stdout.flush
10
+ end
11
+
12
+ def pass(unit)
13
+ print "."; $stdout.flush
14
+ end
15
+
16
+ def fail(unit, exception)
17
+ print "F"
18
+ end
19
+
20
+ def error(unit, exception)
21
+ print "E"
22
+ end
23
+
24
+ def pending(unit, exception)
25
+ print "P"
26
+ end
27
+
28
+ def finish_suite(suite)
29
+ puts; puts
30
+
31
+ ## if verbose
32
+ unless record[:omit].empty?
33
+ puts "OMITTED:\n\n"
34
+ puts record[:omit].map{ |u| u.to_s }.sort.join(' ')
35
+ puts
36
+ end
37
+ ## end
38
+
39
+ unless record[:pending].empty?
40
+ puts "PENDING:\n\n"
41
+ record[:pending].each do |testunit, exception|
42
+ puts " #{testunit}"
43
+ end
44
+ puts
45
+ end
46
+
47
+ unless record[:fail].empty?
48
+ puts "FAILURES:\n\n"
49
+ record[:fail].each do |testunit, exception|
50
+ puts " #{testunit}"
51
+ puts " #{exception}"
52
+ puts " #{exception.backtrace[0]}"
53
+ puts
54
+ end
55
+ end
56
+
57
+ unless record[:error].empty?
58
+ puts "ERRORS:\n\n"
59
+ record[:error].each do |testunit, exception|
60
+ puts " #{testunit}"
61
+ puts " #{exception}"
62
+ puts " #{exception.backtrace[0]}"
63
+ puts
64
+ end
65
+ end
66
+
67
+ puts tally
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
@@ -0,0 +1,146 @@
1
+ require 'lemon/view/test_reports/abstract'
2
+
3
+ module Lemon::TestReports
4
+
5
+ # HTML Test Reporter
6
+ #
7
+ # TODO: Make this more like a microformat and add timer info.
8
+ class Html < Abstract
9
+
10
+ #
11
+ def start_suite(suite)
12
+ timer_reset
13
+ @html = []
14
+ @html << %[<html>]
15
+ @html << %[<head>]
16
+ @html << %[<title>Unit Test Report</title>]
17
+ @html << %[ <style>]
18
+ @html << %[ html{ background: #fff; margin: 0; padding: 0; font-family: helvetica; }]
19
+ @html << %[ body{ margin: 0; padding: 0;}]
20
+ @html << %[ h3{color:#555;}]
21
+ @html << %[ #main{ margin: 0 auto; color: #110; width: 600px; ]
22
+ @html << %[ border-right: 1px solid #ddd; border-left: 1px solid #ddd; ]
23
+ @html << %[ padding: 10px 30px; width: 500px; } ]
24
+ @html << %[ .lemon{ color: gold; font-size: 22px; font-weight: bold; ]
25
+ @html << %[ font-family: courier; margin-bottom: -15px;}]
26
+ @html << %[ .tally{ font-weight: bold; margin-bottom: 10px; }]
27
+ @html << %[ .omit{ color: cyan; }]
28
+ @html << %[ .pass{ color: green; }]
29
+ @html << %[ .fail{ color: red; }]
30
+ @html << %[ .footer{ font-size: 0.7em; color: #666; margin: 20px 0; }]
31
+ @html << %[ </style>]
32
+ @html << %[</head>]
33
+ @html << %[<body>]
34
+ @html << %[<div id="main">]
35
+ @html << %[<div class="lemon">L E M O N</div>]
36
+ @html << %[<h1>Unit Test Report</h1>]
37
+ @body = []
38
+ end
39
+
40
+ #
41
+ def start_case(tc)
42
+ @body << "<h2>"
43
+ @body << tc.to_s
44
+ @body << "</h2>"
45
+ end
46
+
47
+ #
48
+ def instance(instance)
49
+ @body << "<h3>"
50
+ @body << "#{instance}"
51
+ @body << "</h3>"
52
+ end
53
+
54
+ #
55
+ def start_unit(unit)
56
+ instance = unit.instance
57
+ if @instance != instance
58
+ @instance = instance
59
+ instance(instance)
60
+ end
61
+ end
62
+
63
+ #
64
+ def omit(unit)
65
+ @body << %[<li class="omit">]
66
+ @body << " %s %s %s" % ["OMIT", unit.name, unit.aspect]
67
+ @body << %[</li>]
68
+ end
69
+
70
+ #
71
+ def pass(unit)
72
+ @body << %[<li class="pass">]
73
+ @body << "%s %s %s" % ["PASS", unit.name, unit.aspect]
74
+ @body << %[</li>]
75
+ end
76
+
77
+ #
78
+ def fail(unit, exception)
79
+ @body << %[<li class="fail">]
80
+ @body << "%s %s %s" % ["FAIL", unit.name, unit.aspect]
81
+ @body << "<pre>"
82
+ @body << " FAIL #{exception.backtrace[0]}"
83
+ @body << " #{exception}"
84
+ @body << "</pre>"
85
+ @body << %[</li>]
86
+ end
87
+
88
+ #
89
+ def error(unit, exception)
90
+ @body << %[<li class="error">]
91
+ @body << "%s %s %s" % ["ERROR", unit.name, unit.aspect]
92
+ @body << "<pre>"
93
+ @body << " ERROR #{exception.class}"
94
+ @body << " #{exception}"
95
+ @body << " " + exception.backtrace.join("\n ")
96
+ @body << "</pre>"
97
+ @body << %[</li>]
98
+ end
99
+
100
+ #
101
+ def pending(unit, exception)
102
+ @body << %[<li class="pending">]
103
+ @body << " %s %s %s" % ["PENDING", unit.name, unit.aspect]
104
+ @body << %[</li>]
105
+ end
106
+
107
+ #
108
+ def finish_suite(suite)
109
+ @html << ""
110
+ @html << %[<div class="tally">]
111
+ @html << tally
112
+ @html << %[</div>]
113
+ @html << ""
114
+
115
+ @body << ""
116
+ @body << %[<div class="footer">]
117
+ @body << %[Generated by <a href="http://proutils.github.com/lemon">Lemon</a>]
118
+ @body << %[on #{Time.now}.]
119
+ @body << %[</div>]
120
+ @body << ""
121
+ @body << %[</div>]
122
+ @body << %[</div>]
123
+ @body << ""
124
+ @body << %[</body>]
125
+ @body << %[</html>]
126
+
127
+ puts @html.join("\n")
128
+ puts @body.join("\n")
129
+ end
130
+
131
+ #
132
+ def timer
133
+ secs = Time.now - @time
134
+ @time = Time.now
135
+ return "%0.5fs" % [secs.to_s]
136
+ end
137
+
138
+ #
139
+ def timer_reset
140
+ @time = Time.now
141
+ end
142
+
143
+ end
144
+
145
+ end
146
+