ruport 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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