diff options
Diffstat (limited to 'activerecord/test/cases/type')
-rw-r--r-- | activerecord/test/cases/type/adapter_specific_registry_test.rb | 133 | ||||
-rw-r--r-- | activerecord/test/cases/type/decimal_test.rb | 27 | ||||
-rw-r--r-- | activerecord/test/cases/type/integer_test.rb | 127 | ||||
-rw-r--r-- | activerecord/test/cases/type/string_test.rb | 10 | ||||
-rw-r--r-- | activerecord/test/cases/type/type_map_test.rb | 47 | ||||
-rw-r--r-- | activerecord/test/cases/type/unsigned_integer_test.rb | 17 |
6 files changed, 349 insertions, 12 deletions
diff --git a/activerecord/test/cases/type/adapter_specific_registry_test.rb b/activerecord/test/cases/type/adapter_specific_registry_test.rb new file mode 100644 index 0000000000..8b836b4793 --- /dev/null +++ b/activerecord/test/cases/type/adapter_specific_registry_test.rb @@ -0,0 +1,133 @@ +require "cases/helper" + +module ActiveRecord + class AdapterSpecificRegistryTest < ActiveRecord::TestCase + test "a class can be registered for a symbol" do + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, ::String) + registry.register(:bar, ::Array) + + assert_equal "", registry.lookup(:foo) + assert_equal [], registry.lookup(:bar) + end + + test "a block can be registered" do + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo) do |*args| + [*args, "block for foo"] + end + registry.register(:bar) do |*args| + [*args, "block for bar"] + end + + assert_equal [:foo, 1, "block for foo"], registry.lookup(:foo, 1) + assert_equal [:foo, 2, "block for foo"], registry.lookup(:foo, 2) + assert_equal [:bar, 1, 2, 3, "block for bar"], registry.lookup(:bar, 1, 2, 3) + end + + test "filtering by adapter" do + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, String, adapter: :sqlite3) + registry.register(:foo, Array, adapter: :postgresql) + + assert_equal "", registry.lookup(:foo, adapter: :sqlite3) + assert_equal [], registry.lookup(:foo, adapter: :postgresql) + end + + test "an error is raised if both a generic and adapter specific type match" do + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, String) + registry.register(:foo, Array, adapter: :postgresql) + + assert_raises TypeConflictError do + registry.lookup(:foo, adapter: :postgresql) + end + assert_equal "", registry.lookup(:foo, adapter: :sqlite3) + end + + test "a generic type can explicitly override an adapter specific type" do + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, String, override: true) + registry.register(:foo, Array, adapter: :postgresql) + + assert_equal "", registry.lookup(:foo, adapter: :postgresql) + assert_equal "", registry.lookup(:foo, adapter: :sqlite3) + end + + test "a generic type can explicitly allow an adapter type to be used instead" do + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, String, override: false) + registry.register(:foo, Array, adapter: :postgresql) + + assert_equal [], registry.lookup(:foo, adapter: :postgresql) + assert_equal "", registry.lookup(:foo, adapter: :sqlite3) + end + + test "a reasonable error is given when no type is found" do + registry = Type::AdapterSpecificRegistry.new + + e = assert_raises(ArgumentError) do + registry.lookup(:foo) + end + + assert_equal "Unknown type :foo", e.message + end + + test "construct args are passed to the type" do + type = Struct.new(:args) + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, type) + + assert_equal type.new, registry.lookup(:foo) + assert_equal type.new(:ordered_arg), registry.lookup(:foo, :ordered_arg) + assert_equal type.new(keyword: :arg), registry.lookup(:foo, keyword: :arg) + assert_equal type.new(keyword: :arg), registry.lookup(:foo, keyword: :arg, adapter: :postgresql) + end + + test "registering a modifier" do + decoration = Struct.new(:value) + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, String) + registry.register(:bar, Hash) + registry.add_modifier({ array: true }, decoration) + + assert_equal decoration.new(""), registry.lookup(:foo, array: true) + assert_equal decoration.new({}), registry.lookup(:bar, array: true) + assert_equal "", registry.lookup(:foo) + end + + test "registering multiple modifiers" do + decoration = Struct.new(:value) + other_decoration = Struct.new(:value) + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, String) + registry.add_modifier({ array: true }, decoration) + registry.add_modifier({ range: true }, other_decoration) + + assert_equal "", registry.lookup(:foo) + assert_equal decoration.new(""), registry.lookup(:foo, array: true) + assert_equal other_decoration.new(""), registry.lookup(:foo, range: true) + assert_equal( + decoration.new(other_decoration.new("")), + registry.lookup(:foo, array: true, range: true) + ) + end + + test "registering adapter specific modifiers" do + decoration = Struct.new(:value) + type = Struct.new(:args) + registry = Type::AdapterSpecificRegistry.new + registry.register(:foo, type) + registry.add_modifier({ array: true }, decoration, adapter: :postgresql) + + assert_equal( + decoration.new(type.new(keyword: :arg)), + registry.lookup(:foo, array: true, adapter: :postgresql, keyword: :arg) + ) + assert_equal( + type.new(array: true), + registry.lookup(:foo, array: true, adapter: :sqlite3) + ) + end + end +end diff --git a/activerecord/test/cases/type/decimal_test.rb b/activerecord/test/cases/type/decimal_test.rb index da30de373e..fe49d0e79a 100644 --- a/activerecord/test/cases/type/decimal_test.rb +++ b/activerecord/test/cases/type/decimal_test.rb @@ -5,24 +5,29 @@ module ActiveRecord class DecimalTest < ActiveRecord::TestCase def test_type_cast_decimal type = Decimal.new - assert_equal BigDecimal.new("0"), type.type_cast_from_user(BigDecimal.new("0")) - assert_equal BigDecimal.new("123"), type.type_cast_from_user(123.0) - assert_equal BigDecimal.new("1"), type.type_cast_from_user(:"1") + assert_equal BigDecimal.new("0"), type.cast(BigDecimal.new("0")) + assert_equal BigDecimal.new("123"), type.cast(123.0) + assert_equal BigDecimal.new("1"), type.cast(:"1") end def test_type_cast_decimal_from_float_with_large_precision type = Decimal.new(precision: ::Float::DIG + 2) - assert_equal BigDecimal.new("123.0"), type.type_cast_from_user(123.0) + assert_equal BigDecimal.new("123.0"), type.cast(123.0) + end + + def test_type_cast_from_float_with_unspecified_precision + type = Decimal.new + assert_equal 22.68.to_d, type.cast(22.68) end def test_type_cast_decimal_from_rational_with_precision type = Decimal.new(precision: 2) - assert_equal BigDecimal("0.33"), type.type_cast_from_user(Rational(1, 3)) + assert_equal BigDecimal("0.33"), type.cast(Rational(1, 3)) end def test_type_cast_decimal_from_rational_without_precision_defaults_to_18_36 type = Decimal.new - assert_equal BigDecimal("0.333333333333333333E0"), type.type_cast_from_user(Rational(1, 3)) + assert_equal BigDecimal("0.333333333333333333E0"), type.cast(Rational(1, 3)) end def test_type_cast_decimal_from_object_responding_to_d @@ -31,7 +36,15 @@ module ActiveRecord BigDecimal.new("1") end type = Decimal.new - assert_equal BigDecimal("1"), type.type_cast_from_user(value) + assert_equal BigDecimal("1"), type.cast(value) + end + + def test_changed? + type = Decimal.new + + assert type.changed?(5.0, 5.0, '5.0wibble') + assert_not type.changed?(5.0, 5.0, '5.0') + assert_not type.changed?(-5.0, -5.0, '-5.0') end end end diff --git a/activerecord/test/cases/type/integer_test.rb b/activerecord/test/cases/type/integer_test.rb new file mode 100644 index 0000000000..84fb05dd8e --- /dev/null +++ b/activerecord/test/cases/type/integer_test.rb @@ -0,0 +1,127 @@ +require "cases/helper" +require "models/company" + +module ActiveRecord + module Type + class IntegerTest < ActiveRecord::TestCase + test "simple values" do + type = Type::Integer.new + assert_equal 1, type.cast(1) + assert_equal 1, type.cast('1') + assert_equal 1, type.cast('1ignore') + assert_equal 0, type.cast('bad1') + assert_equal 0, type.cast('bad') + assert_equal 1, type.cast(1.7) + assert_equal 0, type.cast(false) + assert_equal 1, type.cast(true) + assert_nil type.cast(nil) + end + + test "random objects cast to nil" do + type = Type::Integer.new + assert_nil type.cast([1,2]) + assert_nil type.cast({1 => 2}) + assert_nil type.cast((1..2)) + end + + test "casting ActiveRecord models" do + type = Type::Integer.new + firm = Firm.create(:name => 'Apple') + assert_nil type.cast(firm) + end + + test "casting objects without to_i" do + type = Type::Integer.new + assert_nil type.cast(::Object.new) + end + + test "casting nan and infinity" do + type = Type::Integer.new + assert_nil type.cast(::Float::NAN) + assert_nil type.cast(1.0/0.0) + end + + test "casting booleans for database" do + type = Type::Integer.new + assert_equal 1, type.serialize(true) + assert_equal 0, type.serialize(false) + end + + test "changed?" do + type = Type::Integer.new + + assert type.changed?(5, 5, '5wibble') + assert_not type.changed?(5, 5, '5') + assert_not type.changed?(5, 5, '5.0') + assert_not type.changed?(-5, -5, '-5') + assert_not type.changed?(-5, -5, '-5.0') + assert_not type.changed?(nil, nil, nil) + end + + test "values below int min value are out of range" do + assert_raises(::RangeError) do + Integer.new.serialize(-2147483649) + end + end + + test "values above int max value are out of range" do + assert_raises(::RangeError) do + Integer.new.serialize(2147483648) + end + end + + test "very small numbers are out of range" do + assert_raises(::RangeError) do + Integer.new.serialize(-9999999999999999999999999999999) + end + end + + test "very large numbers are out of range" do + assert_raises(::RangeError) do + Integer.new.serialize(9999999999999999999999999999999) + end + end + + test "normal numbers are in range" do + type = Integer.new + assert_equal(0, type.serialize(0)) + assert_equal(-1, type.serialize(-1)) + assert_equal(1, type.serialize(1)) + end + + test "int max value is in range" do + assert_equal(2147483647, Integer.new.serialize(2147483647)) + end + + test "int min value is in range" do + assert_equal(-2147483648, Integer.new.serialize(-2147483648)) + end + + test "columns with a larger limit have larger ranges" do + type = Integer.new(limit: 8) + + assert_equal(9223372036854775807, type.serialize(9223372036854775807)) + assert_equal(-9223372036854775808, type.serialize(-9223372036854775808)) + assert_raises(::RangeError) do + type.serialize(-9999999999999999999999999999999) + end + assert_raises(::RangeError) do + type.serialize(9999999999999999999999999999999) + end + end + + test "values which are out of range can be re-assigned" do + klass = Class.new(ActiveRecord::Base) do + self.table_name = 'posts' + attribute :foo, :integer + end + model = klass.new + + model.foo = 2147483648 + model.foo = 1 + + assert_equal 1, model.foo + end + end + end +end diff --git a/activerecord/test/cases/type/string_test.rb b/activerecord/test/cases/type/string_test.rb index 420177ed49..56e9bf434d 100644 --- a/activerecord/test/cases/type/string_test.rb +++ b/activerecord/test/cases/type/string_test.rb @@ -4,16 +4,16 @@ module ActiveRecord class StringTypeTest < ActiveRecord::TestCase test "type casting" do type = Type::String.new - assert_equal "1", type.type_cast_from_user(true) - assert_equal "0", type.type_cast_from_user(false) - assert_equal "123", type.type_cast_from_user(123) + assert_equal "t", type.cast(true) + assert_equal "f", type.cast(false) + assert_equal "123", type.cast(123) end test "values are duped coming out" do s = "foo" type = Type::String.new - assert_not_same s, type.type_cast_from_user(s) - assert_not_same s, type.type_cast_from_database(s) + assert_not_same s, type.cast(s) + assert_not_same s, type.deserialize(s) end test "string mutations are detected" do diff --git a/activerecord/test/cases/type/type_map_test.rb b/activerecord/test/cases/type/type_map_test.rb index 4e32f92dd0..172c6dfc4c 100644 --- a/activerecord/test/cases/type/type_map_test.rb +++ b/activerecord/test/cases/type/type_map_test.rb @@ -124,6 +124,53 @@ module ActiveRecord assert_equal mapping.lookup(3), 'string' assert_kind_of Type::Value, mapping.lookup(4) end + + def test_fetch + mapping = TypeMap.new + mapping.register_type(1, "string") + + assert_equal "string", mapping.fetch(1) { "int" } + assert_equal "int", mapping.fetch(2) { "int" } + end + + def test_fetch_yields_args + mapping = TypeMap.new + + assert_equal "foo-1-2-3", mapping.fetch("foo", 1, 2, 3) { |*args| args.join("-") } + assert_equal "bar-1-2-3", mapping.fetch("bar", 1, 2, 3) { |*args| args.join("-") } + end + + def test_fetch_memoizes + mapping = TypeMap.new + + looked_up = false + mapping.register_type(1) do + fail if looked_up + looked_up = true + "string" + end + + assert_equal "string", mapping.fetch(1) + assert_equal "string", mapping.fetch(1) + end + + def test_fetch_memoizes_on_args + mapping = TypeMap.new + mapping.register_type("foo") { |*args| args.join("-") } + + assert_equal "foo-1-2-3", mapping.fetch("foo", 1, 2, 3) { |*args| args.join("-") } + assert_equal "foo-2-3-4", mapping.fetch("foo", 2, 3, 4) { |*args| args.join("-") } + end + + def test_register_clears_cache + mapping = TypeMap.new + + mapping.register_type(1, "string") + mapping.lookup(1) + mapping.register_type(1, "int") + + assert_equal "int", mapping.lookup(1) + end end end end diff --git a/activerecord/test/cases/type/unsigned_integer_test.rb b/activerecord/test/cases/type/unsigned_integer_test.rb new file mode 100644 index 0000000000..f2c910eade --- /dev/null +++ b/activerecord/test/cases/type/unsigned_integer_test.rb @@ -0,0 +1,17 @@ +require "cases/helper" + +module ActiveRecord + module Type + class UnsignedIntegerTest < ActiveRecord::TestCase + test "unsigned int max value is in range" do + assert_equal(4294967295, UnsignedInteger.new.serialize(4294967295)) + end + + test "minus value is out of range" do + assert_raises(::RangeError) do + UnsignedInteger.new.serialize(-1) + end + end + end + end +end |