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,90 @@
1
+ module Lemon
2
+
3
+ # Test Instances are used to organize unit tests into groups, so as to address
4
+ # specific scenarios for a given class.
5
+ class TestContext
6
+
7
+ # The test case to which this concern belongs.
8
+ attr :testcase
9
+
10
+ # The description of this concern. Make this
11
+ # as detailed as you wish.
12
+ attr :description
13
+
14
+ # New case instance.
15
+ def initialize(testcase, description, options={}, &block)
16
+ @testcase = testcase
17
+ @description = description.to_s
18
+ @function = options[:function] || options[:singleton]
19
+ @type = options[:type] || :context
20
+ @block = block
21
+ end
22
+
23
+ #
24
+ def teardown=(procedure)
25
+ @teardown = procedure
26
+ end
27
+
28
+ # Teardown instance.
29
+ def teardown(scope=nil)
30
+ if scope
31
+ scope.instance_eval(&@teardown) if @teardown
32
+ else
33
+ @teardown
34
+ end
35
+ end
36
+
37
+ # Create instance.
38
+ def setup(scope)
39
+ if @block
40
+ ins = scope.instance_eval(&@block)
41
+ end
42
+ ins
43
+ end
44
+
45
+ def function? ; false ; end
46
+ alias_method :meta?, :function?
47
+
48
+ # Returns the description with newlines removed.
49
+ def to_s
50
+ description.gsub(/\n/, ' ')
51
+ end
52
+ end
53
+
54
+ ##
55
+ #class TestInstance < TestContext
56
+ #
57
+ # # Create instance.
58
+ # def setup(scope)
59
+ # if @block
60
+ # ins = scope.instance_eval(&@block)
61
+ # raise "target type mismatch" unless testcase.target === ins
62
+ # end
63
+ # ins
64
+ # end
65
+ #
66
+ #end
67
+
68
+ =begin
69
+ #
70
+ class TestSingleton < TestContext
71
+
72
+ # Create instance.
73
+ def setup(scope)
74
+ if @block
75
+ ins = scope.instance_eval(&@block)
76
+ raise "target type mismatch" unless testcase.target == ins
77
+ else
78
+ ins = @testcase.target
79
+ end
80
+ ins
81
+ end
82
+
83
+ def function? ; true ; end
84
+ alias_method :meta?, :function?
85
+
86
+ end
87
+ =end
88
+
89
+ end
90
+
@@ -0,0 +1,216 @@
1
+ require 'lemon/model/test_case'
2
+ require 'lemon/model/snapshot'
3
+ #require 'lemon/model/main'
4
+
5
+ module Lemon
6
+
7
+ # Current suite being defined. This is used
8
+ # to define a Suite object via the toplevel DSL.
9
+ def self.suite
10
+ $lemon_suite #@suite ||= Lemon::TestSuite.new([])
11
+ end
12
+
13
+ #
14
+ def self.suite=(suite)
15
+ $lemon_suite = suite
16
+ end
17
+
18
+ # Test Suites encapsulate a set of test cases.
19
+ #
20
+ class TestSuite
21
+
22
+ # Files from which the suite is loaded.
23
+ attr :files
24
+
25
+ # Test cases in this suite.
26
+ attr :testcases
27
+
28
+ # List of pre-test procedures that apply suite-wide.
29
+ attr :before
30
+
31
+ # List of post-test procedures that apply suite-wide.
32
+ attr :after
33
+
34
+ # A snapshot of the system before the suite is loaded.
35
+ # Only set if +cover+ option is true.
36
+ #attr :canonical
37
+
38
+ # List of files to be covered. This primarily serves
39
+ # as a means for allowing one test to load another
40
+ # and ensuring converage remains accurate.
41
+ #attr :subtest
42
+
43
+ #attr :current_file
44
+
45
+ #def coverage
46
+ # @final_coveage ||= @coverage - @canonical
47
+ #end
48
+
49
+ #
50
+ #attr :options
51
+
52
+ attr :dsl
53
+
54
+ #
55
+ def initialize(files, options={})
56
+ @files = files.flatten
57
+ @options = options
58
+
59
+ @testcases = []
60
+
61
+ @before = {}
62
+ @after = {}
63
+
64
+ #load_helpers
65
+
66
+ #if cover? or cover_all?
67
+ # @coverage = Snapshot.new
68
+ # @canonical = Snapshot.capture
69
+ #end
70
+
71
+ @dsl = DSL.new(self) #, files)
72
+
73
+ load_files
74
+ end
75
+
76
+ #
77
+ #class Scope < Module
78
+ # def initialize
79
+ # extend self
80
+ # end
81
+ #end
82
+
83
+ # Iterate through this suite's test cases.
84
+ def each(&block)
85
+ @testcases.each(&block)
86
+ end
87
+
88
+ #
89
+ def cover?
90
+ @options[:cover]
91
+ end
92
+
93
+ #
94
+ def cover_all?
95
+ @options[:cover_all]
96
+ end
97
+
98
+ # TODO: automatic helper loading ?
99
+ #def load_helpers(*files)
100
+ # helpers = []
101
+ # filelist.each do |file|
102
+ # dir = File.dirname(file)
103
+ # hlp = Dir[File.join(dir, '{test_,}helper.rb')]
104
+ # helpers.concat(hlp)
105
+ # end
106
+ #
107
+ # helpers.each do |hlp|
108
+ # require hlp
109
+ # end
110
+ #end
111
+
112
+ #
113
+ def load_files #(*files)
114
+ s = Lemon.suite || self
115
+ Lemon.suite = self
116
+
117
+ filelist.each do |file|
118
+ #load_file(file)
119
+ load file #require file
120
+ end
121
+
122
+ Lemon.suite = s
123
+
124
+ #if cover?
125
+ # $stdout << "\n"
126
+ # $stdout.flush
127
+ #end
128
+
129
+ self #return Lemon.suite
130
+ end
131
+
132
+ #
133
+ #def load_file(file)
134
+ # #@current_file = file
135
+ # #if cover_all?
136
+ # # Covers(file)
137
+ # #else
138
+ # file = File.expand_path(file)
139
+ # @dsl.module_eval(File.read(file), file)
140
+ # #require(file) #load(file)
141
+ # #end
142
+ #end
143
+
144
+ # Directories glob *.rb files.
145
+ def filelist
146
+ @filelist ||= (
147
+ files = @files
148
+ files = files.map{ |f| Dir[f] }.flatten
149
+ files = files.map do |file|
150
+ if File.directory?(file)
151
+ Dir[File.join(file, '**', '*.rb')]
152
+ else
153
+ file
154
+ end
155
+ end.flatten
156
+ #files = files.map{ |f| File.expand_path(f) }
157
+ files.uniq
158
+ )
159
+ end
160
+
161
+ class DSL < Module
162
+ #
163
+ def initialize(test_suite)
164
+ @test_suite = test_suite
165
+ #module_eval(&code)
166
+ end
167
+
168
+ # TODO: need require_find() to avoid first snapshot ?
169
+ def covers(file)
170
+ #if @test_suite.cover?
171
+ # #return if $".include?(file)
172
+ # s = Snapshot.capture
173
+ # if require(file)
174
+ # z = Snapshot.capture
175
+ # @test_suite.coverage << (z - s)
176
+ # end
177
+ #else
178
+ require file
179
+ #end
180
+ end
181
+ alias_method :Covers, :covers
182
+
183
+ # Define a test case belonging to this suite.
184
+ def testcase(target_class, &block)
185
+ raise "lemon: case target must be a class or module" unless Module === target_class
186
+ @test_suite.testcases << TestCase.new(@test_suite, target_class, &block)
187
+ end
188
+
189
+ #
190
+ alias_method :TestCase, :testcase
191
+ alias_method :tests, :testcase
192
+
193
+ # Define a pre-test procedure to apply suite-wide.
194
+ def before(*matches, &block)
195
+ @test_suite.before[matches] = block #<< Advice.new(match, &block)
196
+ end
197
+ alias_method :Before, :before
198
+
199
+ # Define a post-test procedure to apply suite-wide.
200
+ def after(*matches, &block)
201
+ @test_suite.after[matches] = block #<< Advice.new(match, &block)
202
+ end
203
+ alias_method :After, :after
204
+
205
+ # Includes at the suite level are routed to the toplevel.
206
+ #def include(*mods)
207
+ # TOPLEVEL_BINDING.eval('self').instance_eval do
208
+ # include(*mods)
209
+ # end
210
+ #end
211
+
212
+ end
213
+
214
+ end
215
+
216
+ end
@@ -1,54 +1,58 @@
1
- module Lemon::Test
1
+ module Lemon
2
2
 
3
3
  #
4
- class Unit
4
+ class TestUnit
5
5
 
6
6
  # The test case to which this unit test belongs.
7
7
  attr :testcase
8
8
 
9
- # The concern which this test helps ensure.
10
- attr :concern
9
+ # The context to use for this test.
10
+ attr :context
11
11
 
12
12
  # A test unit +target+ is a method.
13
13
  attr :target
14
14
 
15
- # The aspect of the concern this test fulfills.
15
+ # The aspect of the instance this test fulfills.
16
16
  attr :aspect
17
17
 
18
18
  # Test procedure, in which test assertions should be made.
19
19
  attr :procedure
20
20
 
21
21
  # New unit test.
22
- def initialize(concern, target, options={}, &procedure)
23
- concern.assign(self)
24
-
25
- @concern = concern
26
- @testcase = concern.testcase
27
-
22
+ def initialize(testcase, target, options={}, &procedure)
23
+ @testcase = testcase
28
24
  @target = target
29
25
 
30
26
  @aspect = options[:aspect]
31
- @meta = options[:metaclass]
27
+ @function = options[:function] || options[:metaclass]
28
+ @context = options[:context]
29
+ @omit = options[:omit]
32
30
 
33
31
  @procedure = procedure
32
+
33
+ @tested = false
34
34
  end
35
35
 
36
- # Is this unit test for a meta-method?
37
- def meta?
38
- @meta
36
+ #
37
+ attr_accessor :omit
38
+
39
+ #
40
+ def name ; @target ; end
41
+
42
+ # Is this unit test for a class or module level method?
43
+ def function?
44
+ @function
39
45
  end
46
+ alias_method :meta?, :function?
40
47
 
41
- # This method has the other end of the BIG FAT HACK. See Suite#const_missing.
42
- def call
43
- raise Pending unless procedure
44
- begin
45
- Lemon.test_stack << self # hack
46
- procedure.call
47
- ensure
48
- Lemon.test_stack.pop
49
- end
48
+ #
49
+ def omit?
50
+ @omit
50
51
  end
51
52
 
53
+ #
54
+ attr_accessor :tested
55
+
52
56
  # The suite to which this unit test belongs.
53
57
  def suite
54
58
  testcase.suite
@@ -74,9 +78,19 @@ module Lemon::Test
74
78
  #
75
79
  def to_s
76
80
  if meta?
77
- "#{testcase}.#{target} #{aspect}"
81
+ "#{testcase}.#{target}"
78
82
  else
79
- "#{testcase}##{target} #{aspect}"
83
+ "#{testcase}##{target}"
84
+ end
85
+ end
86
+
87
+ #
88
+ def description
89
+ if meta?
90
+ "#{testcase} #{instance} .#{target} #{aspect}"
91
+ else
92
+ a = /^[aeiou]/i =~ testcase.to_s ? 'An' : 'A'
93
+ "#{a} #{testcase} #{instance} receiving ##{target} #{aspect}"
80
94
  end
81
95
  end
82
96
 
@@ -88,5 +102,3 @@ module Lemon::Test
88
102
 
89
103
  end
90
104
 
91
-
92
-
@@ -1,5 +1,4 @@
1
- module Lemon
2
- module CoverSheet
1
+ module Lemon::CoverReports
3
2
 
4
3
  class Abstract
5
4
 
@@ -21,40 +20,40 @@ module CoverSheet
21
20
  #
22
21
  attr :coverage
23
22
 
24
- def uncovered_cases
25
- coverage.uncovered_cases
23
+ #
24
+ def render
25
+ end
26
+
27
+ def covered_units
28
+ coverage.covered
26
29
  end
27
30
 
28
31
  def uncovered_units
29
- coverage.uncovered_units
32
+ coverage.uncovered
30
33
  end
31
34
 
32
35
  def undefined_units
33
- coverage.undefined_units
36
+ coverage.undefined
34
37
  end
35
38
 
36
- #
37
- def red(string)
38
- @ansicolor ? ANSI::Code.red{ string } : string
39
+ def uncovered_cases
40
+ coverage.uncovered_cases
39
41
  end
40
42
 
41
43
  #
42
- def yellow(string)
43
- @ansicolor ? ANSI::Code.yellow{ string } : string
44
- end
44
+ def tally
45
+ c = covered_units.size
46
+ u = uncovered_units.size
47
+ t = c + u
45
48
 
46
- #
47
- def green(string)
48
- @ansicolor ? ANSI::Code.green{ string } : string
49
- end
49
+ pc = c * 100 / t
50
+ pu = u * 100 / t
50
51
 
51
- #
52
- def tally
53
- "#{uncovered_cases.size} uncovered cases, #{uncovered_units.size} uncovered units, #{undefined_units.size} undefined units"
52
+ "#{pc}% #{c}/#{t} covered, #{pu}% #{u}/#{t} uncovered" +
53
+ " (#{undefined_units.size} undefined units, #{uncovered_cases.size} uncovered cases)"
54
54
  end
55
55
 
56
56
  end
57
57
 
58
58
  end
59
- end
60
59