From bb75d68fe2262199a16973c09a8b2749542c7590 Mon Sep 17 00:00:00 2001
From: Ryuta Kamizono <kamipo@gmail.com>
Date: Sat, 12 Jan 2019 07:44:27 +0900
Subject: More exercise test cases for `not_between`

And support endless ranges for `not_between` like as `between`.

Follow up #34906.
---
 activerecord/lib/arel/predications.rb              |   4 +-
 .../test/cases/arel/attributes/attribute_test.rb   | 111 +++++++++++++++------
 2 files changed, 84 insertions(+), 31 deletions(-)

diff --git a/activerecord/lib/arel/predications.rb b/activerecord/lib/arel/predications.rb
index 0c03e93138..2a62c53aa3 100644
--- a/activerecord/lib/arel/predications.rb
+++ b/activerecord/lib/arel/predications.rb
@@ -82,14 +82,14 @@ Passing a range to `#in` is deprecated. Call `#between`, instead.
 
     def not_between(other)
       if infinity?(other.begin)
-        if infinity?(other.end)
+        if other.end.nil? || infinity?(other.end)
           self.in([])
         elsif other.exclude_end?
           gteq(other.end)
         else
           gt(other.end)
         end
-      elsif infinity?(other.end)
+      elsif other.end.nil? || infinity?(other.end)
         lt(other.begin)
       else
         left = lt(other.begin)
diff --git a/activerecord/test/cases/arel/attributes/attribute_test.rb b/activerecord/test/cases/arel/attributes/attribute_test.rb
index 6ad54ab5df..c7bd0a053b 100644
--- a/activerecord/test/cases/arel/attributes/attribute_test.rb
+++ b/activerecord/test/cases/arel/attributes/attribute_test.rb
@@ -560,7 +560,7 @@ module Arel
         end
       end
 
-      describe "with a range" do
+      describe "#between" do
         it "can be constructed with a standard range" do
           attribute = Attribute.new nil, nil
           node = attribute.between(1..3)
@@ -628,7 +628,6 @@ module Arel
           node.must_equal Nodes::NotIn.new(attribute, [])
         end
 
-
         it "can be constructed with a range ending at Infinity" do
           attribute = Attribute.new nil, nil
           node = attribute.between(0..::Float::INFINITY)
@@ -676,14 +675,6 @@ module Arel
             )
           ])
         end
-
-        def quoted_range(begin_val, end_val, exclude)
-          OpenStruct.new(
-            begin: Nodes::Quoted.new(begin_val),
-            end: Nodes::Quoted.new(end_val),
-            exclude_end?: exclude,
-          )
-        end
       end
 
       describe "#in" do
@@ -765,21 +756,23 @@ module Arel
         end
       end
 
-      describe "with a range" do
+      describe "#not_between" do
         it "can be constructed with a standard range" do
           attribute = Attribute.new nil, nil
           node = attribute.not_between(1..3)
 
-          node.must_equal Nodes::Grouping.new(Nodes::Or.new(
-                                                Nodes::LessThan.new(
-                                                  attribute,
-                                                  Nodes::Casted.new(1, attribute)
-                                                ),
-            Nodes::GreaterThan.new(
-              attribute,
-              Nodes::Casted.new(3, attribute)
+          node.must_equal Nodes::Grouping.new(
+            Nodes::Or.new(
+              Nodes::LessThan.new(
+                attribute,
+                Nodes::Casted.new(1, attribute)
+              ),
+              Nodes::GreaterThan.new(
+                attribute,
+                Nodes::Casted.new(3, attribute)
+              )
             )
-          ))
+          )
         end
 
         it "can be constructed with a range starting from -Infinity" do
@@ -792,6 +785,16 @@ module Arel
           )
         end
 
+        it "can be constructed with a quoted range starting from -Infinity" do
+          attribute = Attribute.new nil, nil
+          node = attribute.not_between(quoted_range(-::Float::INFINITY, 3, false))
+
+          node.must_equal Nodes::GreaterThan.new(
+            attribute,
+            Nodes::Quoted.new(3)
+          )
+        end
+
         it "can be constructed with an exclusive range starting from -Infinity" do
           attribute = Attribute.new nil, nil
           node = attribute.not_between(-::Float::INFINITY...3)
@@ -802,6 +805,16 @@ module Arel
           )
         end
 
+        it "can be constructed with a quoted exclusive range starting from -Infinity" do
+          attribute = Attribute.new nil, nil
+          node = attribute.not_between(quoted_range(-::Float::INFINITY, 3, true))
+
+          node.must_equal Nodes::GreaterThanOrEqual.new(
+            attribute,
+            Nodes::Quoted.new(3)
+          )
+        end
+
         it "can be constructed with an infinite range" do
           attribute = Attribute.new nil, nil
           node = attribute.not_between(-::Float::INFINITY..::Float::INFINITY)
@@ -809,6 +822,13 @@ module Arel
           node.must_equal Nodes::In.new(attribute, [])
         end
 
+        it "can be constructed with a quoted infinite range" do
+          attribute = Attribute.new nil, nil
+          node = attribute.not_between(quoted_range(-::Float::INFINITY, ::Float::INFINITY, false))
+
+          node.must_equal Nodes::In.new(attribute, [])
+        end
+
         it "can be constructed with a range ending at Infinity" do
           attribute = Attribute.new nil, nil
           node = attribute.not_between(0..::Float::INFINITY)
@@ -819,20 +839,44 @@ module Arel
           )
         end
 
+        if Gem::Version.new("2.6.0") <= Gem::Version.new(RUBY_VERSION)
+          it "can be constructed with a range implicitly ending at Infinity" do
+            attribute = Attribute.new nil, nil
+            node = attribute.not_between(eval("0..")) # Use eval for compatibility with Ruby < 2.6 parser
+
+            node.must_equal Nodes::LessThan.new(
+              attribute,
+              Nodes::Casted.new(0, attribute)
+            )
+          end
+        end
+
+        it "can be constructed with a quoted range ending at Infinity" do
+          attribute = Attribute.new nil, nil
+          node = attribute.not_between(quoted_range(0, ::Float::INFINITY, false))
+
+          node.must_equal Nodes::LessThan.new(
+            attribute,
+            Nodes::Quoted.new(0)
+          )
+        end
+
         it "can be constructed with an exclusive range" do
           attribute = Attribute.new nil, nil
           node = attribute.not_between(0...3)
 
-          node.must_equal Nodes::Grouping.new(Nodes::Or.new(
-                                                Nodes::LessThan.new(
-                                                  attribute,
-                                                  Nodes::Casted.new(0, attribute)
-                                                ),
-            Nodes::GreaterThanOrEqual.new(
-              attribute,
-              Nodes::Casted.new(3, attribute)
+          node.must_equal Nodes::Grouping.new(
+            Nodes::Or.new(
+              Nodes::LessThan.new(
+                attribute,
+                Nodes::Casted.new(0, attribute)
+              ),
+              Nodes::GreaterThanOrEqual.new(
+                attribute,
+                Nodes::Casted.new(3, attribute)
+              )
             )
-          ))
+          )
         end
       end
 
@@ -1022,6 +1066,15 @@ module Arel
           condition.to_sql.must_equal %("foo"."id" = (select 1))
         end
       end
+
+      private
+        def quoted_range(begin_val, end_val, exclude)
+          OpenStruct.new(
+            begin: Nodes::Quoted.new(begin_val),
+            end: Nodes::Quoted.new(end_val),
+            exclude_end?: exclude,
+          )
+        end
     end
   end
 end
-- 
cgit v1.2.3