sparkql 0.1.8 → 0.3.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.
@@ -1,9 +1,18 @@
1
1
  require 'test_helper'
2
+ require 'sparkql/geo'
2
3
 
3
4
  class ParserTest < Test::Unit::TestCase
4
5
  include Sparkql
5
6
 
6
- def test_now
7
+ test "function parameters and name preserved" do
8
+ f = FunctionResolver.new('radius', [{:type => :character,
9
+ :value => "35.12 -68.33"},{:type => :decimal, :value => 1.0}])
10
+ value = f.call
11
+ assert_equal 'radius', value[:function_name]
12
+ assert_equal(["35.12 -68.33", 1.0], value[:function_parameters])
13
+ end
14
+
15
+ test "now()" do
7
16
  start = Time.now
8
17
  f = FunctionResolver.new('now', [])
9
18
  f.validate
@@ -14,8 +23,9 @@ class ParserTest < Test::Unit::TestCase
14
23
  assert (-5 < test_time - start && 5 > test_time - start), "Time range off by more than five seconds #{test_time - start} '#{test_time} - #{start}'"
15
24
  end
16
25
 
17
- def test_day
18
- d = Date.today
26
+ test "days()" do
27
+ d = Date.new(2012,10,20)
28
+ Date.expects(:today).returns(d)
19
29
  dt = DateTime.new(d.year, d.month,d.day, 0,0,0, DateTime.now.offset)
20
30
  start = Time.parse(dt.to_s)
21
31
  f = FunctionResolver.new('days', [{:type=>:integer, :value =>7}])
@@ -24,10 +34,99 @@ class ParserTest < Test::Unit::TestCase
24
34
  value = f.call
25
35
  assert_equal :date, value[:type]
26
36
  test_time = Time.parse(value[:value])
27
- assert (605000 > test_time - start && 604000 < test_time - start), "Time range off by more than five seconds #{test_time - start} '#{test_time} - #{start}'"
37
+ assert (615000 > test_time - start && 600000 < test_time - start), "Time range off by more than five seconds #{test_time - start} '#{test_time} - #{start}'"
38
+ end
39
+
40
+ test "months()" do
41
+ dt = DateTime.new(2014, 1, 6, 0, 0, 0, 0)
42
+ DateTime.expects(:now).once.returns(dt)
43
+
44
+ f = FunctionResolver.new('months', [{:type=>:integer, :value =>3}])
45
+ f.validate
46
+ assert !f.errors?, "Errors resolving months(): #{f.errors.inspect}"
47
+ value = f.call
48
+ assert_equal :date, value[:type]
49
+
50
+ assert_equal "2014-04-06", value[:value]
51
+ end
52
+
53
+ test "years()" do
54
+ dt = DateTime.new(2014, 1, 6, 0, 0, 0, 0)
55
+ DateTime.expects(:now).once.returns(dt)
56
+ f = FunctionResolver.new('years', [{:type=>:integer, :value =>-4}])
57
+ f.validate
58
+ assert !f.errors?, "Errors resolving years(): #{f.errors.inspect}"
59
+ value = f.call
60
+ assert_equal :date, value[:type]
61
+ assert_equal '2010-01-06', value[:value], "negative values should go back in time"
62
+ end
63
+
64
+
65
+
66
+ # Polygon searches
67
+
68
+ test "radius()" do
69
+ f = FunctionResolver.new('radius', [{:type => :character, :value => "35.12 -68.33"},{:type => :decimal, :value => 1.0}])
70
+ f.validate
71
+ assert !f.errors?, "Errors #{f.errors.inspect}"
72
+ value = f.call
73
+ assert_equal :shape, value[:type]
74
+ assert_equal GeoRuby::SimpleFeatures::Circle, value[:value].class
75
+ assert_equal [-68.33, 35.12], value[:value].center.to_coordinates, "#{value[:value].inspect} "
76
+ assert_equal 1.0, value[:value].radius, "#{value[:value].inspect} "
77
+ end
78
+
79
+ test "radius() can be overloaded with a ListingKey" do
80
+ f = FunctionResolver.new('radius', [{:type => :character, :value => "20100000000000000000000000"},
81
+ {:type => :decimal, :value => 1.0}])
82
+ f.validate
83
+ assert !f.errors?, "Errors #{f.errors.inspect}"
84
+ value = f.call
85
+ assert_equal :shape, value[:type]
86
+ assert_equal Sparkql::Geo::RecordRadius, value[:value].class
87
+ assert_equal "20100000000000000000000000", value[:value].record_id, "#{value[:value].inspect} "
88
+ assert_equal 1.0, value[:value].radius, "#{value[:value].inspect} "
89
+ end
90
+
91
+ test "radius() fails if not given coords or a flex ID" do
92
+ f = FunctionResolver.new('radius', [{:type => :character, :value => "35.12,-68.33"},
93
+ {:type => :decimal, :value => 1.0}])
94
+ f.validate
95
+ value = f.call
96
+ assert f.errors?
97
+ end
98
+
99
+ test "polygon()" do
100
+ f = FunctionResolver.new('polygon', [{:type => :character, :value => "35.12 -68.33,35.12 -68.32, 35.13 -68.32,35.13 -68.33"}])
101
+ f.validate
102
+ assert !f.errors?, "Errors #{f.errors.inspect}"
103
+ value = f.call
104
+ assert_equal :shape, value[:type]
105
+ assert_equal GeoRuby::SimpleFeatures::Polygon, value[:value].class
106
+ assert_equal [[-68.33, 35.12], [-68.32, 35.12], [-68.32, 35.13], [-68.33, 35.13], [-68.33, 35.12]], value[:value].to_coordinates.first, "#{value[:value].inspect} "
107
+ end
108
+
109
+ test "linestring()" do
110
+ f = FunctionResolver.new('linestring', [{:type => :character, :value => "35.12 -68.33,35.12 -68.32"}])
111
+ f.validate
112
+ assert !f.errors?, "Errors #{f.errors.inspect}"
113
+ value = f.call
114
+ assert_equal :shape, value[:type]
115
+ assert_equal GeoRuby::SimpleFeatures::LineString, value[:value].class
116
+ assert_equal [[-68.33, 35.12], [-68.32, 35.12]], value[:value].to_coordinates, "#{value[:value].inspect} "
117
+ end
118
+
119
+ test "rectangle()" do
120
+ f = FunctionResolver.new('rectangle', [{:type => :character, :value => "35.12 -68.33, 35.13 -68.32"}])
121
+ f.validate
122
+ assert !f.errors?, "Errors #{f.errors.inspect}"
123
+ value = f.call
124
+ assert_equal :shape, value[:type]
125
+ assert_equal GeoRuby::SimpleFeatures::Polygon, value[:value].class
126
+ assert_equal [[-68.33,35.12], [-68.32,35.12], [-68.32,35.13], [-68.33,35.13], [-68.33,35.12]], value[:value].to_coordinates.first, "#{value[:value].inspect} "
28
127
  end
29
128
 
30
- def test_invalid_param
129
+ test "invalid params" do
31
130
  f = FunctionResolver.new('now', [{:type => :character, :value=>'bad value'}])
32
131
  f.validate
33
132
  assert f.errors?, "'now' function does not support parameters"
@@ -40,8 +139,15 @@ class ParserTest < Test::Unit::TestCase
40
139
  f.validate
41
140
  assert f.errors?, "'days' function needs integer parameter"
42
141
  end
142
+
143
+ test "assert nil returned when function called with errors" do
144
+ f = FunctionResolver.new('radius', [{:type => :character,
145
+ :value => "35.12 -68.33, 35.13 -68.34"},{:type => :decimal,
146
+ :value => 1.0}])
147
+ assert_nil f.call
148
+ end
43
149
 
44
- def test_invalid_function
150
+ test "invalid function" do
45
151
  f = FunctionResolver.new('then', [])
46
152
  f.validate
47
153
  assert f.errors?, "'then' is not a function"
@@ -0,0 +1,15 @@
1
+ require 'test_helper'
2
+
3
+ class Sparkql::Geo::RecordRadiusTest < Test::Unit::TestCase
4
+ def test_valid_record_id
5
+ assert Sparkql::Geo::RecordRadius.valid_record_id?("20100000000000000000000000")
6
+
7
+ ["2010000000000000000000000",
8
+ "201000000000000000000000000",
9
+ "test",
10
+ "12.45,-96.5"].each do |bad_record_id|
11
+ assert !Sparkql::Geo::RecordRadius.valid_record_id?(bad_record_id),
12
+ "'#{bad_record_id}' should not be a valid record_id"
13
+ end
14
+ end
15
+ end
@@ -10,12 +10,34 @@ class LexerTest < Test::Unit::TestCase
10
10
  assert_equal :STANDARD_FIELD, token.first, standard_field
11
11
  end
12
12
  end
13
+
14
+ def test_standard_field_formats
15
+ ["City", "PostalCodePlus4", "Inb4ParserError"].each do |standard_field|
16
+ @lexer = Lexer.new("#{standard_field} Eq true")
17
+ token = @lexer.shift
18
+ assert_equal :STANDARD_FIELD, token.first, standard_field
19
+ assert_equal token[1], standard_field
20
+ end
21
+ end
22
+
23
+ def test_bad_standard_field_formats
24
+ @lexer = Lexer.new("4PostalCodePlus4 Eq true")
25
+ token = @lexer.shift
26
+ assert_equal :INTEGER, token.first
27
+ assert_equal token[1][:value], "4"
28
+ end
29
+
13
30
  def test_check_reserved_words_conjunctions
14
31
  ['And Derp', 'Or 123'].each do |conjunction|
15
32
  @lexer = Lexer.new(conjunction)
16
33
  token = @lexer.shift
17
34
  assert_equal :CONJUNCTION, token.first, conjunction
18
35
  end
36
+ ['Not Lol'].each do |conjunction|
37
+ @lexer = Lexer.new(conjunction)
38
+ token = @lexer.shift
39
+ assert_equal :UNARY_CONJUNCTION, token.first, conjunction
40
+ end
19
41
  end
20
42
 
21
43
  def test_check_reserved_words_operators
@@ -24,6 +46,27 @@ class LexerTest < Test::Unit::TestCase
24
46
  token = @lexer.shift
25
47
  assert_equal :OPERATOR, token.first, op
26
48
  end
49
+
50
+ ['Bt 1234','Bt 1234,12345'].each do |op|
51
+ @lexer = Lexer.new(op)
52
+ token = @lexer.shift
53
+ assert_equal :RANGE_OPERATOR, token.first, op
54
+ end
55
+ end
56
+
57
+ def test_datetimes_matches
58
+ ['2013-07-26T10:22:15.422804', '2013-07-26T10:22:15'].each do |op|
59
+ @lexer = Lexer.new(op)
60
+ token = @lexer.shift
61
+ assert_equal :DATETIME, token.first, op
62
+ end
63
+ end
64
+
65
+ def test_utc_offsets
66
+ ['2013-07-26T10:22:15.422804-0300', '2013-07-26T10:22:15+0400'].each do |op|
67
+ @lexer = Lexer.new(op)
68
+ token = @lexer.shift
69
+ assert_equal :DATETIME, token.first, op
70
+ end
27
71
  end
28
-
29
72
  end
@@ -72,6 +72,11 @@ class ParserCompatabilityTest < Test::Unit::TestCase
72
72
  :type => :decimal,
73
73
  :operator => "In"
74
74
  },
75
+ {
76
+ :string => "FloatField Eq 100.1,2,3.4",
77
+ :type => :decimal,
78
+ :operator => "In"
79
+ },
75
80
  {
76
81
  :string => "DateField Eq 2010-10-10",
77
82
  :type => :date,
@@ -155,7 +160,7 @@ class ParserCompatabilityTest < Test::Unit::TestCase
155
160
  @test_filters.each do |elem|
156
161
  parser = Parser.new
157
162
  expressions = parser.tokenize( elem[:string] )
158
- assert !parser.errors?, "Query: #{elem.inspect}"
163
+ assert !parser.errors?, "Query: #{elem.inspect} #{parser.errors.inspect}"
159
164
  assert_equal elem[:operator], expressions.first[:operator]
160
165
  end
161
166
  end
@@ -286,31 +291,50 @@ class ParserCompatabilityTest < Test::Unit::TestCase
286
291
  assert_nil ex
287
292
  end
288
293
  end
294
+
295
+ test "mulitples shouldn't restrict based on string size(OMG LOL THAT WAS FUNNYWTF)" do
296
+ parser = Parser.new
297
+ ex = parser.tokenize("ListAgentId Eq '20110000000000000000000000'")
298
+ assert !parser.errors?, parser.inspect
299
+ end
289
300
 
290
301
  test "max out values" do
291
- parser = Parser.new
292
- to_the_max = []
293
- 35.times do |x|
294
- to_the_max << x
295
- end
296
- ex = parser.tokenize("City Eq #{to_the_max.join(',')}")
297
- vals = ex.first[:value]
298
- assert_equal 25, vals.size
302
+ parser = Parser.new
303
+ to_the_max = []
304
+ 210.times do |x|
305
+ to_the_max << x
306
+ end
307
+ ex = parser.tokenize("City Eq #{to_the_max.join(',')}")
308
+ vals = ex.first[:value]
309
+ assert_equal 200, vals.size
310
+ assert parser.errors?
299
311
  end
300
312
 
301
313
  test "max out expressions" do
302
- parser = Parser.new
303
- to_the_max = []
304
- 60.times do |x|
305
- to_the_max << "City Eq 'Fargo'"
306
- end
307
- vals = parser.tokenize(to_the_max.join(" And "))
308
- assert_equal 50, vals.size
314
+ parser = Parser.new
315
+ to_the_max = []
316
+ 60.times do |x|
317
+ to_the_max << "City Eq 'Fargo'"
318
+ end
319
+ vals = parser.tokenize(to_the_max.join(" And "))
320
+ assert_equal 50, vals.size
321
+ assert parser.errors?
322
+ end
323
+
324
+ test "max out function args" do
325
+ parser = Parser.new
326
+ to_the_max = []
327
+ 201.times do |x|
328
+ to_the_max << "1"
329
+ end
330
+ vals = parser.tokenize("Args Eq myfunc(#{to_the_max.join(",")})")
331
+ assert parser.errors?
332
+ assert parser.errors.first.constraint?
309
333
  end
310
334
 
311
335
  test "API-107 And/Or in string spiel" do
312
336
  search_strings = ['Tom And Jerry', 'Tom Or Jerry', 'And Or Eq', 'City Eq \\\'Fargo\\\'',
313
- ' And Eq Or ', 'Or And Or']
337
+ ' And Eq Or ', 'Or And Not']
314
338
  search_strings.each do |s|
315
339
  parser = Parser.new
316
340
  parser.tokenize("City Eq '#{s}' And PropertyType Eq 'A'")
@@ -433,5 +457,52 @@ class ParserCompatabilityTest < Test::Unit::TestCase
433
457
  expressions = parser.tokenize( "BooleanField Eq true" )
434
458
  assert_equal true, parser.escape_value(expressions.first)
435
459
  end
460
+
461
+ test "Between" do
462
+ ["BathsFull Bt 10,20", "DateField Bt 2012-12-31,2013-01-31"].each do |f|
463
+ parser = Parser.new
464
+ expressions = parser.tokenize f
465
+ assert !parser.errors?, "should successfully parse proper between values, but #{parser.errors.first}"
466
+ end
467
+
468
+ # truckload of fail
469
+ ["BathsFull Bt 2012-12-31,1", "DateField Bt 10,2012-12-31"].each do |f|
470
+ parser = Parser.new
471
+ expressions = parser.tokenize f
472
+ assert parser.errors?, "should have a type mismatch: #{parser.errors.first}"
473
+ assert_match /Type mismatch/, parser.errors.first.message
474
+ end
475
+
476
+ end
477
+
478
+ test "integer type coercion" do
479
+ parser = Parser.new
480
+ expression = parser.tokenize( "DecimalField Eq 100").first
481
+ assert parser.send(:check_type!, expression, :decimal)
482
+ assert_equal 100.0, parser.escape_value(expression)
483
+ end
484
+
485
+ test "datetime->date type coercion" do
486
+ t = Time.now
487
+ parser = Parser.new
488
+ expression = parser.tokenize( "DateField Eq now()").first
489
+ assert !parser.errors?
490
+ assert parser.send(:check_type!, expression, :date)
491
+ assert_equal t.strftime(Sparkql::FunctionResolver::STRFTIME_FORMAT),
492
+ parser.escape_value(expression).strftime(Sparkql::FunctionResolver::STRFTIME_FORMAT)
493
+ end
494
+
495
+ test "datetime->date type coercion array" do
496
+ today = Time.now
497
+ parser = Parser.new
498
+ expression = parser.tokenize('"Custom"."DateField" Bt days(-1),now()').first
499
+ assert !parser.errors?
500
+ assert parser.send(:check_type!, expression, :date)
501
+ yesterday = today - 3600 * 24
502
+ assert_equal [ yesterday.strftime(Sparkql::FunctionResolver::STRFTIME_FORMAT),
503
+ today.strftime(Sparkql::FunctionResolver::STRFTIME_FORMAT)],
504
+ parser.escape_value(expression).map { |i| i.strftime(Sparkql::FunctionResolver::STRFTIME_FORMAT)}
505
+ end
506
+
436
507
 
437
508
  end