lemon 0.8.2 → 0.8.3

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 (39) hide show
  1. data/.ruby +55 -0
  2. data/APACHE2.txt +206 -0
  3. data/HISTORY.rdoc +12 -0
  4. data/NOTICE.rdoc +16 -0
  5. data/bin/lemon +1 -1
  6. data/demo/case_example_error.rb +10 -0
  7. data/{test/cli → features}/coverage.feature +0 -0
  8. data/{test/cli → features}/generate.feature +0 -0
  9. data/{test/cli → features}/step_definitions/coverage_steps.rb +0 -0
  10. data/{test/cli → features}/support/ae.rb +0 -0
  11. data/{test/cli → features}/support/aruba.rb +0 -0
  12. data/{test/cli → features}/test.feature +0 -0
  13. data/lib/lemon.rb +19 -1
  14. data/lib/lemon.yml +55 -0
  15. data/lib/lemon/cli.rb +0 -1
  16. data/lib/lemon/controller/test_runner.rb +12 -3
  17. data/lib/lemon/model/test_case.rb +4 -2
  18. data/lib/lemon/model/test_unit.rb +45 -2
  19. data/lib/lemon/view/test_reports/abstract.rb +107 -0
  20. data/lib/lemon/view/test_reports/tapj.rb +130 -0
  21. data/lib/lemon/view/test_reports/tapy.rb +141 -0
  22. data/qed/applique/fs.rb +21 -0
  23. data/{test/api/coverage/complete.rdoc → qed/coverage/01_complete.rdoc} +9 -9
  24. data/qed/coverage/02_incomplete.rdoc +97 -0
  25. data/{test/api/coverage/extensions.rdoc → qed/coverage/03_extensions.rdoc} +5 -5
  26. data/test/{unit/case_coverage_analyzer.rb → case_coverage_analyzer.rb} +0 -0
  27. data/test/{unit/case_test_case_dsl.rb → case_test_case_dsl.rb} +0 -0
  28. data/test/fixtures/case_complete.rb +5 -1
  29. data/test/runner +1 -2
  30. metadata +31 -39
  31. data/LICENSE +0 -22
  32. data/lib/lemon/meta/data.rb +0 -29
  33. data/lib/lemon/meta/gemfile +0 -24
  34. data/lib/lemon/meta/profile +0 -17
  35. data/meta/data.rb +0 -29
  36. data/meta/gemfile +0 -24
  37. data/meta/profile +0 -17
  38. data/test/api/applique/fs.rb +0 -18
  39. data/test/api/coverage/incomplete.rdoc +0 -97
@@ -95,7 +95,8 @@ module Lemon
95
95
  @testcase, method,
96
96
  :function => false,
97
97
  :aspect => aspect,
98
- :context => @context,
98
+ :context => @context,
99
+ :caller => caller,
99
100
  &block
100
101
  )
101
102
  #@testcase.steps << unit
@@ -114,7 +115,8 @@ module Lemon
114
115
  @testcase, method,
115
116
  :function => true,
116
117
  :aspect => aspect,
117
- :context => @context,
118
+ :context => @context,
119
+ :caller => caller,
118
120
  &block
119
121
  )
120
122
  #@testcase.steps << unit
@@ -18,6 +18,9 @@ module Lemon
18
18
  # Test procedure, in which test assertions should be made.
19
19
  attr :procedure
20
20
 
21
+ #
22
+ attr :caller
23
+
21
24
  # New unit test.
22
25
  def initialize(testcase, target, options={}, &procedure)
23
26
  @testcase = testcase
@@ -27,6 +30,7 @@ module Lemon
27
30
  @function = options[:function] || options[:metaclass]
28
31
  @context = options[:context]
29
32
  @omit = options[:omit]
33
+ @caller = options[:caller]
30
34
 
31
35
  @procedure = procedure
32
36
 
@@ -87,13 +91,52 @@ module Lemon
87
91
  #
88
92
  def description
89
93
  if meta?
90
- "#{testcase} #{instance} .#{target} #{aspect}"
94
+ #"#{testcase} .#{target} #{aspect}"
95
+ "#{testcase}.#{target} #{context} #{aspect}".strip
91
96
  else
92
97
  a = /^[aeiou]/i =~ testcase.to_s ? 'An' : 'A'
93
- "#{a} #{testcase} #{instance} receiving ##{target} #{aspect}"
98
+ #"#{a} #{testcase} receiving ##{target} #{aspect}"
99
+ "#{testcase}##{target} #{context} #{aspect}".strip
94
100
  end
95
101
  end
96
102
 
103
+ # START-COMMIT. 201105190006
104
+
105
+ # The file method returns the file name of +caller+ which
106
+ # was created upon initialization of this object. It is
107
+ # also the first element of #file_and_line.
108
+ #
109
+ # Returns file name of caller.
110
+ def file
111
+ file_and_line.first
112
+ end
113
+
114
+ # Returns line number of caller.
115
+ def line
116
+ file_and_line.last
117
+ end
118
+
119
+ # The file_and_line method returns the file name and line number of
120
+ # the caller created upon initialization of this object.
121
+ #
122
+ # This method is cached.
123
+ #
124
+ # Examples
125
+ # file_and_line #=> ['foo_test.rb', 123]
126
+ #
127
+ # Returns Array of file name and line number of caller.
128
+ def file_and_line
129
+ @file_and_line ||= (
130
+ line = caller[0]
131
+ i = line.rindex(':in')
132
+ line = i ? line[0...i] : line
133
+ f, l = File.basename(line).split(':')
134
+ [f, l]
135
+ )
136
+ end
137
+
138
+ # END-COMMIT.
139
+
97
140
  #
98
141
  def match?(match)
99
142
  match == target || match === aspect
@@ -128,6 +128,78 @@ module Lemon::TestReports
128
128
  pretty
129
129
  end
130
130
 
131
+ =begin
132
+ #
133
+ def code_snippet_hash(exception, bredth=3)
134
+ backtrace = filtered_backtrace(exception)
135
+
136
+ backtrace.first =~ /(.+?):(\d+(?=:|\z))/ or return ""
137
+ source_file, source_line = $1, $2.to_i
138
+
139
+ source = source(source_file)
140
+
141
+ radius = bredth # number of surrounding lines to show
142
+ region = [source_line - radius, 1].max ..
143
+ [source_line + radius, source.length].min
144
+
145
+ # ensure proper alignment by zero-padding line numbers
146
+ format = " %2s %0#{region.last.to_s.length}d %s"
147
+
148
+ hash = {}
149
+ region.each do |n|
150
+ hash[n] = source[n-1].chomp
151
+ end
152
+ hash
153
+ end
154
+ =end
155
+
156
+ #
157
+ def code_snippet_array(exception, bredth=3)
158
+ backtrace = filtered_backtrace(exception)
159
+ backtrace.first =~ /(.+?):(\d+(?=:|\z))/ or return ""
160
+ source_file, source_line = $1, $2.to_i
161
+
162
+ source = source(source_file)
163
+
164
+ radius = bredth # number of surrounding lines to show
165
+ region = [source_line - radius, 1].max ..
166
+ [source_line + radius, source.length].min
167
+
168
+ # ensure proper alignment by zero-padding line numbers
169
+ #format = " %2s %0#{region.last.to_s.length}d %s"
170
+
171
+ region.map do |n|
172
+ source[n-1].chomp
173
+ end
174
+ end
175
+
176
+ #
177
+ def code_snippet_omap(exception, bredth=3)
178
+ backtrace = filtered_backtrace(exception)
179
+ backtrace.first =~ /(.+?):(\d+(?=:|\z))/ or return ""
180
+ source_file, source_line = $1, $2.to_i
181
+
182
+ source = source(source_file)
183
+
184
+ radius = bredth # number of surrounding lines to show
185
+ region = [source_line - radius, 1].max ..
186
+ [source_line + radius, source.length].min
187
+
188
+ # ensure proper alignment by zero-padding line numbers
189
+ #format = " %2s %0#{region.last.to_s.length}d %s"
190
+
191
+ a = []
192
+ region.each do |n|
193
+ a << {n=> source[n-1].chomp}
194
+ end
195
+ a
196
+ end
197
+
198
+ # TODO: improve
199
+ def code_line(exception)
200
+ code_snippet_array(exception, 0).first.strip
201
+ end
202
+
131
203
  #
132
204
  def source(file)
133
205
  @source[file] ||= (
@@ -144,6 +216,41 @@ module Lemon::TestReports
144
216
  File.basename(line)
145
217
  end
146
218
 
219
+ #
220
+ def file_and_line_array(exception)
221
+ case exception
222
+ when Exception
223
+ line = exception.backtrace[0]
224
+ else
225
+ line = exception[0] # backtrace
226
+ end
227
+ return ["", 0] unless line
228
+ i = line.rindex(':in')
229
+ line = i ? line[0...i] : line
230
+ f, l = File.basename(line).split(':')
231
+ return [f, l.to_i]
232
+ end
233
+
234
+
235
+ def file(exception)
236
+ file_and_line_array(exception).first
237
+ end
238
+
239
+ def line(exception)
240
+ file_and_line_array(exception).last
241
+ end
242
+
243
+ #
244
+ def filtered_backtrace(exception)
245
+ case exception
246
+ when Exception
247
+ backtrace = exception.backtrace
248
+ else
249
+ backtrace = exception
250
+ end
251
+ backtrace.reject{ |bt| bt =~ INTERNALS }
252
+ end
253
+
147
254
  end
148
255
 
149
256
  end
@@ -0,0 +1,130 @@
1
+ require 'lemon/view/test_reports/abstract'
2
+
3
+ module Lemon::TestReports
4
+
5
+ # TAP-J Reporter
6
+ #
7
+ # TODO: Lemon needs some improvements in order to supply all the
8
+ # information TAP-J supports. In particular, `file` and `line` information.
9
+ class Tapj < Abstract
10
+
11
+ #
12
+ def start_suite(suite)
13
+ require 'json'
14
+
15
+ @start = Time.now
16
+ @i = 0
17
+ @n = suite.testcases.inject(0){ |c, tc| c = c + tc.size; c }
18
+ h = {
19
+ 'type' => "header",
20
+ 'count' => @n,
21
+ 'range' => "1..#{@n}"
22
+ }
23
+ puts h.to_json
24
+ end
25
+
26
+ #
27
+ def start_case(tcase)
28
+ h = {
29
+ 'type' => 'case',
30
+ 'description' => "#{tcase.to_s} #{tcase.aspect}".strip
31
+ }
32
+ puts h.to_json
33
+ end
34
+
35
+ #
36
+ def start_unit(unit)
37
+ @i += 1
38
+ end
39
+
40
+ #
41
+ def pass(unit)
42
+ h = {
43
+ 'type' => 'test',
44
+ 'status' => 'pass',
45
+ 'file' => unit.file,
46
+ 'line' => unit.line,
47
+ 'description' => unit.description,
48
+ #'returned' => '',
49
+ #'expected' => '',
50
+ 'source' => code_line(unit.caller),
51
+ 'snippet' => code_snippet_omap(unit.caller, 3),
52
+ 'message' => unit.to_s,
53
+ 'time' => Time.now - @start
54
+ }
55
+ puts h.to_json
56
+ end
57
+
58
+ #
59
+ def fail(unit, exception)
60
+ h = {
61
+ 'type' => 'test',
62
+ 'status' => 'fail',
63
+ 'file' => file(exception),
64
+ 'line' => line(exception),
65
+ 'description' => unit.description,
66
+ #'returned' => '',
67
+ #'expected' => '',
68
+ 'source' => code_line(exception),
69
+ 'snippet' => code_snippet_omap(exception, 3),
70
+ 'message' => exception.message,
71
+ 'time' => Time.now - @start
72
+ #'backtrace' => exception.backtrace
73
+ }
74
+ puts h.to_json
75
+ end
76
+
77
+ #
78
+ def error(unit, exception)
79
+ h = {
80
+ 'type' => 'test',
81
+ 'status' => 'error',
82
+ 'file' => file(exception),
83
+ 'line' => line(exception),
84
+ 'description' => unit.description,
85
+ 'source' => code_line(exception),
86
+ 'snippet' => code_snippet_omap(exception, 3),
87
+ 'message' => exception.message,
88
+ 'trace' => exception.backtrace,
89
+ 'time' => Time.now - @start
90
+ }
91
+ puts h.to_json
92
+ end
93
+
94
+ # TODO: why was this using expception.backtrace[1] and now [0].
95
+ def pending(unit, exception)
96
+ h = {
97
+ 'type' => 'test',
98
+ 'status' => 'pending',
99
+ 'file' => file(exception),
100
+ 'line' => line(exception),
101
+ 'description' => unit.description,
102
+ 'source' => code_line(exception),
103
+ 'snippet' => code_snippet_omap(exception, 3),
104
+ 'message' => exception.message,
105
+ 'time' => Time.now - @start
106
+ #'backtrace' => exception.backtrace
107
+ }
108
+ puts h.to_json
109
+ end
110
+
111
+ #
112
+ def finish_suite(suite)
113
+ h = {
114
+ 'type' => 'footer',
115
+ 'time' => Time.now - @start,
116
+ 'count' => @n, #total
117
+ 'tally' => {
118
+ 'pass' => record[:pass].size,
119
+ 'fail' => record[:fail].size,
120
+ 'error' => record[:error].size,
121
+ 'omit' => record[:omit].size,
122
+ 'pending' => record[:pending].size # TODO: rename to `hold`?
123
+ }
124
+ }
125
+ puts h.to_json
126
+ end
127
+ end
128
+
129
+ end
130
+
@@ -0,0 +1,141 @@
1
+ require 'lemon/view/test_reports/abstract'
2
+
3
+ module Lemon::TestReports
4
+
5
+ #--
6
+ #returned: true
7
+ #expected: true
8
+ #source: ok 1, 2
9
+ #snippet:
10
+ # 44: ok 0,0
11
+ # 45: ok 1,2
12
+ # 46: ok 2,4
13
+ #++
14
+
15
+ # TAP-Y Reporter
16
+ #
17
+ # TODO: Lemon needs some improvements in order to supply all the
18
+ # information TAP-Y supports. In particular, `file` and `line` information.
19
+ class Tapy < Abstract
20
+
21
+ #
22
+ def start_suite(suite)
23
+ require 'yaml'
24
+
25
+ @start = Time.now
26
+ @i = 0
27
+ @n = suite.testcases.inject(0){ |c, tc| c = c + tc.size; c }
28
+ h = {
29
+ 'type' => "header",
30
+ 'count' => @n,
31
+ 'range' => "1..#{@n}"
32
+ }
33
+ puts h.to_yaml
34
+ end
35
+
36
+ #
37
+ def start_case(tcase)
38
+ h = {
39
+ 'type' => 'case',
40
+ 'description' => "#{tcase.to_s} #{tcase.aspect}".strip
41
+ }
42
+ puts h.to_yaml
43
+ end
44
+
45
+ #
46
+ def start_unit(unit)
47
+ @i += 1
48
+ end
49
+
50
+ #
51
+ def pass(unit) #, backtrace=nil)
52
+ h = {
53
+ 'type' => 'test',
54
+ 'status' => 'pass',
55
+ 'file' => unit.file,
56
+ 'line' => unit.line,
57
+ 'description' => unit.description,
58
+ #'returned' => '',
59
+ #'expected' => '',
60
+ 'source' => code_line(unit.caller),
61
+ 'snippet' => code_snippet_omap(unit.caller, 3),
62
+ 'message' => unit.to_s,
63
+ 'time' => Time.now - @start
64
+ }
65
+ puts h.to_yaml
66
+ end
67
+
68
+ #
69
+ def fail(unit, exception)
70
+ h = {
71
+ 'type' => 'test',
72
+ 'status' => 'fail',
73
+ 'file' => file(exception),
74
+ 'line' => line(exception),
75
+ 'description' => unit.description,
76
+ #'returned' => '',
77
+ #'expected' => '',
78
+ 'source' => code_line(exception),
79
+ 'snippet' => code_snippet_omap(exception, 3),
80
+ 'message' => exception.message,
81
+ 'time' => Time.now - @start
82
+ #'backtrace' => exception.backtrace
83
+ }
84
+ puts h.to_yaml
85
+ end
86
+
87
+ #
88
+ def error(unit, exception)
89
+ h = {
90
+ 'type' => 'test',
91
+ 'status' => 'error',
92
+ 'file' => file(exception),
93
+ 'line' => line(exception),
94
+ 'description' => unit.description,
95
+ 'source' => code_line(exception),
96
+ 'snippet' => code_snippet_omap(exception, 3),
97
+ 'message' => exception.message,
98
+ 'backtrace' => exception.backtrace,
99
+ 'time' => Time.now - @start
100
+ }
101
+ puts h.to_yaml
102
+ end
103
+
104
+ #
105
+ def pending(unit, exception)
106
+ h = {
107
+ 'type' => 'test',
108
+ 'status' => 'pending',
109
+ 'file' => file(exception),
110
+ 'line' => line(exception),
111
+ 'description' => unit.description,
112
+ 'source' => code_line(exception),
113
+ 'snippet' => code_snippet_omap(exception, 3),
114
+ 'message' => exception.message,
115
+ 'time' => Time.now - @start
116
+ #'backtrace' => exception.backtrace
117
+ }
118
+ puts h.to_yaml
119
+ end
120
+
121
+ #
122
+ def finish_suite(suite)
123
+ h = {
124
+ 'type' => 'footer',
125
+ 'time' => Time.now - @start,
126
+ 'count' => @n, #total
127
+ 'tally' => {
128
+ 'pass' => record[:pass].size,
129
+ 'fail' => record[:fail].size,
130
+ 'error' => record[:error].size,
131
+ 'omit' => record[:omit].size,
132
+ 'pending' => record[:pending].size # TODO: rename to `hold`?
133
+ }
134
+ }
135
+ puts h.to_yaml
136
+ puts "..."
137
+ end
138
+ end
139
+
140
+ end
141
+