ibm_db 2.5.6-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/CHANGES +181 -0
  2. data/LICENSE +18 -0
  3. data/MANIFEST +14 -0
  4. data/ParameterizedQueries README +39 -0
  5. data/README +282 -0
  6. data/ext/Makefile.nt32 +181 -0
  7. data/ext/extconf.rb +66 -0
  8. data/ext/ibm_db.c +11166 -0
  9. data/ext/ruby_ibm_db.h +236 -0
  10. data/ext/ruby_ibm_db_cli.c +738 -0
  11. data/ext/ruby_ibm_db_cli.h +431 -0
  12. data/init.rb +42 -0
  13. data/lib/IBM_DB.rb +2 -0
  14. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +2598 -0
  15. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1965 -0
  16. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -0
  17. data/lib/mswin32/ibm_db.rb +1 -0
  18. data/lib/mswin32/rb18x/ibm_db.so +0 -0
  19. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  20. data/test/cases/adapter_test.rb +202 -0
  21. data/test/cases/associations/belongs_to_associations_test.rb +486 -0
  22. data/test/cases/associations/cascaded_eager_loading_test.rb +183 -0
  23. data/test/cases/associations/eager_test.rb +862 -0
  24. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +917 -0
  25. data/test/cases/associations/has_many_through_associations_test.rb +461 -0
  26. data/test/cases/associations/join_model_test.rb +793 -0
  27. data/test/cases/attribute_methods_test.rb +621 -0
  28. data/test/cases/base_test.rb +1486 -0
  29. data/test/cases/calculations_test.rb +362 -0
  30. data/test/cases/finder_test.rb +1088 -0
  31. data/test/cases/fixtures_test.rb +684 -0
  32. data/test/cases/migration_test.rb +2014 -0
  33. data/test/cases/schema_dumper_test.rb +232 -0
  34. data/test/cases/validations/uniqueness_validation_test.rb +283 -0
  35. data/test/connections/native_ibm_db/connection.rb +42 -0
  36. data/test/ibm_db_test.rb +25 -0
  37. data/test/models/warehouse_thing.rb +5 -0
  38. data/test/schema/i5/ibm_db_specific_schema.rb +135 -0
  39. data/test/schema/ids/ibm_db_specific_schema.rb +138 -0
  40. data/test/schema/luw/ibm_db_specific_schema.rb +135 -0
  41. data/test/schema/schema.rb +647 -0
  42. data/test/schema/zOS/ibm_db_specific_schema.rb +206 -0
  43. metadata +107 -0
@@ -0,0 +1,232 @@
1
+ require "cases/helper"
2
+ require 'stringio'
3
+
4
+
5
+ class SchemaDumperTest < ActiveRecord::TestCase
6
+ def standard_dump
7
+ stream = StringIO.new
8
+ ActiveRecord::SchemaDumper.ignore_tables = []
9
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
10
+ stream.string
11
+ end
12
+
13
+ def test_schema_dump
14
+ output = standard_dump
15
+ assert_match %r{create_table "accounts"}, output
16
+ assert_match %r{create_table "authors"}, output
17
+ assert_no_match %r{create_table "schema_migrations"}, output
18
+ end
19
+
20
+ def test_schema_dump_excludes_sqlite_sequence
21
+ output = standard_dump
22
+ assert_no_match %r{create_table "sqlite_sequence"}, output
23
+ end
24
+
25
+ unless current_adapter?(:IBM_DBAdapter) #DB2 is case insensitive
26
+ def test_schema_dump_includes_camelcase_table_name
27
+ output = standard_dump
28
+ assert_match %r{create_table "CamelCase"}, output
29
+ end
30
+ end
31
+
32
+ def assert_line_up(lines, pattern, required = false)
33
+ return assert(true) if lines.empty?
34
+ matches = lines.map { |line| line.match(pattern) }
35
+ assert matches.all? if required
36
+ matches.compact!
37
+ return assert(true) if matches.empty?
38
+ assert_equal 1, matches.map{ |match| match.offset(0).first }.uniq.length
39
+ end
40
+
41
+ def column_definition_lines(output = standard_dump)
42
+ output.scan(/^( *)create_table.*?\n(.*?)^\1end/m).map{ |m| m.last.split(/\n/) }
43
+ end
44
+
45
+ def test_types_line_up
46
+ column_definition_lines.each do |column_set|
47
+ next if column_set.empty?
48
+
49
+ lengths = column_set.map do |column|
50
+ if match = column.match(/t\.(?:integer|decimal|float|datetime|timestamp|time|date|text|binary|string|boolean)\s+"/)
51
+ match[0].length
52
+ end
53
+ end
54
+
55
+ assert_equal 1, lengths.uniq.length
56
+ end
57
+ end
58
+
59
+ def test_arguments_line_up
60
+ column_definition_lines.each do |column_set|
61
+ assert_line_up(column_set, /:default => /)
62
+ assert_line_up(column_set, /:limit => /)
63
+ assert_line_up(column_set, /:null => /)
64
+ end
65
+ end
66
+
67
+ def test_no_dump_errors
68
+ output = standard_dump
69
+ assert_no_match %r{\# Could not dump table}, output
70
+ end
71
+
72
+ def test_schema_dump_includes_not_null_columns
73
+ stream = StringIO.new
74
+
75
+ ActiveRecord::SchemaDumper.ignore_tables = [/^[^r]/]
76
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
77
+ output = stream.string
78
+ assert_match %r{:null => false}, output
79
+ end
80
+
81
+ def test_schema_dump_includes_limit_constraint_for_integer_columns
82
+ stream = StringIO.new
83
+
84
+ ActiveRecord::SchemaDumper.ignore_tables = [/^(?!integer_limits)/]
85
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
86
+ output = stream.string
87
+
88
+ if current_adapter?(:PostgreSQLAdapter)
89
+ assert_match %r{c_int_1.*:limit => 2}, output
90
+ assert_match %r{c_int_2.*:limit => 2}, output
91
+
92
+ # int 3 is 4 bytes in postgresql
93
+ assert_match %r{c_int_3.*}, output
94
+ assert_no_match %r{c_int_3.*:limit}, output
95
+
96
+ assert_match %r{c_int_4.*}, output
97
+ assert_no_match %r{c_int_4.*:limit}, output
98
+ elsif current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
99
+ assert_match %r{c_int_1.*:limit => 1}, output
100
+ assert_match %r{c_int_2.*:limit => 2}, output
101
+ assert_match %r{c_int_3.*:limit => 3}, output
102
+
103
+ assert_match %r{c_int_4.*}, output
104
+ assert_no_match %r{c_int_4.*:limit}, output
105
+ elsif current_adapter?(:SQLiteAdapter)
106
+ assert_match %r{c_int_1.*:limit => 1}, output
107
+ assert_match %r{c_int_2.*:limit => 2}, output
108
+ assert_match %r{c_int_3.*:limit => 3}, output
109
+ assert_match %r{c_int_4.*:limit => 4}, output
110
+ end
111
+ assert_match %r{c_int_without_limit.*}, output
112
+ assert_no_match %r{c_int_without_limit.*:limit}, output
113
+
114
+ if current_adapter?(:SQLiteAdapter)
115
+ assert_match %r{c_int_5.*:limit => 5}, output
116
+ assert_match %r{c_int_6.*:limit => 6}, output
117
+ assert_match %r{c_int_7.*:limit => 7}, output
118
+ assert_match %r{c_int_8.*:limit => 8}, output
119
+ elsif current_adapter?(:OracleAdapter)
120
+ assert_match %r{c_int_5.*:limit => 5}, output
121
+ assert_match %r{c_int_6.*:limit => 6}, output
122
+ assert_match %r{c_int_7.*:limit => 7}, output
123
+ assert_match %r{c_int_8.*:limit => 8}, output
124
+ else
125
+ unless current_adapter?(:IBM_DBAdapter) #IBM data servers do not support limits on integer datatype
126
+ assert_match %r{c_int_5.*:limit => 8}, output
127
+ assert_match %r{c_int_6.*:limit => 8}, output
128
+ assert_match %r{c_int_7.*:limit => 8}, output
129
+ assert_match %r{c_int_8.*:limit => 8}, output
130
+ end
131
+ end
132
+ end
133
+
134
+ def test_schema_dump_with_string_ignored_table
135
+ stream = StringIO.new
136
+
137
+ ActiveRecord::SchemaDumper.ignore_tables = ['accounts']
138
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
139
+ output = stream.string
140
+ assert_no_match %r{create_table "accounts"}, output
141
+ assert_match %r{create_table "authors"}, output
142
+ assert_no_match %r{create_table "schema_migrations"}, output
143
+ end
144
+
145
+ def test_schema_dump_with_regexp_ignored_table
146
+ stream = StringIO.new
147
+
148
+ ActiveRecord::SchemaDumper.ignore_tables = [/^account/]
149
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
150
+ output = stream.string
151
+ assert_no_match %r{create_table "accounts"}, output
152
+ assert_match %r{create_table "authors"}, output
153
+ assert_no_match %r{create_table "schema_migrations"}, output
154
+ end
155
+
156
+ def test_schema_dump_illegal_ignored_table_value
157
+ stream = StringIO.new
158
+ ActiveRecord::SchemaDumper.ignore_tables = [5]
159
+ assert_raise(StandardError) do
160
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
161
+ end
162
+ end
163
+
164
+ def test_schema_dumps_index_columns_in_right_order
165
+ index_definition = standard_dump.split(/\n/).grep(/add_index.*companies/).first.strip
166
+ assert_equal 'add_index "companies", ["firm_id", "type", "rating", "ruby_type"], :name => "company_index"', index_definition
167
+ end
168
+
169
+ def test_schema_dump_should_honor_nonstandard_primary_keys
170
+ output = standard_dump
171
+ match = output.match(%r{create_table "movies"(.*)do})
172
+ assert_not_nil(match, "nonstandardpk table not found")
173
+ assert_match %r(:primary_key => "movieid"), match[1], "non-standard primary key not preserved"
174
+ end
175
+
176
+ if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
177
+ def test_schema_dump_should_not_add_default_value_for_mysql_text_field
178
+ output = standard_dump
179
+ assert_match %r{t.text\s+"body",\s+:null => false$}, output
180
+ end
181
+
182
+ def test_schema_dump_includes_length_for_mysql_blob_and_text_fields
183
+ output = standard_dump
184
+ assert_match %r{t.binary\s+"tiny_blob",\s+:limit => 255$}, output
185
+ assert_match %r{t.binary\s+"normal_blob"$}, output
186
+ assert_match %r{t.binary\s+"medium_blob",\s+:limit => 16777215$}, output
187
+ assert_match %r{t.binary\s+"long_blob",\s+:limit => 2147483647$}, output
188
+ assert_match %r{t.text\s+"tiny_text",\s+:limit => 255$}, output
189
+ assert_match %r{t.text\s+"normal_text"$}, output
190
+ assert_match %r{t.text\s+"medium_text",\s+:limit => 16777215$}, output
191
+ assert_match %r{t.text\s+"long_text",\s+:limit => 2147483647$}, output
192
+ end
193
+ end
194
+
195
+ def test_schema_dump_includes_decimal_options
196
+ stream = StringIO.new
197
+ ActiveRecord::SchemaDumper.ignore_tables = [/^[^n]/]
198
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
199
+ output = stream.string
200
+ assert_match %r{:precision => 3,[[:space:]]+:scale => 2,[[:space:]]+:default => 2.78}, output
201
+ end
202
+
203
+ if current_adapter?(:PostgreSQLAdapter)
204
+ def test_schema_dump_includes_xml_shorthand_definition
205
+ output = standard_dump
206
+ if %r{create_table "postgresql_xml_data_type"} =~ output
207
+ assert_match %r{t.xml "data"}, output
208
+ end
209
+ end
210
+ end
211
+
212
+ def test_schema_dump_keeps_large_precision_integer_columns_as_decimal
213
+ output = standard_dump
214
+ # Oracle supports precision up to 38 and it identifies decimals with scale 0 as integers
215
+ if current_adapter?(:OracleAdapter)
216
+ assert_match %r{t.integer\s+"atoms_in_universe",\s+:precision => 38,\s+:scale => 0}, output
217
+ elsif current_adapter?(:IBM_DBAdapter)
218
+ assert_match %r{t.integer\s+"atoms_in_universe",\s+:precision => 31,\s+:scale => 0}, output
219
+ else
220
+ assert_match %r{t.decimal\s+"atoms_in_universe",\s+:precision => 55,\s+:scale => 0}, output
221
+ end
222
+ end
223
+
224
+ def test_schema_dump_keeps_id_column_when_id_is_false_and_id_column_added
225
+ output = standard_dump
226
+ match = output.match(%r{create_table "goofy_string_id"(.*)do.*\n(.*)\n})
227
+ assert_not_nil(match, "goofy_string_id table not found")
228
+ assert_match %r(:id => false), match[1], "no table id not preserved"
229
+ assert_match %r{t.string[[:space:]]+"id",[[:space:]]+:null => false$}, match[2], "non-primary key id column not preserved"
230
+ end
231
+ end
232
+
@@ -0,0 +1,283 @@
1
+ # encoding: utf-8
2
+ require "cases/helper"
3
+ require 'models/topic'
4
+ require 'models/reply'
5
+ require 'models/warehouse_thing'
6
+ require 'models/guid'
7
+ require 'models/event'
8
+
9
+ # The following methods in Topic are used in test_conditional_validation_*
10
+ class Topic
11
+ has_many :unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
12
+ has_many :silly_unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
13
+ end
14
+
15
+ class UniqueReply < Reply
16
+ validates_uniqueness_of :content, :scope => 'parent_id'
17
+ end
18
+
19
+ class SillyUniqueReply < UniqueReply
20
+ end
21
+
22
+ class Wizard < ActiveRecord::Base
23
+ self.abstract_class = true
24
+
25
+ validates_uniqueness_of :name
26
+ end
27
+
28
+ class IneptWizard < Wizard
29
+ validates_uniqueness_of :city
30
+ end
31
+
32
+ class Conjurer < IneptWizard
33
+ end
34
+
35
+ class Thaumaturgist < IneptWizard
36
+ end
37
+
38
+ class UniquenessValidationTest < ActiveRecord::TestCase
39
+ fixtures :topics, :warehouse_things, :developers
40
+
41
+ repair_validations(Topic, Reply)
42
+
43
+ def test_validate_uniqueness
44
+ Topic.validates_uniqueness_of(:title)
45
+
46
+ t = Topic.new("title" => "I'm uniqué!")
47
+ assert t.save, "Should save t as unique"
48
+
49
+ t.content = "Remaining unique"
50
+ assert t.save, "Should still save t as unique"
51
+
52
+ t2 = Topic.new("title" => "I'm uniqué!")
53
+ assert !t2.valid?, "Shouldn't be valid"
54
+ assert !t2.save, "Shouldn't save t2 as unique"
55
+ assert_equal ["has already been taken"], t2.errors[:title]
56
+
57
+ t2.title = "Now Im really also unique"
58
+ assert t2.save, "Should now save t2 as unique"
59
+ end
60
+
61
+ def test_validates_uniqueness_with_validates
62
+ Topic.validates :title, :uniqueness => true
63
+ t = Topic.create!('title' => 'abc')
64
+
65
+ t2 = Topic.new('title' => 'abc')
66
+ assert !t2.valid?
67
+ assert t2.errors[:title]
68
+ end
69
+
70
+ def test_validates_uniqueness_with_newline_chars
71
+ Topic.validates_uniqueness_of(:title, :case_sensitive => false)
72
+
73
+ t = Topic.new("title" => "new\nline")
74
+ assert t.save, "Should save t as unique"
75
+ end
76
+
77
+ def test_validate_uniqueness_with_scope
78
+ Reply.validates_uniqueness_of(:content, :scope => "parent_id")
79
+
80
+ t = Topic.create("title" => "I'm unique!")
81
+
82
+ r1 = t.replies.create "title" => "r1", "content" => "hello world"
83
+ assert r1.valid?, "Saving r1"
84
+
85
+ r2 = t.replies.create "title" => "r2", "content" => "hello world"
86
+ assert !r2.valid?, "Saving r2 first time"
87
+
88
+ r2.content = "something else"
89
+ assert r2.save, "Saving r2 second time"
90
+
91
+ t2 = Topic.create("title" => "I'm unique too!")
92
+ r3 = t2.replies.create "title" => "r3", "content" => "hello world"
93
+ assert r3.valid?, "Saving r3"
94
+ end
95
+
96
+ def test_validate_uniqueness_scoped_to_defining_class
97
+ t = Topic.create("title" => "What, me worry?")
98
+
99
+ r1 = t.unique_replies.create "title" => "r1", "content" => "a barrel of fun"
100
+ assert r1.valid?, "Saving r1"
101
+
102
+ r2 = t.silly_unique_replies.create "title" => "r2", "content" => "a barrel of fun"
103
+ assert !r2.valid?, "Saving r2"
104
+
105
+ # Should succeed as validates_uniqueness_of only applies to
106
+ # UniqueReply and its subclasses
107
+ r3 = t.replies.create "title" => "r2", "content" => "a barrel of fun"
108
+ assert r3.valid?, "Saving r3"
109
+ end
110
+
111
+ def test_validate_uniqueness_with_scope_array
112
+ Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
113
+
114
+ t = Topic.create("title" => "The earth is actually flat!")
115
+
116
+ r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
117
+ assert r1.valid?, "Saving r1"
118
+
119
+ r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
120
+ assert !r2.valid?, "Saving r2. Double reply by same author."
121
+
122
+ r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
123
+ assert r2.save, "Saving r2 the second time."
124
+
125
+ r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
126
+ assert !r3.valid?, "Saving r3"
127
+
128
+ r3.author_name = "jj"
129
+ assert r3.save, "Saving r3 the second time."
130
+
131
+ r3.author_name = "jeremy"
132
+ assert !r3.save, "Saving r3 the third time."
133
+ end
134
+
135
+ def test_validate_case_insensitive_uniqueness
136
+ Topic.validates_uniqueness_of(:title, :parent_id, :case_sensitive => false, :allow_nil => true)
137
+
138
+ t = Topic.new("title" => "I'm unique!", :parent_id => 2)
139
+ assert t.save, "Should save t as unique"
140
+
141
+ t.content = "Remaining unique"
142
+ assert t.save, "Should still save t as unique"
143
+
144
+ t2 = Topic.new("title" => "I'm UNIQUE!", :parent_id => 1)
145
+ assert !t2.valid?, "Shouldn't be valid"
146
+ assert !t2.save, "Shouldn't save t2 as unique"
147
+ assert t2.errors[:title].any?
148
+ assert t2.errors[:parent_id].any?
149
+ assert_equal ["has already been taken"], t2.errors[:title]
150
+
151
+ t2.title = "I'm truly UNIQUE!"
152
+ assert !t2.valid?, "Shouldn't be valid"
153
+ assert !t2.save, "Shouldn't save t2 as unique"
154
+ assert t2.errors[:title].empty?
155
+ assert t2.errors[:parent_id].any?
156
+
157
+ t2.parent_id = 4
158
+ assert t2.save, "Should now save t2 as unique"
159
+
160
+ t2.parent_id = nil
161
+ t2.title = nil
162
+ assert t2.valid?, "should validate with nil"
163
+ assert t2.save, "should save with nil"
164
+
165
+ with_kcode('UTF8') do
166
+ t_utf8 = Topic.new("title" => "Я тоже уникальный!")
167
+ assert t_utf8.save, "Should save t_utf8 as unique"
168
+
169
+ # If database hasn't UTF-8 character set, this test fails
170
+ if Topic.find(t_utf8, :select => 'LOWER(title) AS title').title == "я тоже уникальный!"
171
+ t2_utf8 = Topic.new("title" => "я тоже УНИКАЛЬНЫЙ!")
172
+ assert !t2_utf8.valid?, "Shouldn't be valid"
173
+ assert !t2_utf8.save, "Shouldn't save t2_utf8 as unique"
174
+ end
175
+ end
176
+ end
177
+
178
+ def test_validate_case_sensitive_uniqueness
179
+ Topic.validates_uniqueness_of(:title, :case_sensitive => true, :allow_nil => true)
180
+
181
+ t = Topic.new("title" => "I'm unique!")
182
+ assert t.save, "Should save t as unique"
183
+
184
+ t.content = "Remaining unique"
185
+ assert t.save, "Should still save t as unique"
186
+
187
+ t2 = Topic.new("title" => "I'M UNIQUE!")
188
+ assert t2.valid?, "Should be valid"
189
+ assert t2.save, "Should save t2 as unique"
190
+ assert t2.errors[:title].empty?
191
+ assert t2.errors[:parent_id].empty?
192
+ assert_not_equal ["has already been taken"], t2.errors[:title]
193
+
194
+ t3 = Topic.new("title" => "I'M uNiQUe!")
195
+ assert t3.valid?, "Should be valid"
196
+ assert t3.save, "Should save t2 as unique"
197
+ assert t3.errors[:title].empty?
198
+ assert t3.errors[:parent_id].empty?
199
+ assert_not_equal ["has already been taken"], t3.errors[:title]
200
+ end
201
+
202
+ def test_validate_case_sensitive_uniqueness_with_attribute_passed_as_integer
203
+ Topic.validates_uniqueness_of(:title, :case_sensitve => true)
204
+ t = Topic.create!('title' => 101)
205
+
206
+ t2 = Topic.new('title' => 101)
207
+ assert !t2.valid?
208
+ assert t2.errors[:title]
209
+ end
210
+
211
+ def test_validate_uniqueness_with_non_standard_table_names
212
+ i1 = WarehouseThing.create(:value => 1000)
213
+ assert !i1.valid?, "i1 should not be valid"
214
+ assert i1.errors[:value].any?, "Should not be empty"
215
+ end
216
+
217
+ def test_validates_uniqueness_inside_with_scope
218
+ Topic.validates_uniqueness_of(:title)
219
+
220
+ Topic.send(:with_scope, :find => { :conditions => { :author_name => "David" } }) do
221
+ t1 = Topic.new("title" => "I'm unique!", "author_name" => "Mary")
222
+ assert t1.save
223
+ t2 = Topic.new("title" => "I'm unique!", "author_name" => "David")
224
+ assert !t2.valid?
225
+ end
226
+ end
227
+
228
+ def test_validate_uniqueness_with_columns_which_are_sql_keywords
229
+ repair_validations(Guid) do
230
+ Guid.validates_uniqueness_of :key
231
+ g = Guid.new
232
+ g.key = "foo"
233
+ assert_nothing_raised { !g.valid? }
234
+ end
235
+ end
236
+
237
+ def test_validate_uniqueness_with_limit
238
+ # Event.title is limited to 5 characters
239
+ e1 = Event.create(:title => "abcde")
240
+ assert e1.valid?, "Could not create an event with a unique, 5 character title"
241
+ e2 = Event.create(:title => "abcdefgh")
242
+ assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique"
243
+ end
244
+
245
+ def test_validate_uniqueness_with_limit_and_utf8
246
+ with_kcode('UTF8') do
247
+ # Event.title is limited to 5 characters
248
+ e1 = Event.create(:title => "一二三四五")
249
+ assert e1.valid?, "Could not create an event with a unique, 5 character title"
250
+ e2 = Event.create(:title => "一二三四五六七八")
251
+ assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique"
252
+ end
253
+ end
254
+
255
+ def test_validate_straight_inheritance_uniqueness
256
+ w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork")
257
+ assert w1.valid?, "Saving w1"
258
+
259
+ # Should use validation from base class (which is abstract)
260
+ w2 = IneptWizard.new(:name => "Rincewind", :city => "Quirm")
261
+ assert !w2.valid?, "w2 shouldn't be valid"
262
+ assert w2.errors[:name].any?, "Should have errors for name"
263
+ assert_equal ["has already been taken"], w2.errors[:name], "Should have uniqueness message for name"
264
+
265
+ w3 = Conjurer.new(:name => "Rincewind", :city => "Quirm")
266
+ assert !w3.valid?, "w3 shouldn't be valid"
267
+ assert w3.errors[:name].any?, "Should have errors for name"
268
+ assert_equal ["has already been taken"], w3.errors[:name], "Should have uniqueness message for name"
269
+
270
+ w4 = Conjurer.create(:name => "The Amazing Bonko", :city => "Quirm")
271
+ assert w4.valid?, "Saving w4"
272
+
273
+ w5 = Thaumaturgist.new(:name => "The Amazing Bonko", :city => "Lancre")
274
+ assert !w5.valid?, "w5 shouldn't be valid"
275
+ assert w5.errors[:name].any?, "Should have errors for name"
276
+ assert_equal ["has already been taken"], w5.errors[:name], "Should have uniqueness message for name"
277
+
278
+ w6 = Thaumaturgist.new(:name => "Mustrum Ridcully", :city => "Quirm")
279
+ assert !w6.valid?, "w6 shouldn't be valid"
280
+ assert w6.errors[:city].any?, "Should have errors for city"
281
+ assert_equal ["has already been taken"], w6.errors[:city], "Should have uniqueness message for city"
282
+ end
283
+ end