# frozen_string_literal: true require "cases/helper" require "support/schema_dumping_helper" class PostgresqlByteaTest < ActiveRecord::PostgreSQLTestCase include SchemaDumpingHelper class ByteaDataType < ActiveRecord::Base self.table_name = "bytea_data_type" end def setup @connection = ActiveRecord::Base.connection begin @connection.transaction do @connection.create_table("bytea_data_type") do |t| t.binary "payload" t.binary "serialized" end end end @column = ByteaDataType.columns_hash["payload"] @type = ByteaDataType.type_for_attribute("payload") end teardown do @connection.drop_table "bytea_data_type", if_exists: true end def test_column assert @column.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQLColumn) assert_equal :binary, @column.type end def test_binary_columns_are_limitless_the_upper_limit_is_one_GB assert_equal "bytea", @connection.type_to_sql(:binary, limit: 100_000) assert_raise ArgumentError do @connection.type_to_sql(:binary, limit: 4294967295) end end def test_type_cast_binary_converts_the_encoding assert @column data = "\u001F\x8B" assert_equal("UTF-8", data.encoding.name) assert_equal("ASCII-8BIT", @type.deserialize(data).encoding.name) end def test_type_cast_binary_value data = (+"\u001F\x8B").force_encoding("BINARY") assert_equal(data, @type.deserialize(data)) end def test_type_case_nil assert_nil(@type.deserialize(nil)) end def test_read_value data = "\u001F" @connection.execute "insert into bytea_data_type (payload) VALUES ('#{data}')" record = ByteaDataType.first assert_equal(data, record.payload) record.delete end def test_read_nil_value @connection.execute "insert into bytea_data_type (payload) VALUES (null)" record = ByteaDataType.first assert_nil(record.payload) record.delete end def test_write_value data = "\u001F" record = ByteaDataType.create(payload: data) assert_not_predicate record, :new_record? assert_equal(data, record.payload) end def test_via_to_sql data = "'\u001F\\" ByteaDataType.create(payload: data) sql = ByteaDataType.where(payload: data).select(:payload).to_sql result = @connection.query(sql) assert_equal([[data]], result) end def test_via_to_sql_with_complicating_connection Thread.new do other_conn = ActiveRecord::Base.connection other_conn.execute("SET standard_conforming_strings = off") other_conn.execute("SET escape_string_warning = off") end.join test_via_to_sql end def test_write_binary data = File.read(File.join(__dir__, "..", "..", "..", "assets", "example.log")) assert(data.size > 1) record = ByteaDataType.create(payload: data) assert_not_predicate record, :new_record? assert_equal(data, record.payload) assert_equal(data, ByteaDataType.where(id: record.id).first.payload) end def test_write_nil record = ByteaDataType.create(payload: nil) assert_not_predicate record, :new_record? assert_nil(record.payload) assert_nil(ByteaDataType.where(id: record.id).first.payload) end class Serializer def load(str); str; end def dump(str); str; end end def test_serialize klass = Class.new(ByteaDataType) { serialize :serialized, Serializer.new } obj = klass.new obj.serialized = "hello world" obj.save! obj.reload assert_equal "hello world", obj.serialized end def test_schema_dumping output = dump_table_schema("bytea_data_type") assert_match %r{t\.binary\s+"payload"$}, output assert_match %r{t\.binary\s+"serialized"$}, output end end