activerecord_csi 2.3.5.p6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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