activerecord_csi 2.3.5.p6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (333) hide show
  1. data/CHANGELOG +5858 -0
  2. data/README +351 -0
  3. data/RUNNING_UNIT_TESTS +36 -0
  4. data/Rakefile +270 -0
  5. data/examples/associations.png +0 -0
  6. data/examples/performance.rb +162 -0
  7. data/install.rb +30 -0
  8. data/lib/active_record/aggregations.rb +261 -0
  9. data/lib/active_record/association_preload.rb +389 -0
  10. data/lib/active_record/associations/association_collection.rb +475 -0
  11. data/lib/active_record/associations/association_proxy.rb +278 -0
  12. data/lib/active_record/associations/belongs_to_association.rb +76 -0
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +53 -0
  14. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
  15. data/lib/active_record/associations/has_many_association.rb +122 -0
  16. data/lib/active_record/associations/has_many_through_association.rb +266 -0
  17. data/lib/active_record/associations/has_one_association.rb +133 -0
  18. data/lib/active_record/associations/has_one_through_association.rb +37 -0
  19. data/lib/active_record/associations.rb +2241 -0
  20. data/lib/active_record/attribute_methods.rb +388 -0
  21. data/lib/active_record/autosave_association.rb +364 -0
  22. data/lib/active_record/base.rb +3171 -0
  23. data/lib/active_record/batches.rb +81 -0
  24. data/lib/active_record/calculations.rb +311 -0
  25. data/lib/active_record/callbacks.rb +360 -0
  26. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +371 -0
  27. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +139 -0
  28. data/lib/active_record/connection_adapters/abstract/database_statements.rb +289 -0
  29. data/lib/active_record/connection_adapters/abstract/query_cache.rb +94 -0
  30. data/lib/active_record/connection_adapters/abstract/quoting.rb +69 -0
  31. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +722 -0
  32. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +434 -0
  33. data/lib/active_record/connection_adapters/abstract_adapter.rb +241 -0
  34. data/lib/active_record/connection_adapters/mysql_adapter.rb +630 -0
  35. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1113 -0
  36. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
  37. data/lib/active_record/connection_adapters/sqlite_adapter.rb +453 -0
  38. data/lib/active_record/dirty.rb +183 -0
  39. data/lib/active_record/dynamic_finder_match.rb +41 -0
  40. data/lib/active_record/dynamic_scope_match.rb +25 -0
  41. data/lib/active_record/fixtures.rb +996 -0
  42. data/lib/active_record/i18n_interpolation_deprecation.rb +26 -0
  43. data/lib/active_record/locale/en.yml +58 -0
  44. data/lib/active_record/locking/optimistic.rb +148 -0
  45. data/lib/active_record/locking/pessimistic.rb +55 -0
  46. data/lib/active_record/migration.rb +566 -0
  47. data/lib/active_record/named_scope.rb +192 -0
  48. data/lib/active_record/nested_attributes.rb +392 -0
  49. data/lib/active_record/observer.rb +197 -0
  50. data/lib/active_record/query_cache.rb +33 -0
  51. data/lib/active_record/reflection.rb +320 -0
  52. data/lib/active_record/schema.rb +51 -0
  53. data/lib/active_record/schema_dumper.rb +182 -0
  54. data/lib/active_record/serialization.rb +101 -0
  55. data/lib/active_record/serializers/json_serializer.rb +91 -0
  56. data/lib/active_record/serializers/xml_serializer.rb +357 -0
  57. data/lib/active_record/session_store.rb +326 -0
  58. data/lib/active_record/test_case.rb +66 -0
  59. data/lib/active_record/timestamp.rb +71 -0
  60. data/lib/active_record/transactions.rb +235 -0
  61. data/lib/active_record/validations.rb +1135 -0
  62. data/lib/active_record/version.rb +9 -0
  63. data/lib/active_record.rb +84 -0
  64. data/lib/activerecord.rb +2 -0
  65. data/test/assets/example.log +1 -0
  66. data/test/assets/flowers.jpg +0 -0
  67. data/test/cases/aaa_create_tables_test.rb +24 -0
  68. data/test/cases/active_schema_test_mysql.rb +100 -0
  69. data/test/cases/active_schema_test_postgresql.rb +24 -0
  70. data/test/cases/adapter_test.rb +145 -0
  71. data/test/cases/aggregations_test.rb +167 -0
  72. data/test/cases/ar_schema_test.rb +32 -0
  73. data/test/cases/associations/belongs_to_associations_test.rb +425 -0
  74. data/test/cases/associations/callbacks_test.rb +161 -0
  75. data/test/cases/associations/cascaded_eager_loading_test.rb +131 -0
  76. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  77. data/test/cases/associations/eager_load_nested_include_test.rb +130 -0
  78. data/test/cases/associations/eager_singularization_test.rb +145 -0
  79. data/test/cases/associations/eager_test.rb +834 -0
  80. data/test/cases/associations/extension_test.rb +62 -0
  81. data/test/cases/associations/habtm_join_table_test.rb +56 -0
  82. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +822 -0
  83. data/test/cases/associations/has_many_associations_test.rb +1134 -0
  84. data/test/cases/associations/has_many_through_associations_test.rb +346 -0
  85. data/test/cases/associations/has_one_associations_test.rb +330 -0
  86. data/test/cases/associations/has_one_through_associations_test.rb +209 -0
  87. data/test/cases/associations/inner_join_association_test.rb +93 -0
  88. data/test/cases/associations/join_model_test.rb +712 -0
  89. data/test/cases/associations_test.rb +262 -0
  90. data/test/cases/attribute_methods_test.rb +305 -0
  91. data/test/cases/autosave_association_test.rb +1142 -0
  92. data/test/cases/base_test.rb +2154 -0
  93. data/test/cases/batches_test.rb +61 -0
  94. data/test/cases/binary_test.rb +30 -0
  95. data/test/cases/calculations_test.rb +348 -0
  96. data/test/cases/callbacks_observers_test.rb +38 -0
  97. data/test/cases/callbacks_test.rb +438 -0
  98. data/test/cases/class_inheritable_attributes_test.rb +32 -0
  99. data/test/cases/column_alias_test.rb +17 -0
  100. data/test/cases/column_definition_test.rb +70 -0
  101. data/test/cases/connection_pool_test.rb +25 -0
  102. data/test/cases/connection_test_firebird.rb +8 -0
  103. data/test/cases/connection_test_mysql.rb +64 -0
  104. data/test/cases/copy_table_test_sqlite.rb +80 -0
  105. data/test/cases/database_statements_test.rb +12 -0
  106. data/test/cases/datatype_test_postgresql.rb +204 -0
  107. data/test/cases/date_time_test.rb +37 -0
  108. data/test/cases/default_test_firebird.rb +16 -0
  109. data/test/cases/defaults_test.rb +111 -0
  110. data/test/cases/deprecated_finder_test.rb +30 -0
  111. data/test/cases/dirty_test.rb +316 -0
  112. data/test/cases/finder_respond_to_test.rb +76 -0
  113. data/test/cases/finder_test.rb +1066 -0
  114. data/test/cases/fixtures_test.rb +656 -0
  115. data/test/cases/helper.rb +68 -0
  116. data/test/cases/i18n_test.rb +46 -0
  117. data/test/cases/inheritance_test.rb +262 -0
  118. data/test/cases/invalid_date_test.rb +24 -0
  119. data/test/cases/json_serialization_test.rb +205 -0
  120. data/test/cases/lifecycle_test.rb +193 -0
  121. data/test/cases/locking_test.rb +304 -0
  122. data/test/cases/method_scoping_test.rb +704 -0
  123. data/test/cases/migration_test.rb +1523 -0
  124. data/test/cases/migration_test_firebird.rb +124 -0
  125. data/test/cases/mixin_test.rb +96 -0
  126. data/test/cases/modules_test.rb +81 -0
  127. data/test/cases/multiple_db_test.rb +85 -0
  128. data/test/cases/named_scope_test.rb +361 -0
  129. data/test/cases/nested_attributes_test.rb +581 -0
  130. data/test/cases/pk_test.rb +119 -0
  131. data/test/cases/pooled_connections_test.rb +103 -0
  132. data/test/cases/query_cache_test.rb +123 -0
  133. data/test/cases/readonly_test.rb +107 -0
  134. data/test/cases/reflection_test.rb +194 -0
  135. data/test/cases/reload_models_test.rb +22 -0
  136. data/test/cases/repair_helper.rb +50 -0
  137. data/test/cases/reserved_word_test_mysql.rb +176 -0
  138. data/test/cases/sanitize_test.rb +25 -0
  139. data/test/cases/schema_authorization_test_postgresql.rb +75 -0
  140. data/test/cases/schema_dumper_test.rb +211 -0
  141. data/test/cases/schema_test_postgresql.rb +178 -0
  142. data/test/cases/serialization_test.rb +47 -0
  143. data/test/cases/synonym_test_oracle.rb +17 -0
  144. data/test/cases/timestamp_test.rb +75 -0
  145. data/test/cases/transactions_test.rb +522 -0
  146. data/test/cases/unconnected_test.rb +32 -0
  147. data/test/cases/validations_i18n_test.rb +955 -0
  148. data/test/cases/validations_test.rb +1640 -0
  149. data/test/cases/xml_serialization_test.rb +240 -0
  150. data/test/config.rb +5 -0
  151. data/test/connections/jdbc_jdbcderby/connection.rb +18 -0
  152. data/test/connections/jdbc_jdbch2/connection.rb +18 -0
  153. data/test/connections/jdbc_jdbchsqldb/connection.rb +18 -0
  154. data/test/connections/jdbc_jdbcmysql/connection.rb +26 -0
  155. data/test/connections/jdbc_jdbcpostgresql/connection.rb +26 -0
  156. data/test/connections/jdbc_jdbcsqlite3/connection.rb +25 -0
  157. data/test/connections/native_db2/connection.rb +25 -0
  158. data/test/connections/native_firebird/connection.rb +26 -0
  159. data/test/connections/native_frontbase/connection.rb +27 -0
  160. data/test/connections/native_mysql/connection.rb +25 -0
  161. data/test/connections/native_openbase/connection.rb +21 -0
  162. data/test/connections/native_oracle/connection.rb +27 -0
  163. data/test/connections/native_postgresql/connection.rb +25 -0
  164. data/test/connections/native_sqlite/connection.rb +25 -0
  165. data/test/connections/native_sqlite3/connection.rb +25 -0
  166. data/test/connections/native_sqlite3/in_memory_connection.rb +18 -0
  167. data/test/connections/native_sybase/connection.rb +23 -0
  168. data/test/fixtures/accounts.yml +29 -0
  169. data/test/fixtures/all/developers.yml +0 -0
  170. data/test/fixtures/all/people.csv +0 -0
  171. data/test/fixtures/all/tasks.yml +0 -0
  172. data/test/fixtures/author_addresses.yml +5 -0
  173. data/test/fixtures/author_favorites.yml +4 -0
  174. data/test/fixtures/authors.yml +9 -0
  175. data/test/fixtures/binaries.yml +132 -0
  176. data/test/fixtures/books.yml +7 -0
  177. data/test/fixtures/categories/special_categories.yml +9 -0
  178. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  179. data/test/fixtures/categories.yml +14 -0
  180. data/test/fixtures/categories_ordered.yml +7 -0
  181. data/test/fixtures/categories_posts.yml +23 -0
  182. data/test/fixtures/categorizations.yml +17 -0
  183. data/test/fixtures/clubs.yml +6 -0
  184. data/test/fixtures/comments.yml +59 -0
  185. data/test/fixtures/companies.yml +56 -0
  186. data/test/fixtures/computers.yml +4 -0
  187. data/test/fixtures/courses.yml +7 -0
  188. data/test/fixtures/customers.yml +26 -0
  189. data/test/fixtures/developers.yml +21 -0
  190. data/test/fixtures/developers_projects.yml +17 -0
  191. data/test/fixtures/edges.yml +6 -0
  192. data/test/fixtures/entrants.yml +14 -0
  193. data/test/fixtures/fixture_database.sqlite3 +0 -0
  194. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  195. data/test/fixtures/fk_test_has_fk.yml +3 -0
  196. data/test/fixtures/fk_test_has_pk.yml +2 -0
  197. data/test/fixtures/funny_jokes.yml +10 -0
  198. data/test/fixtures/items.yml +4 -0
  199. data/test/fixtures/jobs.yml +7 -0
  200. data/test/fixtures/legacy_things.yml +3 -0
  201. data/test/fixtures/mateys.yml +4 -0
  202. data/test/fixtures/member_types.yml +6 -0
  203. data/test/fixtures/members.yml +6 -0
  204. data/test/fixtures/memberships.yml +20 -0
  205. data/test/fixtures/minimalistics.yml +2 -0
  206. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  207. data/test/fixtures/mixins.yml +29 -0
  208. data/test/fixtures/movies.yml +7 -0
  209. data/test/fixtures/naked/csv/accounts.csv +1 -0
  210. data/test/fixtures/naked/yml/accounts.yml +1 -0
  211. data/test/fixtures/naked/yml/companies.yml +1 -0
  212. data/test/fixtures/naked/yml/courses.yml +1 -0
  213. data/test/fixtures/organizations.yml +5 -0
  214. data/test/fixtures/owners.yml +7 -0
  215. data/test/fixtures/parrots.yml +27 -0
  216. data/test/fixtures/parrots_pirates.yml +7 -0
  217. data/test/fixtures/people.yml +15 -0
  218. data/test/fixtures/pets.yml +14 -0
  219. data/test/fixtures/pirates.yml +9 -0
  220. data/test/fixtures/posts.yml +52 -0
  221. data/test/fixtures/price_estimates.yml +7 -0
  222. data/test/fixtures/projects.yml +7 -0
  223. data/test/fixtures/readers.yml +9 -0
  224. data/test/fixtures/references.yml +17 -0
  225. data/test/fixtures/reserved_words/distinct.yml +5 -0
  226. data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
  227. data/test/fixtures/reserved_words/group.yml +14 -0
  228. data/test/fixtures/reserved_words/select.yml +8 -0
  229. data/test/fixtures/reserved_words/values.yml +7 -0
  230. data/test/fixtures/ships.yml +5 -0
  231. data/test/fixtures/sponsors.yml +9 -0
  232. data/test/fixtures/subscribers.yml +7 -0
  233. data/test/fixtures/subscriptions.yml +12 -0
  234. data/test/fixtures/taggings.yml +28 -0
  235. data/test/fixtures/tags.yml +7 -0
  236. data/test/fixtures/tasks.yml +7 -0
  237. data/test/fixtures/topics.yml +42 -0
  238. data/test/fixtures/toys.yml +4 -0
  239. data/test/fixtures/treasures.yml +10 -0
  240. data/test/fixtures/vertices.yml +4 -0
  241. data/test/fixtures/warehouse-things.yml +3 -0
  242. data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
  243. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  244. data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
  245. data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
  246. data/test/migrations/duplicate/3_foo.rb +7 -0
  247. data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
  248. data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
  249. data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
  250. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
  251. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
  252. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
  253. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
  254. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
  255. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
  256. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  257. data/test/migrations/missing/1_people_have_last_names.rb +9 -0
  258. data/test/migrations/missing/3_we_need_reminders.rb +12 -0
  259. data/test/migrations/missing/4_innocent_jointable.rb +12 -0
  260. data/test/migrations/valid/1_people_have_last_names.rb +9 -0
  261. data/test/migrations/valid/2_we_need_reminders.rb +12 -0
  262. data/test/migrations/valid/3_innocent_jointable.rb +12 -0
  263. data/test/models/author.rb +146 -0
  264. data/test/models/auto_id.rb +4 -0
  265. data/test/models/binary.rb +2 -0
  266. data/test/models/bird.rb +3 -0
  267. data/test/models/book.rb +4 -0
  268. data/test/models/categorization.rb +5 -0
  269. data/test/models/category.rb +34 -0
  270. data/test/models/citation.rb +6 -0
  271. data/test/models/club.rb +13 -0
  272. data/test/models/column_name.rb +3 -0
  273. data/test/models/comment.rb +29 -0
  274. data/test/models/company.rb +171 -0
  275. data/test/models/company_in_module.rb +61 -0
  276. data/test/models/computer.rb +3 -0
  277. data/test/models/contact.rb +16 -0
  278. data/test/models/contract.rb +5 -0
  279. data/test/models/course.rb +3 -0
  280. data/test/models/customer.rb +73 -0
  281. data/test/models/default.rb +2 -0
  282. data/test/models/developer.rb +101 -0
  283. data/test/models/edge.rb +5 -0
  284. data/test/models/entrant.rb +3 -0
  285. data/test/models/essay.rb +3 -0
  286. data/test/models/event.rb +3 -0
  287. data/test/models/guid.rb +2 -0
  288. data/test/models/item.rb +7 -0
  289. data/test/models/job.rb +5 -0
  290. data/test/models/joke.rb +3 -0
  291. data/test/models/keyboard.rb +3 -0
  292. data/test/models/legacy_thing.rb +3 -0
  293. data/test/models/matey.rb +4 -0
  294. data/test/models/member.rb +12 -0
  295. data/test/models/member_detail.rb +5 -0
  296. data/test/models/member_type.rb +3 -0
  297. data/test/models/membership.rb +9 -0
  298. data/test/models/minimalistic.rb +2 -0
  299. data/test/models/mixed_case_monkey.rb +3 -0
  300. data/test/models/movie.rb +5 -0
  301. data/test/models/order.rb +4 -0
  302. data/test/models/organization.rb +6 -0
  303. data/test/models/owner.rb +5 -0
  304. data/test/models/parrot.rb +16 -0
  305. data/test/models/person.rb +16 -0
  306. data/test/models/pet.rb +5 -0
  307. data/test/models/pirate.rb +70 -0
  308. data/test/models/post.rb +100 -0
  309. data/test/models/price_estimate.rb +3 -0
  310. data/test/models/project.rb +30 -0
  311. data/test/models/reader.rb +4 -0
  312. data/test/models/reference.rb +4 -0
  313. data/test/models/reply.rb +46 -0
  314. data/test/models/ship.rb +10 -0
  315. data/test/models/ship_part.rb +5 -0
  316. data/test/models/sponsor.rb +4 -0
  317. data/test/models/subject.rb +4 -0
  318. data/test/models/subscriber.rb +8 -0
  319. data/test/models/subscription.rb +4 -0
  320. data/test/models/tag.rb +7 -0
  321. data/test/models/tagging.rb +10 -0
  322. data/test/models/task.rb +3 -0
  323. data/test/models/topic.rb +80 -0
  324. data/test/models/toy.rb +6 -0
  325. data/test/models/treasure.rb +8 -0
  326. data/test/models/vertex.rb +9 -0
  327. data/test/models/warehouse_thing.rb +5 -0
  328. data/test/schema/mysql_specific_schema.rb +24 -0
  329. data/test/schema/postgresql_specific_schema.rb +114 -0
  330. data/test/schema/schema.rb +493 -0
  331. data/test/schema/schema2.rb +6 -0
  332. data/test/schema/sqlite_specific_schema.rb +25 -0
  333. metadata +420 -0
@@ -0,0 +1,955 @@
1
+ require "cases/helper"
2
+ require 'models/topic'
3
+ require 'models/reply'
4
+ require 'models/person'
5
+
6
+ module ActiveRecordValidationsI18nTestHelper
7
+ def store_translations(*args)
8
+ data = args.extract_options!
9
+ locale = args.shift || 'en'
10
+ I18n.backend.send(:init_translations)
11
+ I18n.backend.store_translations(locale, :activerecord => data)
12
+ end
13
+
14
+ def delete_translation(key)
15
+ I18n.backend.instance_eval do
16
+ keys = I18n.send(:normalize_translation_keys, 'en', key, nil)
17
+ keys.inject(translations) { |result, k| keys.last == k ? result.delete(k.to_sym) : result[k.to_sym] }
18
+ end
19
+ end
20
+
21
+ def reset_callbacks(*models)
22
+ models.each do |model|
23
+ model.instance_variable_set("@validate_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
24
+ model.instance_variable_set("@validate_on_create_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
25
+ model.instance_variable_set("@validate_on_update_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
26
+ end
27
+ end
28
+ end
29
+
30
+ # DEPRECATIONS
31
+
32
+ class ActiveRecordValidationsI18nDeprecationsTests < ActiveSupport::TestCase
33
+ test "default_error_messages is deprecated and can be removed in Rails 3 / ActiveModel" do
34
+ assert_deprecated('ActiveRecord::Errors.default_error_messages') do
35
+ ActiveRecord::Errors.default_error_messages
36
+ end
37
+ end
38
+
39
+ test "%s interpolation syntax in error messages still works" do
40
+ ActiveSupport::Deprecation.silence do
41
+ result = I18n.t :does_not_exist, :default => "%s interpolation syntax is deprecated", :value => 'this'
42
+ assert_equal result, "this interpolation syntax is deprecated"
43
+ end
44
+ end
45
+
46
+ test "%s interpolation syntax in error messages is deprecated" do
47
+ assert_deprecated('using %s in messages') do
48
+ I18n.t :does_not_exist, :default => "%s interpolation syntax is deprected", :value => 'this'
49
+ end
50
+ end
51
+
52
+ test "%d interpolation syntax in error messages still works" do
53
+ ActiveSupport::Deprecation.silence do
54
+ result = I18n.t :does_not_exist, :default => "%d interpolation syntaxes are deprecated", :count => 2
55
+ assert_equal result, "2 interpolation syntaxes are deprecated"
56
+ end
57
+ end
58
+
59
+ test "%d interpolation syntax in error messages is deprecated" do
60
+ assert_deprecated('using %d in messages') do
61
+ I18n.t :does_not_exist, :default => "%d interpolation syntaxes are deprected", :count => 2
62
+ end
63
+ end
64
+ end
65
+
66
+
67
+ # ACTIVERECORD VALIDATIONS
68
+ #
69
+ # For each validation:
70
+ #
71
+ # * test expect that it adds an error with the appropriate arguments
72
+ # * test that it looks up the correct default message
73
+
74
+ class ActiveRecordValidationsI18nTests < ActiveSupport::TestCase
75
+ include ActiveRecordValidationsI18nTestHelper
76
+
77
+ def setup
78
+ reset_callbacks(Topic)
79
+ @topic = Topic.new
80
+ @reply = Reply.new
81
+ @old_load_path, @old_backend = I18n.load_path, I18n.backend
82
+ I18n.load_path.clear
83
+ I18n.backend = I18n::Backend::Simple.new
84
+ I18n.backend.store_translations('en', :activerecord => {:errors => {:messages => {:custom => nil}}})
85
+ end
86
+
87
+ def teardown
88
+ reset_callbacks(Topic)
89
+ I18n.load_path.replace(@old_load_path)
90
+ I18n.backend = @old_backend
91
+ end
92
+
93
+ def expect_error_added(model, attribute, type, options)
94
+ model.errors.expects(:add).with(attribute, type, options)
95
+ yield
96
+ model.valid?
97
+ end
98
+
99
+ def assert_message_translations(model, attribute, type, &block)
100
+ assert_default_message_translation(model, attribute, type, &block)
101
+ reset_callbacks(model.class)
102
+ model.errors.clear
103
+ assert_custom_message_translation(model, attribute, type, &block)
104
+ end
105
+
106
+ def assert_custom_message_translation(model, attribute, type)
107
+ store_translations(:errors => { :models => { model.class.name.underscore => { :attributes => { attribute => { type => 'custom message' } } } } })
108
+ yield
109
+ model.valid?
110
+ assert_equal 'custom message', model.errors.on(attribute)
111
+ end
112
+
113
+ def assert_default_message_translation(model, attribute, type)
114
+ store_translations(:errors => { :messages => { type => 'default message' } })
115
+ yield
116
+ model.valid?
117
+ assert_equal 'default message', model.errors.on(attribute)
118
+ end
119
+
120
+ def unique_topic
121
+ @unique ||= Topic.create(:title => 'unique!')
122
+ end
123
+
124
+ def replied_topic
125
+ @replied_topic ||= begin
126
+ topic = Topic.create(:title => "topic")
127
+ topic.replies << Reply.new
128
+ topic
129
+ end
130
+ end
131
+
132
+ # validates_confirmation_of
133
+
134
+ test "#validates_confirmation_of given no custom message" do
135
+ expect_error_added(@topic, :title, :confirmation, :default => nil) do
136
+ Topic.validates_confirmation_of :title
137
+ @topic.title = 'title'
138
+ @topic.title_confirmation = 'foo'
139
+ end
140
+ end
141
+
142
+ test "#validates_confirmation_of given a custom message" do
143
+ expect_error_added(@topic, :title, :confirmation, :default => 'custom') do
144
+ Topic.validates_confirmation_of :title, :message => 'custom'
145
+ @topic.title_confirmation = 'foo'
146
+ end
147
+ end
148
+
149
+ test "#validates_confirmation_of finds the correct message translations" do
150
+ assert_message_translations(@topic, :title, :confirmation) do
151
+ Topic.validates_confirmation_of :title
152
+ @topic.title_confirmation = 'foo'
153
+ end
154
+ end
155
+
156
+ # validates_acceptance_of
157
+
158
+ test "#validates_acceptance_of given no custom message" do
159
+ expect_error_added(@topic, :title, :accepted, :default => nil) do
160
+ Topic.validates_acceptance_of :title, :allow_nil => false
161
+ end
162
+ end
163
+
164
+ test "#validates_acceptance_of given a custom message" do
165
+ expect_error_added(@topic, :title, :accepted, :default => 'custom') do
166
+ Topic.validates_acceptance_of :title, :message => 'custom', :allow_nil => false
167
+ end
168
+ end
169
+
170
+ test "#validates_acceptance_of finds the correct message translations" do
171
+ assert_message_translations(@topic, :title, :accepted) do
172
+ Topic.validates_acceptance_of :title, :allow_nil => false
173
+ end
174
+ end
175
+
176
+ # validates_presence_of
177
+
178
+ test "#validates_presence_of given no custom message" do
179
+ expect_error_added(@topic, :title, :blank, :default => nil) do
180
+ Topic.validates_presence_of :title
181
+ end
182
+ end
183
+
184
+ test "#validates_presence_of given a custom message" do
185
+ expect_error_added(@topic, :title, :blank, :default => 'custom') do
186
+ Topic.validates_presence_of :title, :message => 'custom'
187
+ end
188
+ end
189
+
190
+ test "#validates_presence_of finds the correct message translations" do
191
+ assert_message_translations(@topic, :title, :blank) do
192
+ Topic.validates_presence_of :title
193
+ end
194
+ end
195
+
196
+ # validates_length_of :too_short
197
+
198
+ test "#validates_length_of (:too_short) and no custom message" do
199
+ expect_error_added(@topic, :title, :too_short, :default => nil, :count => 3) do
200
+ Topic.validates_length_of :title, :within => 3..5
201
+ end
202
+ end
203
+
204
+ test "#validates_length_of (:too_short) and a custom message" do
205
+ expect_error_added(@topic, :title, :too_short, :default => 'custom', :count => 3) do
206
+ Topic.validates_length_of :title, :within => 3..5, :too_short => 'custom'
207
+ end
208
+ end
209
+
210
+ test "#validates_length_of (:too_short) finds the correct message translations" do
211
+ assert_message_translations(@topic, :title, :too_short) do
212
+ Topic.validates_length_of :title, :within => 3..5
213
+ end
214
+ end
215
+
216
+ # validates_length_of :too_long
217
+
218
+ test "#validates_length_of (:too_long) and no custom message" do
219
+ expect_error_added(@topic, :title, :too_long, :default => nil, :count => 5) do
220
+ Topic.validates_length_of :title, :within => 3..5
221
+ @topic.title = 'this title is too long'
222
+ end
223
+ end
224
+
225
+ test "#validates_length_of (:too_long) and a custom message" do
226
+ expect_error_added(@topic, :title, :too_long, :default => 'custom', :count => 5) do
227
+ Topic.validates_length_of :title, :within => 3..5, :too_long => 'custom'
228
+ @topic.title = 'this title is too long'
229
+ end
230
+ end
231
+
232
+ test "#validates_length_of (:too_long) finds the correct message translations" do
233
+ assert_message_translations(@topic, :title, :too_long) do
234
+ Topic.validates_length_of :title, :within => 3..5
235
+ @topic.title = 'this title is too long'
236
+ end
237
+ end
238
+
239
+ # validates_length_of :is
240
+
241
+ test "#validates_length_of (:is) and no custom message" do
242
+ expect_error_added(@topic, :title, :wrong_length, :default => nil, :count => 5) do
243
+ Topic.validates_length_of :title, :is => 5
244
+ @topic.title = 'this title has the wrong length'
245
+ end
246
+ end
247
+
248
+ test "#validates_length_of (:is) and a custom message" do
249
+ expect_error_added(@topic, :title, :wrong_length, :default => 'custom', :count => 5) do
250
+ Topic.validates_length_of :title, :is => 5, :wrong_length => 'custom'
251
+ @topic.title = 'this title has the wrong length'
252
+ end
253
+ end
254
+
255
+ test "#validates_length_of (:is) finds the correct message translations" do
256
+ assert_message_translations(@topic, :title, :wrong_length) do
257
+ Topic.validates_length_of :title, :is => 5
258
+ @topic.title = 'this title has the wrong length'
259
+ end
260
+ end
261
+
262
+ # validates_uniqueness_of
263
+
264
+ test "#validates_uniqueness_of and no custom message" do
265
+ expect_error_added(@topic, :title, :taken, :default => nil, :value => 'unique!') do
266
+ Topic.validates_uniqueness_of :title
267
+ @topic.title = unique_topic.title
268
+ end
269
+ end
270
+
271
+ test "#validates_uniqueness_of and a custom message" do
272
+ expect_error_added(@topic, :title, :taken, :default => 'custom', :value => 'unique!') do
273
+ Topic.validates_uniqueness_of :title, :message => 'custom'
274
+ @topic.title = unique_topic.title
275
+ end
276
+ end
277
+
278
+ test "#validates_uniqueness_of finds the correct message translations" do
279
+ assert_message_translations(@topic, :title, :taken) do
280
+ Topic.validates_uniqueness_of :title
281
+ @topic.title = unique_topic.title
282
+ end
283
+ end
284
+
285
+ # validates_format_of
286
+
287
+ test "#validates_format_of and no custom message" do
288
+ expect_error_added(@topic, :title, :invalid, :default => nil, :value => '72x') do
289
+ Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/
290
+ @topic.title = '72x'
291
+ end
292
+ end
293
+
294
+ test "#validates_format_of and a custom message" do
295
+ expect_error_added(@topic, :title, :invalid, :default => 'custom', :value => '72x') do
296
+ Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/, :message => 'custom'
297
+ @topic.title = '72x'
298
+ end
299
+ end
300
+
301
+ test "#validates_format_of finds the correct message translations" do
302
+ assert_message_translations(@topic, :title, :invalid) do
303
+ Topic.validates_format_of :title, :with => /^[1-9][0-9]*$/
304
+ @topic.title = '72x'
305
+ end
306
+ end
307
+
308
+ # validates_inclusion_of
309
+
310
+ test "#validates_inclusion_of and no custom message" do
311
+ list = %w(a b c)
312
+ expect_error_added(@topic, :title, :inclusion, :default => nil, :value => 'z') do
313
+ Topic.validates_inclusion_of :title, :in => list
314
+ @topic.title = 'z'
315
+ end
316
+ end
317
+
318
+ test "#validates_inclusion_of and a custom message" do
319
+ list = %w(a b c)
320
+ expect_error_added(@topic, :title, :inclusion, :default => 'custom', :value => 'z') do
321
+ Topic.validates_inclusion_of :title, :in => list, :message => 'custom'
322
+ @topic.title = 'z'
323
+ end
324
+ end
325
+
326
+ test "#validates_inclusion_of finds the correct message translations" do
327
+ list = %w(a b c)
328
+ assert_message_translations(@topic, :title, :inclusion) do
329
+ Topic.validates_inclusion_of :title, :in => list
330
+ @topic.title = 'z'
331
+ end
332
+ end
333
+
334
+ # validates_exclusion_of
335
+
336
+ test "#validates_exclusion_of and no custom message" do
337
+ list = %w(a b c)
338
+ expect_error_added(@topic, :title, :exclusion, :default => nil, :value => 'a') do
339
+ Topic.validates_exclusion_of :title, :in => list
340
+ @topic.title = 'a'
341
+ end
342
+ end
343
+
344
+ test "#validates_exclusion_of and a custom message" do
345
+ list = %w(a b c)
346
+ expect_error_added(@topic, :title, :exclusion, :default => 'custom', :value => 'a') do
347
+ Topic.validates_exclusion_of :title, :in => list, :message => 'custom'
348
+ @topic.title = 'a'
349
+ end
350
+ end
351
+
352
+ test "#validates_exclusion_of finds the correct message translations" do
353
+ list = %w(a b c)
354
+ assert_message_translations(@topic, :title, :exclusion) do
355
+ Topic.validates_exclusion_of :title, :in => list
356
+ @topic.title = 'a'
357
+ end
358
+ end
359
+
360
+ # validates_numericality_of :not_a_number, without :only_integer
361
+
362
+ test "#validates_numericality_of (:not_a_number, w/o :only_integer) no custom message" do
363
+ expect_error_added(@topic, :title, :not_a_number, :default => nil, :value => 'a') do
364
+ Topic.validates_numericality_of :title
365
+ @topic.title = 'a'
366
+ end
367
+ end
368
+
369
+ test "#validates_numericality_of (:not_a_number, w/o :only_integer) and a custom message" do
370
+ expect_error_added(@topic, :title, :not_a_number, :default => 'custom', :value => 'a') do
371
+ Topic.validates_numericality_of :title, :message => 'custom'
372
+ @topic.title = 'a'
373
+ end
374
+ end
375
+
376
+ test "#validates_numericality_of (:not_a_number, w/o :only_integer) finds the correct message translations" do
377
+ assert_message_translations(@topic, :title, :not_a_number) do
378
+ Topic.validates_numericality_of :title
379
+ @topic.title = 'a'
380
+ end
381
+ end
382
+
383
+ # validates_numericality_of :not_a_number, with :only_integer
384
+
385
+ test "#validates_numericality_of (:not_a_number, with :only_integer) no custom message" do
386
+ expect_error_added(@topic, :title, :not_a_number, :default => nil, :value => 'a') do
387
+ Topic.validates_numericality_of :title, :only_integer => true
388
+ @topic.title = 'a'
389
+ end
390
+ end
391
+
392
+ test "#validates_numericality_of (:not_a_number, with :only_integer) and a custom message" do
393
+ expect_error_added(@topic, :title, :not_a_number, :default => 'custom', :value => 'a') do
394
+ Topic.validates_numericality_of :title, :only_integer => true, :message => 'custom'
395
+ @topic.title = 'a'
396
+ end
397
+ end
398
+
399
+ test "#validates_numericality_of (:not_a_number, with :only_integer) finds the correct message translations" do
400
+ assert_message_translations(@topic, :title, :not_a_number) do
401
+ Topic.validates_numericality_of :title, :only_integer => true
402
+ @topic.title = 'a'
403
+ end
404
+ end
405
+
406
+ # validates_numericality_of :odd
407
+
408
+ test "#validates_numericality_of (:odd) no custom message" do
409
+ expect_error_added(@topic, :title, :odd, :default => nil, :value => 0) do
410
+ Topic.validates_numericality_of :title, :only_integer => true, :odd => true
411
+ @topic.title = 0
412
+ end
413
+ end
414
+
415
+ test "#validates_numericality_of (:odd) and a custom message" do
416
+ expect_error_added(@topic, :title, :odd, :default => 'custom', :value => 0) do
417
+ Topic.validates_numericality_of :title, :only_integer => true, :odd => true, :message => 'custom'
418
+ @topic.title = 0
419
+ end
420
+ end
421
+
422
+ test "#validates_numericality_of (:odd) finds the correct message translations" do
423
+ assert_message_translations(@topic, :title, :odd) do
424
+ Topic.validates_numericality_of :title, :only_integer => true, :odd => true
425
+ @topic.title = 0
426
+ end
427
+ end
428
+
429
+ # validates_numericality_of :even
430
+
431
+ test "#validates_numericality_of (:even) no custom message" do
432
+ expect_error_added(@topic, :title, :even, :default => nil, :value => 1) do
433
+ Topic.validates_numericality_of :title, :only_integer => true, :even => true
434
+ @topic.title = 1
435
+ end
436
+ end
437
+
438
+ test "#validates_numericality_of (:even) and a custom message" do
439
+ expect_error_added(@topic, :title, :even, :default => 'custom', :value => 1) do
440
+ Topic.validates_numericality_of :title, :only_integer => true, :even => true, :message => 'custom'
441
+ @topic.title = 1
442
+ end
443
+ end
444
+
445
+ test "#validates_numericality_of (:even) finds the correct message translations" do
446
+ assert_message_translations(@topic, :title, :even) do
447
+ Topic.validates_numericality_of :title, :only_integer => true, :even => true
448
+ @topic.title = 1
449
+ end
450
+ end
451
+
452
+ # validates_numericality_of :less_than
453
+
454
+ test "#validates_numericality_of (:less_than) no custom message" do
455
+ expect_error_added(@topic, :title, :less_than, :default => nil, :value => 1, :count => 0) do
456
+ Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0
457
+ @topic.title = 1
458
+ end
459
+ end
460
+
461
+ test "#validates_numericality_of (:less_than) and a custom message" do
462
+ expect_error_added(@topic, :title, :less_than, :default => 'custom', :value => 1, :count => 0) do
463
+ Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0, :message => 'custom'
464
+ @topic.title = 1
465
+ end
466
+ end
467
+
468
+ test "#validates_numericality_of (:less_than) finds the correct message translations" do
469
+ assert_message_translations(@topic, :title, :less_than) do
470
+ Topic.validates_numericality_of :title, :only_integer => true, :less_than => 0
471
+ @topic.title = 1
472
+ end
473
+ end
474
+
475
+ # validates_associated
476
+
477
+ test "#validates_associated no custom message" do
478
+ expect_error_added(replied_topic, :replies, :invalid, :default => nil, :value => replied_topic.replies) do
479
+ Topic.validates_associated :replies
480
+ end
481
+ end
482
+
483
+ test "#validates_associated and a custom message" do
484
+ expect_error_added(replied_topic, :replies, :invalid, :default => 'custom', :value => replied_topic.replies) do
485
+ Topic.validates_associated :replies, :message => 'custom'
486
+ end
487
+ end
488
+
489
+ test "#validates_associated finds the correct message translations" do
490
+ assert_message_translations(replied_topic, :replies, :invalid) do
491
+ Topic.validates_associated :replies
492
+ end
493
+ end
494
+ end
495
+
496
+
497
+ # ACTIVERECORD ERROR
498
+ #
499
+ # * test that it passes given interpolation arguments, the human model name and human attribute name
500
+ # * test that it looks messages up with the the correct keys
501
+ # * test that it looks up the correct default messages
502
+
503
+ class ActiveRecordErrorI18nTests < ActiveSupport::TestCase
504
+ include ActiveRecordValidationsI18nTestHelper
505
+
506
+ def setup
507
+ @reply = Reply.new
508
+ @old_backend, I18n.backend = I18n.backend, I18n::Backend::Simple.new
509
+ end
510
+
511
+ def teardown
512
+ I18n.backend = @old_backend
513
+ I18n.locale = nil
514
+ end
515
+
516
+ def assert_error_message(message, *args)
517
+ assert_equal message, ActiveRecord::Error.new(@reply, *args).message
518
+ end
519
+
520
+ def assert_full_message(message, *args)
521
+ assert_equal message, ActiveRecord::Error.new(@reply, *args).full_message
522
+ end
523
+
524
+ test "#generate_message passes the model attribute value for interpolation" do
525
+ store_translations(:errors => { :messages => { :foo => "You fooed: {{value}}." } })
526
+ @reply.title = "da title"
527
+ assert_error_message 'You fooed: da title.', :title, :foo
528
+ end
529
+
530
+ test "#generate_message passes the human_name of the model for interpolation" do
531
+ store_translations(
532
+ :errors => { :messages => { :foo => "You fooed: {{model}}." } },
533
+ :models => { :topic => 'da topic' }
534
+ )
535
+ assert_error_message 'You fooed: da topic.', :title, :foo
536
+ end
537
+
538
+ test "#generate_message passes the human_name of the attribute for interpolation" do
539
+ store_translations(
540
+ :errors => { :messages => { :foo => "You fooed: {{attribute}}." } },
541
+ :attributes => { :topic => { :title => 'da topic title' } }
542
+ )
543
+ assert_error_message 'You fooed: da topic title.', :title, :foo
544
+ end
545
+
546
+ # generate_message will look up the key for the error message (e.g. :blank) in these namespaces:
547
+ #
548
+ # activerecord.errors.models.reply.attributes.title
549
+ # activerecord.errors.models.reply
550
+ # activerecord.errors.models.topic.attributes.title
551
+ # activerecord.errors.models.topic
552
+ # [default from class level :validates_foo statement if this is a String]
553
+ # activerecord.errors.messages
554
+
555
+ test "#generate_message key fallbacks (given a String as key)" do
556
+ store_translations(
557
+ :errors => {
558
+ :models => {
559
+ :reply => {
560
+ :attributes => { :title => { :custom => 'activerecord.errors.models.reply.attributes.title.custom' } },
561
+ :custom => 'activerecord.errors.models.reply.custom'
562
+ },
563
+ :topic => {
564
+ :attributes => { :title => { :custom => 'activerecord.errors.models.topic.attributes.title.custom' } },
565
+ :custom => 'activerecord.errors.models.topic.custom'
566
+ }
567
+ },
568
+ :messages => {
569
+ :custom => 'activerecord.errors.messages.custom',
570
+ :kaputt => 'activerecord.errors.messages.kaputt'
571
+ }
572
+ }
573
+ )
574
+
575
+ assert_error_message 'activerecord.errors.models.reply.attributes.title.custom', :title, :kaputt, :message => 'custom'
576
+ delete_translation :'activerecord.errors.models.reply.attributes.title.custom'
577
+
578
+ assert_error_message 'activerecord.errors.models.reply.custom', :title, :kaputt, :message => 'custom'
579
+ delete_translation :'activerecord.errors.models.reply.custom'
580
+
581
+ assert_error_message 'activerecord.errors.models.topic.attributes.title.custom', :title, :kaputt, :message => 'custom'
582
+ delete_translation :'activerecord.errors.models.topic.attributes.title.custom'
583
+
584
+ assert_error_message 'activerecord.errors.models.topic.custom', :title, :kaputt, :message => 'custom'
585
+ delete_translation :'activerecord.errors.models.topic.custom'
586
+
587
+ assert_error_message 'activerecord.errors.messages.custom', :title, :kaputt, :message => 'custom'
588
+ delete_translation :'activerecord.errors.messages.custom'
589
+
590
+ # Implementing this would clash with the AR default behaviour of using validates_foo :message => 'foo'
591
+ # as an untranslated string. I.e. at this point we can either fall back to the given string from the
592
+ # class-level macro (validates_*) or fall back to the default message for this validation type.
593
+ # assert_error_message 'activerecord.errors.messages.kaputt', :title, :kaputt, :message => 'custom'
594
+
595
+ assert_error_message 'custom', :title, :kaputt, :message => 'custom'
596
+ end
597
+
598
+ test "#generate_message key fallbacks (given a Symbol as key)" do
599
+ store_translations(
600
+ :errors => {
601
+ :models => {
602
+ :reply => {
603
+ :attributes => { :title => { :kaputt => 'activerecord.errors.models.reply.attributes.title.kaputt' } },
604
+ :kaputt => 'activerecord.errors.models.reply.kaputt'
605
+ },
606
+ :topic => {
607
+ :attributes => { :title => { :kaputt => 'activerecord.errors.models.topic.attributes.title.kaputt' } },
608
+ :kaputt => 'activerecord.errors.models.topic.kaputt'
609
+ }
610
+ },
611
+ :messages => {
612
+ :kaputt => 'activerecord.errors.messages.kaputt'
613
+ }
614
+ }
615
+ )
616
+
617
+ assert_error_message 'activerecord.errors.models.reply.attributes.title.kaputt', :title, :kaputt
618
+ delete_translation :'activerecord.errors.models.reply.attributes.title.kaputt'
619
+
620
+ assert_error_message 'activerecord.errors.models.reply.kaputt', :title, :kaputt
621
+ delete_translation :'activerecord.errors.models.reply.kaputt'
622
+
623
+ assert_error_message 'activerecord.errors.models.topic.attributes.title.kaputt', :title, :kaputt
624
+ delete_translation :'activerecord.errors.models.topic.attributes.title.kaputt'
625
+
626
+ assert_error_message 'activerecord.errors.models.topic.kaputt', :title, :kaputt
627
+ delete_translation :'activerecord.errors.models.topic.kaputt'
628
+
629
+ assert_error_message 'activerecord.errors.messages.kaputt', :title, :kaputt
630
+ end
631
+
632
+ # full_messages
633
+
634
+ test "#full_message with no format present" do
635
+ store_translations(:errors => { :messages => { :kaputt => 'is kaputt' } })
636
+ assert_full_message 'Title is kaputt', :title, :kaputt
637
+ end
638
+
639
+ test "#full_message with a format present" do
640
+ store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :format => '{{attribute}}: {{message}}' } })
641
+ assert_full_message 'Title: is kaputt', :title, :kaputt
642
+ end
643
+
644
+ test "#full_message with a type specific format present" do
645
+ store_translations(:errors => { :messages => { :kaputt => 'is kaputt' }, :full_messages => { :kaputt => '{{attribute}} {{message}}!' } })
646
+ assert_full_message 'Title is kaputt!', :title, :kaputt
647
+ end
648
+
649
+ test "#full_message with class-level specified custom message" do
650
+ store_translations(:errors => { :messages => { :broken => 'is kaputt' }, :full_messages => { :broken => '{{attribute}} {{message}}?!' } })
651
+ assert_full_message 'Title is kaputt?!', :title, :kaputt, :message => :broken
652
+ end
653
+
654
+ test "#full_message with different scope" do
655
+ store_translations(:my_errors => { :messages => { :kaputt => 'is kaputt' } })
656
+ assert_full_message 'Title is kaputt', :title, :kaputt, :scope => [:activerecord, :my_errors]
657
+
658
+ store_translations(:my_errors => { :full_messages => { :kaputt => '{{attribute}} {{message}}!' } })
659
+ assert_full_message 'Title is kaputt!', :title, :kaputt, :scope => [:activerecord, :my_errors]
660
+ end
661
+
662
+ # switch locales
663
+
664
+ test "#message allows to switch locales" do
665
+ store_translations(:en, :errors => { :messages => { :kaputt => 'is kaputt' } })
666
+ store_translations(:de, :errors => { :messages => { :kaputt => 'ist kaputt' } })
667
+
668
+ assert_error_message 'is kaputt', :title, :kaputt
669
+ I18n.locale = :de
670
+ assert_error_message 'ist kaputt', :title, :kaputt
671
+ I18n.locale = :en
672
+ assert_error_message 'is kaputt', :title, :kaputt
673
+ end
674
+
675
+ test "#full_message allows to switch locales" do
676
+ store_translations(:en, :errors => { :messages => { :kaputt => 'is kaputt' } }, :attributes => { :topic => { :title => 'The title' } })
677
+ store_translations(:de, :errors => { :messages => { :kaputt => 'ist kaputt' } }, :attributes => { :topic => { :title => 'Der Titel' } })
678
+
679
+ assert_full_message 'The title is kaputt', :title, :kaputt
680
+ I18n.locale = :de
681
+ assert_full_message 'Der Titel ist kaputt', :title, :kaputt
682
+ I18n.locale = :en
683
+ assert_full_message 'The title is kaputt', :title, :kaputt
684
+ end
685
+ end
686
+
687
+ # ACTIVERECORD DEFAULT ERROR MESSAGES
688
+ #
689
+ # * test that Error generates the default error messages
690
+
691
+ class ActiveRecordDefaultErrorMessagesI18nTests < ActiveSupport::TestCase
692
+ def assert_default_error_message(message, *args)
693
+ assert_equal message, error_message(*args)
694
+ end
695
+
696
+ def error_message(*args)
697
+ ActiveRecord::Error.new(Topic.new, :title, *args).message
698
+ end
699
+
700
+ # used by: validates_inclusion_of
701
+ test "default error message: inclusion" do
702
+ assert_default_error_message 'is not included in the list', :inclusion, :value => 'title'
703
+ end
704
+
705
+ # used by: validates_exclusion_of
706
+ test "default error message: exclusion" do
707
+ assert_default_error_message 'is reserved', :exclusion, :value => 'title'
708
+ end
709
+
710
+ # used by: validates_associated and validates_format_of
711
+ test "default error message: invalid" do
712
+ assert_default_error_message 'is invalid', :invalid, :value => 'title'
713
+ end
714
+
715
+ # used by: validates_confirmation_of
716
+ test "default error message: confirmation" do
717
+ assert_default_error_message "doesn't match confirmation", :confirmation, :default => nil
718
+ end
719
+
720
+ # used by: validates_acceptance_of
721
+ test "default error message: accepted" do
722
+ assert_default_error_message "must be accepted", :accepted
723
+ end
724
+
725
+ # used by: add_on_empty
726
+ test "default error message: empty" do
727
+ assert_default_error_message "can't be empty", :empty
728
+ end
729
+
730
+ # used by: add_on_blank
731
+ test "default error message: blank" do
732
+ assert_default_error_message "can't be blank", :blank
733
+ end
734
+
735
+ # used by: validates_length_of
736
+ test "default error message: too_long" do
737
+ assert_default_error_message "is too long (maximum is 10 characters)", :too_long, :count => 10
738
+ end
739
+
740
+ # used by: validates_length_of
741
+ test "default error message: too_short" do
742
+ assert_default_error_message "is too short (minimum is 10 characters)", :too_short, :count => 10
743
+ end
744
+
745
+ # used by: validates_length_of
746
+ test "default error message: wrong_length" do
747
+ assert_default_error_message "is the wrong length (should be 10 characters)", :wrong_length, :count => 10
748
+ end
749
+
750
+ # used by: validates_uniqueness_of
751
+ test "default error message: taken" do
752
+ assert_default_error_message "has already been taken", :taken, :value => 'title'
753
+ end
754
+
755
+ # used by: validates_numericality_of
756
+ test "default error message: not_a_number" do
757
+ assert_default_error_message "is not a number", :not_a_number, :value => 'title'
758
+ end
759
+
760
+ # used by: validates_numericality_of
761
+ test "default error message: greater_than" do
762
+ assert_default_error_message "must be greater than 10", :greater_than, :value => 'title', :count => 10
763
+ end
764
+
765
+ # used by: validates_numericality_of
766
+ test "default error message: greater_than_or_equal_to" do
767
+ assert_default_error_message "must be greater than or equal to 10", :greater_than_or_equal_to, :value => 'title', :count => 10
768
+ end
769
+
770
+ # used by: validates_numericality_of
771
+ test "default error message: equal_to" do
772
+ assert_default_error_message "must be equal to 10", :equal_to, :value => 'title', :count => 10
773
+ end
774
+
775
+ # used by: validates_numericality_of
776
+ test "default error message: less_than" do
777
+ assert_default_error_message "must be less than 10", :less_than, :value => 'title', :count => 10
778
+ end
779
+
780
+ # used by: validates_numericality_of
781
+ test "default error message: less_than_or_equal_to" do
782
+ assert_default_error_message "must be less than or equal to 10", :less_than_or_equal_to, :value => 'title', :count => 10
783
+ end
784
+
785
+ # used by: validates_numericality_of
786
+ test "default error message: odd" do
787
+ assert_default_error_message "must be odd", :odd, :value => 'title', :count => 10
788
+ end
789
+
790
+ # used by: validates_numericality_of
791
+ test "default error message: even" do
792
+ assert_default_error_message "must be even", :even, :value => 'title', :count => 10
793
+ end
794
+
795
+ test "custom message string interpolation" do
796
+ assert_equal 'custom message title', error_message(:invalid, :default => 'custom message {{value}}', :value => 'title')
797
+ end
798
+ end
799
+
800
+ # ACTIVERECORD VALIDATION ERROR MESSAGES - FULL STACK
801
+ #
802
+ # * test a few combinations full stack to ensure the tests above are correct
803
+
804
+ class I18nPerson < Person
805
+ end
806
+
807
+ class ActiveRecordValidationsI18nFullStackTests < ActiveSupport::TestCase
808
+ include ActiveRecordValidationsI18nTestHelper
809
+
810
+ def setup
811
+ reset_callbacks(I18nPerson)
812
+ @old_backend, I18n.backend = I18n.backend, I18n::Backend::Simple.new
813
+ @person = I18nPerson.new
814
+ end
815
+
816
+ def teardown
817
+ reset_callbacks(I18nPerson)
818
+ I18n.backend = @old_backend
819
+ end
820
+
821
+ def assert_name_invalid(message)
822
+ yield
823
+ @person.valid?
824
+ assert_equal message, @person.errors.on(:name)
825
+ end
826
+
827
+ # Symbols as class-level validation messages
828
+
829
+ test "Symbol as class level validation message translated per attribute (translation on child class)" do
830
+ assert_name_invalid("is broken") do
831
+ store_translations :errors => {:models => {:i18n_person => {:attributes => {:name => {:broken => "is broken"}}}}}
832
+ I18nPerson.validates_presence_of :name, :message => :broken
833
+ end
834
+ end
835
+
836
+ test "Symbol as class level validation message translated per attribute (translation on base class)" do
837
+ assert_name_invalid("is broken") do
838
+ store_translations :errors => {:models => {:person => {:attributes => {:name => {:broken => "is broken"}}}}}
839
+ I18nPerson.validates_presence_of :name, :message => :broken
840
+ end
841
+ end
842
+
843
+ test "Symbol as class level validation message translated per model (translation on child class)" do
844
+ assert_name_invalid("is broken") do
845
+ store_translations :errors => {:models => {:i18n_person => {:broken => "is broken"}}}
846
+ I18nPerson.validates_presence_of :name, :message => :broken
847
+ end
848
+ end
849
+
850
+ test "Symbol as class level validation message translated per model (translation on base class)" do
851
+ assert_name_invalid("is broken") do
852
+ store_translations :errors => {:models => {:person => {:broken => "is broken"}}}
853
+ I18nPerson.validates_presence_of :name, :message => :broken
854
+ end
855
+ end
856
+
857
+ test "Symbol as class level validation message translated as error message" do
858
+ assert_name_invalid("is broken") do
859
+ store_translations :errors => {:messages => {:broken => "is broken"}}
860
+ I18nPerson.validates_presence_of :name, :message => :broken
861
+ end
862
+ end
863
+
864
+ # Strings as class-level validation messages
865
+
866
+ test "String as class level validation message translated per attribute (translation on child class)" do
867
+ assert_name_invalid("is broken") do
868
+ store_translations :errors => {:models => {:i18n_person => {:attributes => {:name => {"is broken" => "is broken"}}}}}
869
+ I18nPerson.validates_presence_of :name, :message => "is broken"
870
+ end
871
+ end
872
+
873
+ test "String as class level validation message translated per attribute (translation on base class)" do
874
+ assert_name_invalid("is broken") do
875
+ store_translations :errors => {:models => {:person => {:attributes => {:name => {"is broken" => "is broken"}}}}}
876
+ I18nPerson.validates_presence_of :name, :message => "is broken"
877
+ end
878
+ end
879
+
880
+ test "String as class level validation message translated per model (translation on child class)" do
881
+ assert_name_invalid("is broken") do
882
+ store_translations :errors => {:models => {:i18n_person => {"is broken" => "is broken"}}}
883
+ I18nPerson.validates_presence_of :name, :message => "is broken"
884
+ end
885
+ end
886
+
887
+ test "String as class level validation message translated per model (translation on base class)" do
888
+ assert_name_invalid("is broken") do
889
+ store_translations :errors => {:models => {:person => {"is broken" => "is broken"}}}
890
+ I18nPerson.validates_presence_of :name, :message => "is broken"
891
+ end
892
+ end
893
+
894
+ test "String as class level validation message translated as error message" do
895
+ assert_name_invalid("is broken") do
896
+ store_translations :errors => {:messages => {"is broken" => "is broken"}}
897
+ I18nPerson.validates_presence_of :name, :message => "is broken"
898
+ end
899
+ end
900
+
901
+ test "String as class level validation message not translated (uses message as default)" do
902
+ assert_name_invalid("is broken!") do
903
+ I18nPerson.validates_presence_of :name, :message => "is broken!"
904
+ end
905
+ end
906
+ end
907
+
908
+ class ActiveRecordValidationsI18nFullMessagesFullStackTests < ActiveSupport::TestCase
909
+ include ActiveRecordValidationsI18nTestHelper
910
+
911
+ def setup
912
+ reset_callbacks(I18nPerson)
913
+ @old_backend, I18n.backend = I18n.backend, I18n::Backend::Simple.new
914
+ @person = I18nPerson.new
915
+ end
916
+
917
+ def teardown
918
+ reset_callbacks(I18nPerson)
919
+ I18n.backend = @old_backend
920
+ end
921
+
922
+ def assert_full_message(message)
923
+ yield
924
+ @person.valid?
925
+ assert_equal message, @person.errors.full_messages.join
926
+ end
927
+
928
+ test "full_message format stored per custom error message key" do
929
+ assert_full_message("Name is broken!") do
930
+ store_translations :errors => { :messages => { :broken => 'is broken' }, :full_messages => { :broken => '{{attribute}} {{message}}!' } }
931
+ I18nPerson.validates_presence_of :name, :message => :broken
932
+ end
933
+ end
934
+
935
+ test "full_message format stored per error type" do
936
+ assert_full_message("Name can't be blank!") do
937
+ store_translations :errors => { :full_messages => { :blank => '{{attribute}} {{message}}!' } }
938
+ I18nPerson.validates_presence_of :name
939
+ end
940
+ end
941
+ # ActiveRecord#RecordInvalid exception
942
+
943
+ test "full_message format stored as default" do
944
+ assert_full_message("Name: can't be blank") do
945
+ store_translations :errors => { :full_messages => { :format => '{{attribute}}: {{message}}' } }
946
+ I18nPerson.validates_presence_of :name
947
+ end
948
+ end
949
+ test "RecordInvalid exception can be localized" do
950
+ topic = Topic.new
951
+ topic.errors.add(:title, :invalid)
952
+ topic.errors.add(:title, :blank)
953
+ assert_equal "Validation failed: Title is invalid, Title can't be blank", ActiveRecord::RecordInvalid.new(topic).message
954
+ end
955
+ end