mochigome 0.0.3 → 0.0.4

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.
data/test/test_helper.rb CHANGED
@@ -1,67 +1,67 @@
1
1
  ENV['RAILS_ENV'] = 'test'
2
2
 
3
- prev_dir = Dir.getwd
4
3
  begin
5
- Dir.chdir("#{File.dirname(__FILE__)}/..")
6
-
7
- begin
8
- # Used when running test files directly
9
- $LOAD_PATH << File.dirname(__FILE__)
10
- $LOAD_PATH << "#{File.dirname(__FILE__)}/../lib"
11
- require "#{File.dirname(__FILE__)}/app_root/config/environment"
12
- rescue LoadError
13
- # This is needed for root-level rake task 'test'
14
- require "app_root/config/environment"
15
- end
16
- ensure
17
- Dir.chdir(prev_dir)
4
+ # Used when running test files directly
5
+ d = File.expand_path File.dirname(__FILE__)
6
+ $LOAD_PATH << d
7
+ $LOAD_PATH << "#{d}/../lib"
8
+ $LOAD_PATH << "#{d}/app_root/config"
9
+ require "environment"
10
+ rescue LoadError
11
+ # This is needed for root-level rake task 'test'
12
+ require "app_root/config/environment"
18
13
  end
19
14
 
20
15
  require 'rubygems'
21
- require 'minitest/autorun'
22
- require 'redgreen'
23
16
 
24
- module MiniTest
25
- def self.filter_backtrace(backtrace)
26
- backtrace = backtrace.select do |e|
27
- if ENV['FULL_BACKTRACE']
28
- true
29
- else
30
- !(e.include?("/ruby/") || e.include?("/gems/"))
17
+ if ENV['NO_MINITEST']
18
+ ActiveRecord::Migration.verbose = false
19
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate") # Migrations in the test app
20
+ else
21
+ require 'minitest/autorun'
22
+ require 'redgreen'
23
+
24
+ module MiniTest
25
+ def self.filter_backtrace(backtrace)
26
+ backtrace = backtrace.select do |e|
27
+ if ENV['FULL_BACKTRACE']
28
+ true
29
+ else
30
+ !(e.include?("/ruby/") || e.include?("/gems/"))
31
+ end
31
32
  end
32
- end
33
33
 
34
- common_prefix = nil
35
- backtrace.each do |elem|
36
- next if elem.start_with? "./"
37
- if common_prefix
38
- until elem.start_with? common_prefix
39
- common_prefix.chop!
34
+ common_prefix = nil
35
+ backtrace.each do |elem|
36
+ next if elem.start_with? "./"
37
+ if common_prefix
38
+ until elem.start_with? common_prefix
39
+ common_prefix.chop!
40
+ end
41
+ else
42
+ common_prefix = String.new(elem)
40
43
  end
41
- else
42
- common_prefix = String.new(elem)
43
44
  end
44
- end
45
45
 
46
- return backtrace.map do |element|
47
- if element.start_with? common_prefix && common_prefix.size < element.size
48
- element[common_prefix.size, element.size]
49
- elsif element.start_with? "./"
50
- element[2, element.size]
51
- elsif element.start_with?(Dir.getwd)
52
- element[Dir.getwd.size+1, element.size]
53
- else
54
- element
46
+ return backtrace.map do |element|
47
+ if element.start_with? common_prefix && common_prefix.size < element.size
48
+ element[common_prefix.size, element.size]
49
+ elsif element.start_with? "./"
50
+ element[2, element.size]
51
+ elsif element.start_with?(Dir.getwd)
52
+ element[Dir.getwd.size+1, element.size]
53
+ else
54
+ element
55
+ end
55
56
  end
56
57
  end
57
58
  end
58
- end
59
-
60
59
 
61
- require 'factories'
62
- MiniTest::Unit::TestCase.send(:include, Factory::Syntax::Methods)
60
+ require 'factories'
61
+ MiniTest::Unit::TestCase.send(:include, Factory::Syntax::Methods)
63
62
 
64
- MiniTest::Unit::TestCase.add_setup_hook do
65
- ActiveRecord::Migration.verbose = false
66
- ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate") # Migrations in the test app
63
+ MiniTest::Unit::TestCase.add_setup_hook do
64
+ ActiveRecord::Migration.verbose = false
65
+ ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate") # Migrations in the test app
66
+ end
67
67
  end
@@ -77,6 +77,13 @@ describe Mochigome::DataNode do
77
77
  ]
78
78
  assert_equal @datanode.children.drop(1), new_children
79
79
  end
80
+
81
+ it "understands forward-slash to mean indexing in children" do
82
+ @datanode << Mochigome::DataNode.new(:subdata, :alice)
83
+ @datanode << Mochigome::DataNode.new(:subdata, :bob)
84
+ assert_equal @datanode.children[0], @datanode/0
85
+ assert_equal @datanode.children[1], @datanode/1
86
+ end
80
87
  end
81
88
 
82
89
  describe "when populated" do
@@ -1,31 +1,5 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
2
 
3
- describe "an input string" do
4
- it "will be converted by auto_numerify to an integer if appropriate" do
5
- [35, -35, 0].each do |n|
6
- result = Mochigome::ReportFocus.auto_numerify(n.to_s)
7
- assert_equal n, result
8
- assert_kind_of Integer, result
9
- end
10
- end
11
-
12
- it "will be converted by auto_numerify to a float if appropriate" do
13
- [-35.5, 35.5, 0.0].each do |n|
14
- result = Mochigome::ReportFocus.auto_numerify(n.to_s)
15
- assert_in_delta n, result
16
- assert_kind_of Float, result
17
- end
18
- end
19
-
20
- it "will remain a string if it is not numeric" do
21
- ["", "zero", "yeehah", "foo0.0" "9.2bar"].each do |s|
22
- result = Mochigome::ReportFocus.auto_numerify(s)
23
- assert_equal s, result
24
- assert_kind_of String, result
25
- end
26
- end
27
- end
28
-
29
3
  describe "an ActiveRecord model" do
30
4
  before do
31
5
  @model_class = Class.new(ActiveRecord::Base)
@@ -147,6 +121,27 @@ describe "an ActiveRecord model" do
147
121
  assert_equal "Moby Dick", i.mochigome_focus.name
148
122
  end
149
123
 
124
+ it "uses the primary key as the default ordering" do
125
+ @model_class.class_eval do
126
+ acts_as_mochigome_focus do |f|
127
+ f.name :last_name
128
+ end
129
+ end
130
+ assert_equal "id",
131
+ @model_class.mochigome_focus_settings.get_ordering
132
+ end
133
+
134
+ it "can specify a custom ordering" do
135
+ @model_class.class_eval do
136
+ acts_as_mochigome_focus do |f|
137
+ f.name :last_name
138
+ f.ordering :first_name
139
+ end
140
+ end
141
+ assert_equal "first_name",
142
+ @model_class.mochigome_focus_settings.get_ordering
143
+ end
144
+
150
145
  it "can specify fields" do
151
146
  @model_class.class_eval do
152
147
  acts_as_mochigome_focus do |f|
@@ -275,119 +270,141 @@ describe "an ActiveRecord model" do
275
270
  end
276
271
  end
277
272
 
278
- it "appears in Mochigome's global model list if it acts_as_mochigome_focus" do
279
- assert !Mochigome.reportFocusModels.include?(@model_class)
280
- @model_class.class_eval do
281
- acts_as_mochigome_focus
282
- end
283
- assert Mochigome.reportFocusModels.include?(@model_class)
284
- end
273
+ # Actual use of aggregations is tested in query_test.
285
274
 
286
275
  it "can specify aggregated data to be collected" do
287
276
  @model_class.class_eval do
288
- has_mochigome_aggregations [:average_x, :Count, "sum x"]
277
+ has_mochigome_aggregations do |a|
278
+ a.fields [
279
+ :average_x,
280
+ :Count,
281
+ {"bloo" => :sum_x}
282
+ ]
283
+ end
289
284
  end
290
- # Peeking in past API to make sure it set the expressions correctly
291
285
  assert_equal [
292
- {:name => "Whales average x", :expr => "avg(x)"},
293
- {:name => "Whales Count", :expr => "count(*)"},
294
- {:name => "Whales sum x", :expr => "sum(x)"}
295
- ], @model_class.mochigome_aggregations
286
+ "Whales average x",
287
+ "Whales Count",
288
+ "bloo"
289
+ ], @model_class.mochigome_aggregation_settings.options[:fields].map{|a| a[:name]}
296
290
  end
297
291
 
298
292
  it "can specify aggregations with custom names" do
299
293
  @model_class.class_eval do
300
- has_mochigome_aggregations [{"Mean X" => "avg x"}]
294
+ has_mochigome_aggregations do |a|
295
+ a.fields [{"Mean X" => "avg x"}]
296
+ end
301
297
  end
302
298
  assert_equal [
303
- {:name => "Mean X", :expr => "avg(x)"}
304
- ], @model_class.mochigome_aggregations
299
+ "Mean X"
300
+ ], @model_class.mochigome_aggregation_settings.options[:fields].map{|a| a[:name]}
305
301
  end
306
302
 
307
- it "can specify aggregations with custom SQL expressions" do
303
+ it "can specify aggregations with custom arel expressions for value" do
308
304
  @model_class.class_eval do
309
- has_mochigome_aggregations [{"The Answer" => "7*6"}]
305
+ has_mochigome_aggregations do |a|
306
+ a.fields [{"The Answer" => [:sum, lambda{|t| t[:some_number_column]*2}]}]
307
+ end
310
308
  end
311
309
  assert_equal [
312
- {:name => "The Answer", :expr => "7*6"}
313
- ], @model_class.mochigome_aggregations
310
+ "The Answer"
311
+ ], @model_class.mochigome_aggregation_settings.options[:fields].map{|a| a[:name]}
314
312
  end
315
313
 
316
- it "can specify aggregations with custom conditions" do
314
+ it "can specify aggregations with custom arel expressions for aggregation" do
317
315
  @model_class.class_eval do
318
- has_mochigome_aggregations [{"Blue Sales" => ["count", "color='blue'"]}]
316
+ has_mochigome_aggregations do |a|
317
+ a.fields [{"The Answer" => [lambda{|a| a.sum}, :some_col]}]
318
+ end
319
319
  end
320
320
  assert_equal [
321
- {:name => "Blue Sales", :expr => "count(*)", :conditions => "color='blue'"}
322
- ], @model_class.mochigome_aggregations
321
+ "The Answer"
322
+ ], @model_class.mochigome_aggregation_settings.options[:fields].map{|a| a[:name]}
323
323
  end
324
324
 
325
- it "cannot call has_mochigome_aggregations with nonsense" do
325
+ it "cannot call aggregation fields method with nonsense" do
326
326
  assert_raises Mochigome::ModelSetupError do
327
327
  @model_class.class_eval do
328
- has_mochigome_aggregations 3
328
+ has_mochigome_aggregations do |a|
329
+ a.fields 3
330
+ end
329
331
  end
330
332
  end
331
333
  assert_raises Mochigome::ModelSetupError do
332
334
  @model_class.class_eval do
333
- has_mochigome_aggregations [42]
335
+ has_mochigome_aggregations do |a|
336
+ a.fields [42]
337
+ end
334
338
  end
335
339
  end
336
340
  end
337
341
 
338
- describe "with some aggregatable data" do
339
- before do
340
- @store1 = create(:store)
341
- @store2 = create(:store)
342
- @product_a = create(:product, :name => "Product A", :price => 30)
343
- @product_b = create(:product, :name => "Product B", :price => 50)
344
- @sp1A = create(:store_product, :store => @store1, :product => @product_a)
345
- @sp1B = create(:store_product, :store => @store1, :product => @product_b)
346
- @sp2A = create(:store_product, :store => @store2, :product => @product_a)
347
- @sp2B = create(:store_product, :store => @store2, :product => @product_b)
348
- [
349
- [2, @sp1A],
350
- [4, @sp1B],
351
- [7, @sp2A],
352
- [3, @sp2B]
353
- ].each do |num, sp|
354
- num.times { create(:sale, :store_product => sp) }
342
+ it "can specify hidden aggregation fields" do
343
+ @model_class.class_eval do
344
+ has_mochigome_aggregations do |a|
345
+ a.hidden_fields [:count]
355
346
  end
356
347
  end
348
+ agg = @model_class.mochigome_aggregation_settings.options[:fields].first
349
+ assert_equal "Whales count", agg[:name]
350
+ assert agg[:hidden]
351
+ end
357
352
 
358
- it "can collect aggregate data from a report focus through an association" do
359
- assert_equal 9, @product_a.mochigome_focus.aggregate_data('sales')['Sales count']
360
- assert_equal 7, @product_b.mochigome_focus.aggregate_data('sales')['Sales count']
361
- end
362
-
363
- it "can collect aggregate data through all known associations with :all keyword" do
364
- assert_equal 9, @product_a.mochigome_focus.aggregate_data(:all)['Sales count']
353
+ it "can specify aggregation fields in ruby which post-process regular fields" do
354
+ @model_class.class_eval do
355
+ has_mochigome_aggregations do |a|
356
+ a.hidden_fields [:count]
357
+ a.fields_in_ruby [
358
+ {"Double count" => lambda{|row| row["Whales count"]*2}}
359
+ ]
360
+ end
365
361
  end
362
+ agg = @model_class.mochigome_aggregation_settings.options[:fields].last
363
+ assert_equal "Double count", agg[:name]
364
+ assert agg[:in_ruby]
365
+ end
366
366
 
367
- it "returns both field data and all aggregate data with the data method" do
368
- data = @product_a.mochigome_focus.data
369
- assert_equal 9, data['Sales count']
370
- assert_equal 30, data['price']
367
+ def assoc_query_words_match(assoc, words)
368
+ q = assoc.call(Arel::Table.new(:foo).project(Arel.star)).to_sql
369
+ cur_word = words.shift
370
+ q.split(/[ .]/).each do |s_word|
371
+ if s_word.gsub(/["'`]+/, '').downcase == cur_word.downcase
372
+ cur_word = words.shift
373
+ end
371
374
  end
375
+ return true if cur_word.nil?
376
+ raise "AQWM '#{q}': NO WORD MATCH ON '#{cur_word}'"
377
+ end
372
378
 
373
- it "can return data aggregated in the context of another class with similar assoc" do
374
- focus = @product_a.mochigome_focus
375
- assert_equal 2, focus.aggregate_data('sales', :context => [@sp1A])['Sales count']
379
+ it "can convert a belongs_to association into a lambda that processes an arel relation" do
380
+ @model_class.class_eval do
381
+ belongs_to :store
376
382
  end
383
+ assert assoc_query_words_match @model_class.arelified_assoc(:store),
384
+ %w{select * from foo join stores on fake store_id = stores id}
385
+ end
377
386
 
378
- it "can return data aggregated in the context through the data method" do
379
- focus = @product_a.mochigome_focus
380
- assert_equal 2, focus.data(:context => [@sp1A])['Sales count']
387
+ it "can convert a has_many association into an arel relation lambda" do
388
+ @model_class.class_eval do
389
+ has_many :stores
381
390
  end
391
+ assert assoc_query_words_match @model_class.arelified_assoc(:stores),
392
+ %w{select * from foo join stores on fake id = stores whale_id}
393
+ end
382
394
 
383
- it "can return data aggregated using a custom sql expression" do
384
- focus = @store1.mochigome_focus
385
- assert_equal 9001, focus.data['Power level']
395
+ it "can convert a has_one association into an arel relation lambda" do
396
+ @model_class.class_eval do
397
+ has_one :store
386
398
  end
399
+ assert assoc_query_words_match @model_class.arelified_assoc(:store),
400
+ %w{select * from foo join stores on fake id = stores whale_id}
401
+ end
387
402
 
388
- it "can return data aggregated using custom conditions" do
389
- focus = @store1.mochigome_focus
390
- assert_equal 1, focus.data['Expensive products']
403
+ it "raises AssociationError on attempting to arelify a non-extant assoc" do
404
+ assert_raises Mochigome::AssociationError do
405
+ Store.arelified_assoc(:dinosaurs)
391
406
  end
392
407
  end
408
+
409
+ # TODO: Test proper conditions used on polymorphic assocs
393
410
  end