sparkql 0.1.8 → 0.3.2

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