Report abuse

Here's an activerecord test that not passing:

validations_test.rb -- activerecord (ruby)

  def test_validates_length_of_using_maximum_utf8
    with_kcode('UTF8') do
      Topic.validates_length_of :title, :maximum => 5

      t = Topic.create("title" => "一二三四五", "content" => "whatever")
      assert t.valid?

      t.title = "一二34五六"
      assert !t.valid?
      assert t.errors.on(:title)
      assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
    end
  end

output

  5) Failure:
test_validates_length_of_using_maximum_utf8(ValidationsTest)
    [test/cases/validations_test.rb:1004:in `test_validates_length_of_using_maximum_utf8'
     test/cases/validations_test.rb:1442:in `with_kcode'
     test/cases/validations_test.rb:1000:in `test_validates_length_of_using_maximum_utf8'
     ./test/cases/../../../activesupport/lib/active_support/testing/setup_and_teardown.rb:57:in `run']:
<false> is not true.

The error happens on this statement: assert t.valid?

ar_utf8.rb (ruby)

# this is a plain program that should duplicate the same error
# but it doesn't -- everything works correctly.

require 'rubygems'
require 'activerecord'

def with_kcode(kcode)
  if RUBY_VERSION < '1.9'
    orig_kcode, $KCODE = $KCODE, kcode
    begin
      yield
    ensure
      $KCODE = orig_kcode
    end
  else
    yield
  end
end

@logger = Logger.new $stderr
ActiveRecord::Base.logger = @logger
ActiveRecord::Base.colorize_logging = false

# GRANT ALL PRIVILEGES ON my_activerecord_test.* to 'rails'@'localhost';

pool = ActiveRecord::Base.establish_connection(
  :adapter  => RUBY_PLATFORM =~ /java/ ? 'jdbcmysql' : 'mysql',
  :username => 'rails',
  :encoding => 'utf8',
  :database => 'my_activerecord_test'
)

ActiveRecord::Schema.define do
  drop_table :posts if pool.connection.table_exists?(:posts)
  create_table :posts do |t|
    t.string :subject
    t.text :body
  end
end
  
class Post < ActiveRecord::Base
  validates_length_of :subject, :maximum => 5
end

with_kcode('UTF8') do
  p1 = Post.create(:subject => "一二三四五", :body => 'this is the body')

  len1 = p1.subject.length
  len2 = p1.subject.mb_chars.length

  puts "length: #{len1}, #{len2}"

  puts p1.valid?
  puts p1.errors.on(:subject)

  p2 = Post.find(:first)

  p2.subject = "一二34五六"

  puts p2.valid?
  puts p2.errors.on(:subject)
end

output

$ jruby ar_utf8.rb 
SQL (1.3ms)  SET SQL_AUTO_IS_NULL=0
-- drop_table(:posts)
SQL (2.5ms)  DROP TABLE `posts`
   -> 0.0037s
   -> 0 rows
-- create_table(:posts)
SQL (2.2ms)  CREATE TABLE `posts` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `subject` varchar(255), `body` text) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin
   -> 0.0072s
   -> 0 rows
SQL (2.1ms)  INSERT INTO `posts` (`subject`, `body`) VALUES('一二三四五', 'this is the body')
length: 15, 5
true
nil
Post Load (1.6ms)  SELECT * FROM `posts` LIMIT 1
false
is too long (maximum is 5 characters)