ruport 0.6.0 → 0.6.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.
@@ -12,7 +12,7 @@ module Ruport
12
12
  class Query
13
13
  # This class properly splits up multi-statement SQL input for use with
14
14
  # Ruby/DBI
15
- class SqlSplit < Array
15
+ class SqlSplit < Array #:nodoc:
16
16
  def initialize( sql )
17
17
  super()
18
18
  next_sql = ''
data/lib/ruport/report.rb CHANGED
@@ -29,7 +29,7 @@ module Ruport
29
29
  # require "ruport"
30
30
  # require "fileutils"
31
31
  # class MyReport < Ruport::Report
32
- # prepare do
32
+ # def prepare
33
33
  # log_file "f.log"
34
34
  # log "preparing report", :status => :info
35
35
  # source :default,
@@ -40,12 +40,12 @@ module Ruport
40
40
  # :address => "gregory.t.brown@gmail.com"
41
41
  # end
42
42
  #
43
- # generate do
43
+ # def generate
44
44
  # log "generated csv from query", :status => :info
45
45
  # query "select * from bar", :as => :csv
46
46
  # end
47
47
  #
48
- # cleanup do
48
+ # def cleanup
49
49
  # log "removing foo.csv", :status => :info
50
50
  # FileUtils.rm("foo.csv")
51
51
  # end
@@ -63,24 +63,26 @@ module Ruport
63
63
  # }
64
64
  #
65
65
  #
66
- # This class can also be used to run templates and process text filters
66
+ # This class can also be used to run templates and process text filters.
67
67
  #
68
68
  # See the examples in the documentation below to see how to use these
69
- # features. (Namely Report#process_text , Report#text_processor, and
70
- # Report#eval_template )
69
+ # features (namely Report#process_text , Report#text_processor, and
70
+ # Report#eval_template).
71
71
  #
72
72
  class Report
73
73
  extend Forwardable
74
74
 
75
75
  include Ruport::Data::TableHelper
76
+ #
76
77
  # When initializing a report, you can provide a default mailer and source by
77
78
  # giving a name of a valid source or mailer you've defined via
78
- # Ruport::Config
79
+ # Ruport::Config.
79
80
  #
80
81
  # If your report does not need any sort of specialized information, you can
81
- # simply use Report.run (Or MyReportName.run if you've inherited)
82
+ # simply use Report.run (Or MyReportName.run if you've inherited).
82
83
  #
83
84
  # This will auto-initialize a report.
85
+ #
84
86
  def initialize( source_name=:default, mailer_name=:default )
85
87
  use_source source_name
86
88
  use_mailer mailer_name
@@ -89,46 +91,49 @@ module Ruport
89
91
  @file = nil
90
92
  end
91
93
 
92
- #by default, this file will be used by Report#write
94
+ # By default, this file will be used by Report#write.
93
95
  attr_accessor :file
94
96
 
95
- #this attribute will get the results of Report#generate when the report is
96
- #run.
97
+ #
98
+ # This attribute will get the results of Report#generate when the report is
99
+ # run.
100
+ #
97
101
  attr_accessor :results
98
102
 
99
- # Simplified interface to Ruport::Query
103
+ # This is a simplified interface to Ruport::Query.
100
104
  #
101
- # === Can read SQL statements from file or string
105
+ # You can use it to read SQL statements from file or string:
102
106
  #
103
- # #from string
104
- # result = query "select * from foo"
107
+ # #from string
108
+ # result = query "select * from foo"
105
109
  #
106
- # #from file
107
- # result = query "my_query.sql", :origin => :file
110
+ # #from file
111
+ # result = query "my_query.sql", :origin => :file
108
112
  #
109
- # === Can use multistatement SQL
113
+ # You can use multistatement SQL:
110
114
  #
111
- # # will return the value of the last statement, "select * from foo"
112
- # result = query "insert into foo values(1,2); select * from foo"
115
+ # # will return the value of the last statement, "select * from foo"
116
+ # result = query "insert into foo values(1,2); select * from foo"
113
117
  #
114
- # === Can iterate by row or return entire set
118
+ # You can iterate by row or return the entire set:
115
119
  #
116
- # query("select * from foo", :yield_type => :by_row) { |r|
120
+ # query("select * from foo", :yield_type => :by_row) { |r|
117
121
  # #do something with the rows here
118
- # }
122
+ # }
119
123
  #
120
- # === Can return raw DBI:Row objects or Ruport's data structures.
124
+ # query() can return raw DBI:Row objects or Ruport's data structures:
121
125
  #
122
- # # will return an Array of DBI::Row objects
123
- # result = query "select * from foo", :raw_data => true
126
+ # # will return an Array of DBI::Row objects
127
+ # result = query "select * from foo", :raw_data => true
124
128
  #
125
- # === Can quickly output in a number of formats
129
+ # You can quickly output in a number of formats:
126
130
  #
127
- # result = query "select * from foo", :as => :csv
128
- # result = query "select * from foo", :as => :html
129
- # result = query "select * from foo", :as => :pdf
131
+ # result = query "select * from foo", :as => :csv
132
+ # result = query "select * from foo", :as => :html
133
+ # result = query "select * from foo", :as => :pdf
134
+ #
135
+ # See Ruport::Query for details.
130
136
  #
131
- # See source of this function and methods of Ruport::Query for details.
132
137
  def query(sql, options={})
133
138
  options[:origin] ||= :string
134
139
  options[:source] ||= @source
@@ -143,25 +148,28 @@ module Ruport
143
148
  end
144
149
  end
145
150
 
146
- # Evaluates _code_ from _filename_ as pure ruby code for files ending in
147
- # .rb, and as ERb templates for anything else.
148
151
  #
149
- # This code will be evaluated in the context of the instance on which it is
150
- # called.
152
+ # Evaluates <tt>code</tt> from <tt>filename</tt> as pure ruby code for
153
+ # files ending in .rb, and as ERb templates for anything else.
154
+ #
155
+ # This code will be evaluated in the context of the instance on which it
156
+ # is called.
157
+ #
151
158
  def eval_template( code, filename=nil )
152
159
  filename =~ /\.rb/ ? eval(code) : ERB.new(code, 0, "%").result(binding)
153
160
  end
154
161
 
155
- # sets the active source to the Ruport::Config source requested by label.
162
+ # Sets the active source to the Ruport::Config source requested by <tt>label</tt>.
156
163
  def use_source(label)
157
164
  @source = label
158
165
  end
159
166
 
160
- # sets the active mailer to the Ruport::Config source requested by label.
167
+ # Sets the active mailer to the Ruport::Config source requested by <tt>label</tt>.
161
168
  def use_mailer(label)
162
169
  @mailer = label
163
170
  end
164
171
 
172
+ #
165
173
  # Provides a nice way to execute templates and filters.
166
174
  #
167
175
  # Example:
@@ -170,6 +178,7 @@ module Ruport
170
178
  #
171
179
  # This method automatically passes a binding into the filters, so you are
172
180
  # free to access data from your Report instance in your templates.
181
+ #
173
182
  def process_text(string, options)
174
183
  options[:filters].each do |f|
175
184
  format = Format.new(binding)
@@ -179,60 +188,70 @@ module Ruport
179
188
  string
180
189
  end
181
190
 
182
- # This allows you to create filters to be used by process_text
191
+ #
192
+ # This allows you to create filters to be used by process_text.
183
193
  #
184
194
  # The block is evaluated in the context of the instance.
185
195
  #
186
- # E.g
196
+ # Example:
187
197
  #
188
198
  # text_processor(:unix_newlines) { |r| r.gsub(/\r\n/,"\n") }
199
+ #
189
200
  def text_processor(label,&block)
190
201
  Format.register_filter(label, &block)
191
202
  end
192
203
 
193
-
194
- # Writes the contents of <tt>results</tt> to file. If a filename is
204
+ #
205
+ # Writes the contents of <tt>results</tt> to a file. If a filename is
195
206
  # specified, it will use it. Otherwise, it will try to write to the file
196
207
  # specified by the <tt>file</tt> attribute.
208
+ #
197
209
  def write(my_file=file,my_results=results)
198
210
  File.open(my_file,"w") { |f| f << my_results }
199
211
  end
200
212
 
213
+ #
201
214
  # Like Report#write, but will append to a file rather than overwrite it if
202
- # the file already exists
215
+ # the file already exists.
216
+ #
203
217
  def append(my_file=file)
204
218
  File.open(my_file,"a") { |f| f << results }
205
219
  end
206
220
 
207
221
  class << self
208
222
 
223
+ #
209
224
  # Defines an instance method which will be run before the
210
- # <tt>generate</tt> method when Ruport.run is executed
225
+ # <tt>generate</tt> method when Ruport.run is executed.
211
226
  #
212
- # Good for setting config info and perhaps files and/or loggers
227
+ # Good for setting config info and perhaps files and/or loggers.
213
228
  #
214
229
  def prepare(&block); define_method(:prepare,&block) end
215
230
 
216
- # Defines an instance method which will be executed by Report.run
231
+ #
232
+ # Defines an instance method which will be executed by Report.run.
217
233
  #
218
234
  # The return value of this method is assigned to the <tt>results</tt>
219
- # attribute
235
+ # attribute.
220
236
  #
221
237
  def generate(&block); define_method(:generate,&block) end
222
238
 
239
+ #
223
240
  # Defines an instance method which will be executed after the object is
224
- # yielded in Report.run
241
+ # yielded in Report.run.
225
242
  #
226
243
  def cleanup(&block); define_method(:cleanup,&block) end
227
244
 
245
+ #
228
246
  # Runs the reports specified. If no reports are specified, then it
229
- # creates a new instance via <tt>self.new</tt>
247
+ # creates a new instance via <tt>self.new</tt>.
230
248
  #
231
249
  # Tries to execute the prepare instance method, then runs generate.
232
250
  # It then yields the object so that you may do something with it
233
- # (print something out, write to file, email, etc)
251
+ # (print something out, write to file, email, etc.).
234
252
  #
235
253
  # Finally, it tries to call cleanup.
254
+ #
236
255
  def run(options={})
237
256
  options[:reports] ||= [self.new]
238
257
 
@@ -260,23 +279,26 @@ module Ruport
260
279
 
261
280
  end
262
281
 
263
- # this method passes <tt>self</tt> to Report.run
282
+ #
283
+ # This method passes <tt>self</tt> to Report.run.
264
284
  #
265
285
  # Please see the class method for details.
286
+ #
266
287
  def run(options={},&block)
267
288
  options[:reports] ||= [self]
268
289
  self.class.run(options,&block)
269
290
  end
270
291
 
271
-
272
- # loads a CSV in from file.
273
292
  #
274
- # Example
293
+ # Loads a CSV in from a file.
294
+ #
295
+ # Example:
296
+ #
297
+ # my_table = load_csv "foo.csv" #=> Data::Table
298
+ # my_array = load_csv "foo.csv", :as => :array #=> Array
275
299
  #
276
- # my_table = load_csv "foo.csv" #=> Data::Table
277
- # my_array = load_csv "foo.csv", :as => :array #=> Array
300
+ # See also Ruport::Data::Table.load
278
301
  #
279
- # See also, Ruport::Data::Table.load
280
302
  def load_csv(file,options={})
281
303
  case options[:as]
282
304
  when :array
@@ -287,11 +309,15 @@ module Ruport
287
309
  end
288
310
  end
289
311
 
290
- # Allows logging and other fun stuff. See Ruport.log
312
+ #
313
+ # Allows logging and other fun stuff.
314
+ # See also Ruport.log
315
+ #
291
316
  def log(*args); Ruport.log(*args) end
292
317
 
318
+ #
293
319
  # Creates a new Mailer and sets the <tt>to</tt> attribute to the addresses
294
- # specified. Yields a Mailer object, which can be modified before delivery.
320
+ # specified. Yields a Mailer object, which can be modified before delivery.
295
321
  #
296
322
  def send_to(adds)
297
323
  m = Mailer.new
@@ -1,6 +1,6 @@
1
1
  module Ruport
2
2
  class Report
3
- module Graph
3
+ module Graph #:nodoc:
4
4
  def build_graph
5
5
  a = Ruport::Format.graph_object :plugin => :svg
6
6
  yield(a); return a
@@ -1,6 +1,6 @@
1
1
  module Ruport
2
2
  class Report
3
- module Invoice
3
+ module Invoice #:nodoc:
4
4
 
5
5
  # Returns a Format::Engine::Invoice object
6
6
  #
data/test/test_query.rb CHANGED
@@ -1,80 +1,337 @@
1
1
  require "test/unit"
2
2
  require "ruport"
3
- class TestQuery < Test::Unit::TestCase
4
-
3
+
4
+ begin
5
+ require 'mocha'
6
+ require 'stubba'
7
+ require 'dbi'
8
+ rescue LoadError
9
+ $stderr.puts "Warning: Mocha not found -- skipping some Query tests"
10
+ end
5
11
 
12
+ class TestQuery < Test::Unit::TestCase
6
13
  def setup
7
- Ruport::Config.source :default,
8
- :dsn => "ruport:test", :user => "greg", :password => "apple"
14
+ @sources = {
15
+ :default => {
16
+ :dsn => 'ruport:test', :user => 'greg', :password => 'apple' },
17
+ :alternative => {
18
+ :dsn => "ruport:test2", :user => "sandal", :password => "harmonix" },
19
+ }
20
+ Ruport::Config.source :default, @sources[:default]
21
+ Ruport::Config.source :alternative, @sources[:alternative]
22
+
23
+ @columns = %w(a b c)
24
+ @data = [ [[1,2,3],[4,5,6],[7,8,9]],
25
+ [[9,8,7],[6,5,4],[3,2,1]],
26
+ [[7,8,9],[4,5,6],[1,2,3]], ]
27
+ @datasets = @data.dup
28
+
29
+ @sql = [ "select * from foo", "create table foo ..." ]
30
+ @sql << @sql.values_at(0, 0).join(";\n")
31
+ @sql << @sql.values_at(1, 0).join(";\n")
32
+ @query = {
33
+ :plain => Ruport::Query.new(@sql[0]),
34
+ :sourced => Ruport::Query.new(@sql[0], :source => :alternative),
35
+ :paramed => Ruport::Query.new(@sql[0], :params => [ 42 ]),
36
+ :cached => Ruport::Query.new(@sql[0], :cache_enabled => true),
37
+ :uncached => Ruport::Query.new(@sql[0], :cache_enabled => false),
38
+ :precached => Ruport::Query.new(@sql[0], :cache_enabled => true),
39
+ :raw => Ruport::Query.new(@sql[0], :raw_data => true),
40
+ :unraw => Ruport::Query.new(@sql[0], :raw_data => false),
41
+ :resultless => Ruport::Query.new(@sql[1]),
42
+ :multi => Ruport::Query.new(@sql[2]),
43
+ :mixed => Ruport::Query.new(@sql[3]),
44
+ }
45
+ @query[:precached].cached_data = @data[0]
46
+ end
47
+
48
+ def test_execute
49
+ return unless Object.const_defined? :Mocha
50
+ query = @query[:uncached]
51
+ setup_mock_dbi(1)
9
52
 
10
- Ruport::Config.source :alternate,
11
- :dsn => "ruport:test2", :user => "sandal", :password => "harmonix"
53
+ assert_equal nil, query.execute
54
+ end
55
+
56
+ def test_execute_sourced
57
+ return unless Object.const_defined? :Mocha
58
+ query = @query[:sourced]
59
+ setup_mock_dbi(1, :source => :alternative)
60
+
61
+ assert_equal nil, query.execute
62
+ end
63
+
64
+ def test_execute_paramed
65
+ return unless Object.const_defined? :Mocha
66
+ query = @query[:paramed]
67
+ setup_mock_dbi(1, :params => [ 42 ])
68
+
69
+ assert_equal nil, query.execute
70
+ end
71
+
72
+ def test_result_cache_disabled
73
+ return unless Object.const_defined? :Mocha
74
+ query = @query[:uncached]
75
+ setup_mock_dbi(3)
12
76
 
13
- @query1 = Ruport::Query.new "select * from foo", :cache_enabled => true
14
- @query1.cached_data = [[1,2,3],[4,5,6],[7,8,9]]
77
+ assert_nothing_raised { query.result }
78
+ assert_equal @data[1], get_raw(query.result)
79
+ assert_equal @data[2], get_raw(query.result)
15
80
  end
16
81
 
82
+ def test_result_cache_enabled
83
+ return unless Object.const_defined? :Mocha
84
+ query = @query[:cached]
85
+ setup_mock_dbi(1)
86
+
87
+ assert_nothing_raised { query.result }
88
+ assert_equal @data[0], get_raw(query.result)
89
+ assert_equal @data[0], get_raw(query.result)
90
+ end
91
+
92
+ def test_result_resultless
93
+ return unless Object.const_defined? :Mocha
94
+ query = @query[:resultless]
95
+ setup_mock_dbi(1, :resultless => true, :sql => @sql[1])
96
+
97
+ assert_equal nil, query.result
98
+ end
99
+
100
+ def test_result_multi
101
+ return unless Object.const_defined? :Mocha
102
+ query = @query[:multi]
103
+ setup_mock_dbi(2)
104
+
105
+ assert_equal @data[1], get_raw(query.result)
106
+ end
107
+
108
+ def test_result_raw_disabled
109
+ return unless Object.const_defined? :Mocha
110
+ query = @query[:unraw]
111
+ setup_mock_dbi(1)
112
+
113
+ assert_equal @data[0].to_table(@columns), query.result
114
+ end
115
+
116
+ def test_result_raw_enabled
117
+ return unless Object.const_defined? :Mocha
118
+ query = @query[:raw]
119
+ setup_mock_dbi(1)
120
+
121
+ assert_equal @data[0], query.result
122
+ end
123
+
124
+ def test_update_cache
125
+ return unless Object.const_defined? :Mocha
126
+ query = @query[:cached]
127
+ setup_mock_dbi(2)
128
+
129
+ assert_equal @data[0], get_raw(query.result)
130
+ query.update_cache
131
+ assert_equal @data[1], get_raw(query.cached_data)
132
+ assert_equal @data[1], get_raw(query.result)
133
+ end
134
+
135
+ def test_clear_cache
136
+ return unless Object.const_defined? :Mocha
137
+ query = @query[:cached]
138
+ setup_mock_dbi(2)
139
+
140
+ assert_equal @data[0], get_raw(query.result)
141
+ query.clear_cache
142
+ assert_equal nil, query.cached_data
143
+ assert_equal @data[1], get_raw(query.result)
144
+ end
17
145
 
18
- def test_result
19
- assert_nothing_raised { @query1.result }
20
- assert_equal([[1,2,3],[4,5,6],[7,8,9]],@query1.result)
146
+ def test_disable_caching
147
+ return unless Object.const_defined? :Mocha
148
+ query = @query[:cached]
149
+ setup_mock_dbi(3)
150
+
151
+ assert_equal @data[0], get_raw(query.result)
152
+ assert_equal @data[0], get_raw(query.result)
153
+ query.disable_caching
154
+ assert_equal @data[1], get_raw(query.result)
155
+ assert_equal @data[2], get_raw(query.result)
21
156
  end
22
157
 
23
- def test_auto_resolve_file
24
- q = Ruport::Query.new "test/samples/query_test.sql"
25
- assert_equal "select * from foo", q.sql
158
+ def test_enable_caching
159
+ return unless Object.const_defined? :Mocha
160
+ query = @query[:uncached]
161
+ setup_mock_dbi(3)
162
+
163
+ assert_equal @data[0], get_raw(query.result)
164
+ assert_equal @data[1], get_raw(query.result)
165
+ query.enable_caching
166
+ assert_equal @data[2], get_raw(query.result)
167
+ assert_equal @data[2], get_raw(query.result)
168
+ end
169
+
170
+ def test_load_file
171
+ return unless Object.const_defined? :Mocha
172
+ File.expects(:read).
173
+ with("query_test.sql").
174
+ returns("select * from foo\n")
175
+
176
+ query = Ruport::Query.new "query_test.sql"
177
+ assert_equal "select * from foo", query.sql
26
178
  end
27
179
 
28
- def test_erb_replacement
180
+ def test_load_file_erb
181
+ return unless Object.const_defined? :Mocha
29
182
  @table = 'bar'
30
- q = Ruport::Query.new "test/samples/erb_test.sql", :binding => binding
31
- assert_equal "select * from bar", q.sql
183
+ File.expects(:read).
184
+ with("query_test.sql").
185
+ returns("select * from <%= @table %>\n")
186
+
187
+ query = Ruport::Query.new "query_test.sql", :binding => binding
188
+ assert_equal "select * from bar", query.sql
32
189
  end
33
190
 
34
- def test_each
35
- data = [[1,2,3],[4,5,6],[7,8,9]]
36
- @query1.each do |r|
37
- assert_equal(data.shift,r)
38
- end
39
- data = [1,4,7]
40
- @query1.each do |r|
41
- assert_equal(data.shift,r.first)
191
+ def test_load_file_not_found
192
+ return unless Object.const_defined? :Mocha
193
+ File.expects(:read).
194
+ with("query_test.sql").
195
+ raises(Errno::ENOENT)
196
+ Ruport.expects(:log).
197
+ with("Could not open query_test.sql",
198
+ :status => :fatal, :exception => LoadError).
199
+ raises(LoadError)
200
+
201
+ assert_raises LoadError do
202
+ query = Ruport::Query.new "query_test.sql"
42
203
  end
43
- assert_raise (LocalJumpError) { @query1.each }
44
204
  end
45
205
 
46
- def test_select_source
47
-
48
- assert_equal( "ruport:test", @query1.instance_eval("@dsn") )
49
- assert_equal( "greg", @query1.instance_eval("@user") )
50
- assert_equal( "apple", @query1.instance_eval("@password") )
206
+ def test_each_cache_disabled
207
+ return unless Object.const_defined? :Mocha
208
+ query = @query[:uncached]
209
+ setup_mock_dbi(2)
51
210
 
52
- @query1.select_source :alternate
211
+ result = []; query.each { |r| result << r.to_a }
212
+ assert_equal @data[0], result
213
+
214
+ result = []; query.each { |r| result << r.to_a }
215
+ assert_equal @data[1], result
216
+ end
53
217
 
54
- assert_equal( "ruport:test2", @query1.instance_eval("@dsn") )
55
- assert_equal( "sandal", @query1.instance_eval("@user") )
56
- assert_equal( "harmonix", @query1.instance_eval("@password") )
218
+ def test_each_cache_enabled
219
+ return unless Object.const_defined? :Mocha
220
+ query = @query[:cached]
221
+ setup_mock_dbi(1)
57
222
 
58
- @query1.select_source :default
223
+ result = []; query.each { |r| result << r.to_a }
224
+ assert_equal @data[0], result
225
+
226
+ result = []; query.each { |r| result << r.to_a }
227
+ assert_equal @data[0], result
228
+ end
229
+
230
+ def test_each_multi
231
+ return unless Object.const_defined? :Mocha
232
+ query = @query[:multi]
233
+ setup_mock_dbi(2)
59
234
 
60
- assert_equal( "ruport:test", @query1.instance_eval("@dsn") )
61
- assert_equal( "greg", @query1.instance_eval("@user") )
62
- assert_equal( "apple", @query1.instance_eval("@password") )
63
-
235
+ result = []; query.each { |r| result << r.to_a }
236
+ assert_equal @data[1], result
237
+ end
238
+
239
+ def test_each_without_block
240
+ assert_raise (LocalJumpError) { @query[:precached].each }
241
+ end
242
+
243
+ def test_select_source
244
+ query = @query[:precached]
245
+ assert_equal @sources[:default], get_query_source(query)
246
+
247
+ query.select_source :alternative
248
+ assert_equal @sources[:alternative], get_query_source(query)
249
+
250
+ query.select_source :default
251
+ assert_equal @sources[:default], get_query_source(query)
252
+ end
253
+
254
+ def test_initialize_source_temporary
255
+ query = Ruport::Query.new "<unused>", @sources[:alternative]
256
+ assert_equal @sources[:alternative], get_query_source(query)
257
+ end
258
+
259
+ def test_initialize_source_temporary_multiple
260
+ query1 = Ruport::Query.new "<unused>", @sources[:default]
261
+ query2 = Ruport::Query.new "<unused>", @sources[:alternative]
262
+
263
+ assert_equal @sources[:default], get_query_source(query1)
264
+ assert_equal @sources[:alternative], get_query_source(query2)
64
265
  end
65
266
 
66
267
  def test_generator
67
- assert @query1.generator.kind_of?(Generator)
68
- gen = @query1.generator
69
- assert_equal [1,2,3], gen.next
70
- assert_equal [4,5,6], gen.next
71
- assert_equal [7,8,9], gen.next
268
+ query = @query[:precached]
269
+ gen = query.generator
270
+ assert_equal @data[0][0], gen.next
271
+ assert_equal @data[0][1], gen.next
272
+ assert_equal @data[0][2], gen.next
72
273
  assert_raise(EOFError) { gen.next }
73
274
  end
74
275
 
75
- def test_caching_triggers
76
- assert_nothing_raised { @query1.enable_caching }
77
- assert_nothing_raised { @query1.disable_caching }
276
+ def test_to_table
277
+ return unless Object.const_defined? :Mocha
278
+ query = @query[:raw]
279
+ setup_mock_dbi(3, :returns => @data[0])
280
+
281
+ assert_equal @data[0], query.result
282
+ assert_equal @data[0].to_table(@columns), query.to_table
283
+ assert_equal @data[0], query.result
78
284
  end
79
285
 
286
+ def test_to_csv
287
+ return unless Object.const_defined? :Mocha
288
+ query = @query[:plain]
289
+ setup_mock_dbi(1)
290
+
291
+ csv = @data[0].to_table(@columns).as(:csv)
292
+ assert_equal csv, query.to_csv
293
+ end
294
+
295
+ private
296
+ def setup_mock_dbi(count, options={})
297
+ sql = options[:sql] || @sql[0]
298
+ source = options[:source] || :default
299
+ returns = options[:returns] || Proc.new { @datasets.shift }
300
+ resultless = options[:resultless]
301
+ params = options[:params] || []
302
+
303
+ @dbh = mock("database_handle")
304
+ @sth = mock("statement_handle")
305
+ def @dbh.execute(*a, &b); execute__(*a, &b); ensure; sth__.finish if b; end
306
+ def @sth.each; data__.each { |x| yield(x) }; end
307
+ def @sth.fetch_all; data__; end
308
+
309
+ DBI.expects(:connect).
310
+ with(*@sources[source].values_at(:dsn, :user, :password)).
311
+ yields(@dbh).times(count)
312
+ @dbh.expects(:execute__).with(sql, *params).
313
+ yields(@sth).returns(@sth).times(count)
314
+ @dbh.stubs(:sth__).returns(@sth)
315
+ @sth.expects(:finish).with().times(count)
316
+ unless resultless
317
+ @sth.stubs(:fetchable?).returns(true)
318
+ @sth.stubs(:column_names).returns(@columns)
319
+ @sth.expects(:data__).returns(returns).times(count)
320
+ else
321
+ @sth.stubs(:fetchable?).returns(false)
322
+ @sth.stubs(:column_names).returns([])
323
+ @sth.stubs(:cancel)
324
+ @sth.expects(:data__).times(0)
325
+ end
326
+ end
327
+
328
+ def get_query_source(query)
329
+ [ :dsn, :user, :password ].inject({}) do |memo, var|
330
+ memo.update var => query.instance_variable_get("@#{var}")
331
+ end
332
+ end
333
+
334
+ def get_raw(table)
335
+ table.collect { |row| row.to_a }
336
+ end
80
337
  end