activerecord 2.3.18 → 3.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (378) hide show
  1. data/CHANGELOG +105 -34
  2. data/examples/performance.rb +3 -39
  3. data/examples/simple.rb +14 -0
  4. data/lib/active_record.rb +81 -47
  5. data/lib/active_record/aggregations.rb +1 -3
  6. data/lib/active_record/association_preload.rb +39 -54
  7. data/lib/active_record/associations.rb +262 -419
  8. data/lib/active_record/associations/association_collection.rb +85 -100
  9. data/lib/active_record/associations/association_proxy.rb +20 -18
  10. data/lib/active_record/associations/belongs_to_association.rb +8 -8
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -35
  12. data/lib/active_record/associations/has_many_association.rb +11 -19
  13. data/lib/active_record/associations/has_many_through_association.rb +30 -183
  14. data/lib/active_record/associations/has_one_association.rb +10 -10
  15. data/lib/active_record/associations/has_one_through_association.rb +13 -11
  16. data/lib/active_record/associations/through_association_scope.rb +153 -0
  17. data/lib/active_record/attribute_methods.rb +17 -370
  18. data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
  19. data/lib/active_record/attribute_methods/dirty.rb +87 -0
  20. data/lib/active_record/attribute_methods/primary_key.rb +44 -0
  21. data/lib/active_record/attribute_methods/query.rb +37 -0
  22. data/lib/active_record/attribute_methods/read.rb +116 -0
  23. data/lib/active_record/attribute_methods/time_zone_conversion.rb +60 -0
  24. data/lib/active_record/attribute_methods/write.rb +37 -0
  25. data/lib/active_record/autosave_association.rb +20 -41
  26. data/lib/active_record/base.rb +357 -1180
  27. data/lib/active_record/batches.rb +10 -16
  28. data/lib/active_record/callbacks.rb +66 -126
  29. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +17 -13
  30. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +5 -25
  31. data/lib/active_record/connection_adapters/abstract/database_statements.rb +4 -43
  32. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -2
  33. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -4
  34. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  35. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -72
  36. data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -49
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +15 -27
  38. data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -46
  39. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +9 -3
  40. data/lib/active_record/connection_adapters/sqlite_adapter.rb +34 -65
  41. data/lib/active_record/fixtures.rb +21 -25
  42. data/lib/active_record/locale/en.yml +9 -27
  43. data/lib/active_record/locking/optimistic.rb +16 -48
  44. data/lib/active_record/migration.rb +59 -46
  45. data/lib/active_record/named_scope.rb +85 -92
  46. data/lib/active_record/nested_attributes.rb +18 -24
  47. data/lib/active_record/observer.rb +18 -94
  48. data/lib/active_record/railtie.rb +83 -0
  49. data/lib/active_record/railties/controller_runtime.rb +38 -0
  50. data/lib/active_record/railties/databases.rake +477 -0
  51. data/lib/active_record/railties/subscriber.rb +27 -0
  52. data/lib/active_record/reflection.rb +2 -15
  53. data/lib/active_record/relation.rb +339 -0
  54. data/lib/active_record/relation/calculations.rb +259 -0
  55. data/lib/active_record/relation/finder_methods.rb +315 -0
  56. data/lib/active_record/relation/predicate_builder.rb +46 -0
  57. data/lib/active_record/relation/query_methods.rb +218 -0
  58. data/lib/active_record/relation/spawn_methods.rb +102 -0
  59. data/lib/active_record/schema_dumper.rb +10 -6
  60. data/lib/active_record/serialization.rb +31 -74
  61. data/lib/active_record/serializers/xml_serializer.rb +33 -121
  62. data/lib/active_record/session_store.rb +1 -9
  63. data/lib/active_record/test_case.rb +1 -3
  64. data/lib/active_record/timestamp.rb +7 -5
  65. data/lib/active_record/transactions.rb +9 -9
  66. data/lib/active_record/validations.rb +51 -1100
  67. data/lib/active_record/validations/associated.rb +47 -0
  68. data/lib/active_record/validations/uniqueness.rb +181 -0
  69. data/lib/active_record/version.rb +3 -3
  70. data/lib/generators/active_record.rb +30 -0
  71. data/lib/generators/active_record/migration/migration_generator.rb +25 -0
  72. data/lib/generators/active_record/migration/templates/migration.rb +11 -0
  73. data/lib/generators/active_record/model/model_generator.rb +33 -0
  74. data/lib/generators/active_record/model/templates/migration.rb +16 -0
  75. data/lib/generators/active_record/model/templates/model.rb +5 -0
  76. data/lib/generators/active_record/observer/observer_generator.rb +15 -0
  77. data/lib/generators/active_record/observer/templates/observer.rb +2 -0
  78. data/lib/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  79. data/lib/generators/active_record/session_migration/templates/migration.rb +16 -0
  80. metadata +67 -325
  81. data/RUNNING_UNIT_TESTS +0 -36
  82. data/Rakefile +0 -268
  83. data/install.rb +0 -30
  84. data/lib/active_record/calculations.rb +0 -321
  85. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -57
  86. data/lib/active_record/dirty.rb +0 -183
  87. data/lib/active_record/serializers/json_serializer.rb +0 -91
  88. data/lib/activerecord.rb +0 -2
  89. data/test/assets/example.log +0 -1
  90. data/test/assets/flowers.jpg +0 -0
  91. data/test/cases/aaa_create_tables_test.rb +0 -24
  92. data/test/cases/active_schema_test_mysql.rb +0 -122
  93. data/test/cases/active_schema_test_postgresql.rb +0 -24
  94. data/test/cases/adapter_test.rb +0 -144
  95. data/test/cases/aggregations_test.rb +0 -167
  96. data/test/cases/ar_schema_test.rb +0 -32
  97. data/test/cases/associations/belongs_to_associations_test.rb +0 -438
  98. data/test/cases/associations/callbacks_test.rb +0 -161
  99. data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
  100. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
  101. data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
  102. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
  103. data/test/cases/associations/eager_singularization_test.rb +0 -145
  104. data/test/cases/associations/eager_test.rb +0 -852
  105. data/test/cases/associations/extension_test.rb +0 -62
  106. data/test/cases/associations/habtm_join_table_test.rb +0 -56
  107. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
  108. data/test/cases/associations/has_many_associations_test.rb +0 -1273
  109. data/test/cases/associations/has_many_through_associations_test.rb +0 -360
  110. data/test/cases/associations/has_one_associations_test.rb +0 -330
  111. data/test/cases/associations/has_one_through_associations_test.rb +0 -209
  112. data/test/cases/associations/inner_join_association_test.rb +0 -93
  113. data/test/cases/associations/inverse_associations_test.rb +0 -566
  114. data/test/cases/associations/join_model_test.rb +0 -712
  115. data/test/cases/associations_test.rb +0 -282
  116. data/test/cases/attribute_methods_test.rb +0 -305
  117. data/test/cases/autosave_association_test.rb +0 -1218
  118. data/test/cases/base_test.rb +0 -2166
  119. data/test/cases/batches_test.rb +0 -81
  120. data/test/cases/binary_test.rb +0 -30
  121. data/test/cases/calculations_test.rb +0 -360
  122. data/test/cases/callbacks_observers_test.rb +0 -38
  123. data/test/cases/callbacks_test.rb +0 -438
  124. data/test/cases/class_inheritable_attributes_test.rb +0 -32
  125. data/test/cases/column_alias_test.rb +0 -17
  126. data/test/cases/column_definition_test.rb +0 -70
  127. data/test/cases/connection_pool_test.rb +0 -25
  128. data/test/cases/connection_test_firebird.rb +0 -8
  129. data/test/cases/connection_test_mysql.rb +0 -65
  130. data/test/cases/copy_table_test_sqlite.rb +0 -80
  131. data/test/cases/counter_cache_test.rb +0 -84
  132. data/test/cases/database_statements_test.rb +0 -12
  133. data/test/cases/datatype_test_postgresql.rb +0 -204
  134. data/test/cases/date_time_test.rb +0 -37
  135. data/test/cases/default_test_firebird.rb +0 -16
  136. data/test/cases/defaults_test.rb +0 -111
  137. data/test/cases/deprecated_finder_test.rb +0 -30
  138. data/test/cases/dirty_test.rb +0 -316
  139. data/test/cases/finder_respond_to_test.rb +0 -76
  140. data/test/cases/finder_test.rb +0 -1098
  141. data/test/cases/fixtures_test.rb +0 -661
  142. data/test/cases/helper.rb +0 -68
  143. data/test/cases/i18n_test.rb +0 -46
  144. data/test/cases/inheritance_test.rb +0 -262
  145. data/test/cases/invalid_date_test.rb +0 -24
  146. data/test/cases/json_serialization_test.rb +0 -219
  147. data/test/cases/lifecycle_test.rb +0 -193
  148. data/test/cases/locking_test.rb +0 -350
  149. data/test/cases/method_scoping_test.rb +0 -704
  150. data/test/cases/migration_test.rb +0 -1649
  151. data/test/cases/migration_test_firebird.rb +0 -124
  152. data/test/cases/mixin_test.rb +0 -96
  153. data/test/cases/modules_test.rb +0 -109
  154. data/test/cases/multiple_db_test.rb +0 -85
  155. data/test/cases/named_scope_test.rb +0 -372
  156. data/test/cases/nested_attributes_test.rb +0 -840
  157. data/test/cases/pk_test.rb +0 -119
  158. data/test/cases/pooled_connections_test.rb +0 -103
  159. data/test/cases/query_cache_test.rb +0 -129
  160. data/test/cases/readonly_test.rb +0 -107
  161. data/test/cases/reflection_test.rb +0 -234
  162. data/test/cases/reload_models_test.rb +0 -22
  163. data/test/cases/repair_helper.rb +0 -50
  164. data/test/cases/reserved_word_test_mysql.rb +0 -176
  165. data/test/cases/sanitize_test.rb +0 -25
  166. data/test/cases/schema_authorization_test_postgresql.rb +0 -75
  167. data/test/cases/schema_dumper_test.rb +0 -211
  168. data/test/cases/schema_test_postgresql.rb +0 -178
  169. data/test/cases/serialization_test.rb +0 -47
  170. data/test/cases/sp_test_mysql.rb +0 -16
  171. data/test/cases/synonym_test_oracle.rb +0 -17
  172. data/test/cases/timestamp_test.rb +0 -75
  173. data/test/cases/transactions_test.rb +0 -543
  174. data/test/cases/unconnected_test.rb +0 -32
  175. data/test/cases/validations_i18n_test.rb +0 -925
  176. data/test/cases/validations_test.rb +0 -1684
  177. data/test/cases/xml_serialization_test.rb +0 -240
  178. data/test/cases/yaml_serialization_test.rb +0 -11
  179. data/test/config.rb +0 -5
  180. data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
  181. data/test/connections/jdbc_jdbch2/connection.rb +0 -18
  182. data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
  183. data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
  184. data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
  185. data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
  186. data/test/connections/native_db2/connection.rb +0 -25
  187. data/test/connections/native_firebird/connection.rb +0 -26
  188. data/test/connections/native_frontbase/connection.rb +0 -27
  189. data/test/connections/native_mysql/connection.rb +0 -25
  190. data/test/connections/native_openbase/connection.rb +0 -21
  191. data/test/connections/native_oracle/connection.rb +0 -27
  192. data/test/connections/native_postgresql/connection.rb +0 -21
  193. data/test/connections/native_sqlite/connection.rb +0 -25
  194. data/test/connections/native_sqlite3/connection.rb +0 -25
  195. data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
  196. data/test/connections/native_sybase/connection.rb +0 -23
  197. data/test/fixtures/accounts.yml +0 -29
  198. data/test/fixtures/all/developers.yml +0 -0
  199. data/test/fixtures/all/people.csv +0 -0
  200. data/test/fixtures/all/tasks.yml +0 -0
  201. data/test/fixtures/author_addresses.yml +0 -5
  202. data/test/fixtures/author_favorites.yml +0 -4
  203. data/test/fixtures/authors.yml +0 -9
  204. data/test/fixtures/binaries.yml +0 -132
  205. data/test/fixtures/books.yml +0 -7
  206. data/test/fixtures/categories.yml +0 -14
  207. data/test/fixtures/categories/special_categories.yml +0 -9
  208. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
  209. data/test/fixtures/categories_ordered.yml +0 -7
  210. data/test/fixtures/categories_posts.yml +0 -23
  211. data/test/fixtures/categorizations.yml +0 -17
  212. data/test/fixtures/clubs.yml +0 -6
  213. data/test/fixtures/comments.yml +0 -59
  214. data/test/fixtures/companies.yml +0 -56
  215. data/test/fixtures/computers.yml +0 -4
  216. data/test/fixtures/courses.yml +0 -7
  217. data/test/fixtures/customers.yml +0 -26
  218. data/test/fixtures/developers.yml +0 -21
  219. data/test/fixtures/developers_projects.yml +0 -17
  220. data/test/fixtures/edges.yml +0 -6
  221. data/test/fixtures/entrants.yml +0 -14
  222. data/test/fixtures/faces.yml +0 -11
  223. data/test/fixtures/fk_test_has_fk.yml +0 -3
  224. data/test/fixtures/fk_test_has_pk.yml +0 -2
  225. data/test/fixtures/funny_jokes.yml +0 -10
  226. data/test/fixtures/interests.yml +0 -33
  227. data/test/fixtures/items.yml +0 -4
  228. data/test/fixtures/jobs.yml +0 -7
  229. data/test/fixtures/legacy_things.yml +0 -3
  230. data/test/fixtures/mateys.yml +0 -4
  231. data/test/fixtures/member_types.yml +0 -6
  232. data/test/fixtures/members.yml +0 -6
  233. data/test/fixtures/memberships.yml +0 -20
  234. data/test/fixtures/men.yml +0 -5
  235. data/test/fixtures/minimalistics.yml +0 -2
  236. data/test/fixtures/mixed_case_monkeys.yml +0 -6
  237. data/test/fixtures/mixins.yml +0 -29
  238. data/test/fixtures/movies.yml +0 -7
  239. data/test/fixtures/naked/csv/accounts.csv +0 -1
  240. data/test/fixtures/naked/yml/accounts.yml +0 -1
  241. data/test/fixtures/naked/yml/companies.yml +0 -1
  242. data/test/fixtures/naked/yml/courses.yml +0 -1
  243. data/test/fixtures/organizations.yml +0 -5
  244. data/test/fixtures/owners.yml +0 -7
  245. data/test/fixtures/parrots.yml +0 -27
  246. data/test/fixtures/parrots_pirates.yml +0 -7
  247. data/test/fixtures/people.yml +0 -15
  248. data/test/fixtures/pets.yml +0 -14
  249. data/test/fixtures/pirates.yml +0 -9
  250. data/test/fixtures/polymorphic_designs.yml +0 -19
  251. data/test/fixtures/polymorphic_prices.yml +0 -19
  252. data/test/fixtures/posts.yml +0 -52
  253. data/test/fixtures/price_estimates.yml +0 -7
  254. data/test/fixtures/projects.yml +0 -7
  255. data/test/fixtures/readers.yml +0 -9
  256. data/test/fixtures/references.yml +0 -17
  257. data/test/fixtures/reserved_words/distinct.yml +0 -5
  258. data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
  259. data/test/fixtures/reserved_words/group.yml +0 -14
  260. data/test/fixtures/reserved_words/select.yml +0 -8
  261. data/test/fixtures/reserved_words/values.yml +0 -7
  262. data/test/fixtures/ships.yml +0 -5
  263. data/test/fixtures/sponsors.yml +0 -9
  264. data/test/fixtures/subscribers.yml +0 -7
  265. data/test/fixtures/subscriptions.yml +0 -12
  266. data/test/fixtures/taggings.yml +0 -28
  267. data/test/fixtures/tags.yml +0 -7
  268. data/test/fixtures/tasks.yml +0 -7
  269. data/test/fixtures/tees.yml +0 -4
  270. data/test/fixtures/ties.yml +0 -4
  271. data/test/fixtures/topics.yml +0 -42
  272. data/test/fixtures/toys.yml +0 -4
  273. data/test/fixtures/treasures.yml +0 -10
  274. data/test/fixtures/vertices.yml +0 -4
  275. data/test/fixtures/warehouse-things.yml +0 -3
  276. data/test/fixtures/zines.yml +0 -5
  277. data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
  278. data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
  279. data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
  280. data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
  281. data/test/migrations/duplicate/3_foo.rb +0 -7
  282. data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
  283. data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
  284. data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
  285. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
  286. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
  287. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
  288. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
  289. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
  290. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
  291. data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
  292. data/test/migrations/missing/1_people_have_last_names.rb +0 -9
  293. data/test/migrations/missing/3_we_need_reminders.rb +0 -12
  294. data/test/migrations/missing/4_innocent_jointable.rb +0 -12
  295. data/test/migrations/valid/1_people_have_last_names.rb +0 -9
  296. data/test/migrations/valid/2_we_need_reminders.rb +0 -12
  297. data/test/migrations/valid/3_innocent_jointable.rb +0 -12
  298. data/test/models/author.rb +0 -151
  299. data/test/models/auto_id.rb +0 -4
  300. data/test/models/binary.rb +0 -2
  301. data/test/models/bird.rb +0 -9
  302. data/test/models/book.rb +0 -4
  303. data/test/models/categorization.rb +0 -5
  304. data/test/models/category.rb +0 -34
  305. data/test/models/citation.rb +0 -6
  306. data/test/models/club.rb +0 -13
  307. data/test/models/column_name.rb +0 -3
  308. data/test/models/comment.rb +0 -29
  309. data/test/models/company.rb +0 -173
  310. data/test/models/company_in_module.rb +0 -78
  311. data/test/models/computer.rb +0 -3
  312. data/test/models/contact.rb +0 -16
  313. data/test/models/contract.rb +0 -5
  314. data/test/models/course.rb +0 -3
  315. data/test/models/customer.rb +0 -73
  316. data/test/models/default.rb +0 -2
  317. data/test/models/developer.rb +0 -101
  318. data/test/models/edge.rb +0 -5
  319. data/test/models/entrant.rb +0 -3
  320. data/test/models/essay.rb +0 -3
  321. data/test/models/event.rb +0 -3
  322. data/test/models/event_author.rb +0 -8
  323. data/test/models/face.rb +0 -7
  324. data/test/models/guid.rb +0 -2
  325. data/test/models/interest.rb +0 -5
  326. data/test/models/invoice.rb +0 -4
  327. data/test/models/item.rb +0 -7
  328. data/test/models/job.rb +0 -5
  329. data/test/models/joke.rb +0 -3
  330. data/test/models/keyboard.rb +0 -3
  331. data/test/models/legacy_thing.rb +0 -3
  332. data/test/models/line_item.rb +0 -3
  333. data/test/models/man.rb +0 -9
  334. data/test/models/matey.rb +0 -4
  335. data/test/models/member.rb +0 -12
  336. data/test/models/member_detail.rb +0 -5
  337. data/test/models/member_type.rb +0 -3
  338. data/test/models/membership.rb +0 -9
  339. data/test/models/minimalistic.rb +0 -2
  340. data/test/models/mixed_case_monkey.rb +0 -3
  341. data/test/models/movie.rb +0 -5
  342. data/test/models/order.rb +0 -4
  343. data/test/models/organization.rb +0 -6
  344. data/test/models/owner.rb +0 -5
  345. data/test/models/parrot.rb +0 -22
  346. data/test/models/person.rb +0 -16
  347. data/test/models/pet.rb +0 -5
  348. data/test/models/pirate.rb +0 -80
  349. data/test/models/polymorphic_design.rb +0 -3
  350. data/test/models/polymorphic_price.rb +0 -3
  351. data/test/models/post.rb +0 -102
  352. data/test/models/price_estimate.rb +0 -3
  353. data/test/models/project.rb +0 -30
  354. data/test/models/reader.rb +0 -4
  355. data/test/models/reference.rb +0 -4
  356. data/test/models/reply.rb +0 -46
  357. data/test/models/ship.rb +0 -19
  358. data/test/models/ship_part.rb +0 -7
  359. data/test/models/sponsor.rb +0 -4
  360. data/test/models/subject.rb +0 -4
  361. data/test/models/subscriber.rb +0 -8
  362. data/test/models/subscription.rb +0 -4
  363. data/test/models/tag.rb +0 -7
  364. data/test/models/tagging.rb +0 -10
  365. data/test/models/task.rb +0 -3
  366. data/test/models/tee.rb +0 -4
  367. data/test/models/tie.rb +0 -4
  368. data/test/models/topic.rb +0 -80
  369. data/test/models/toy.rb +0 -6
  370. data/test/models/treasure.rb +0 -8
  371. data/test/models/vertex.rb +0 -9
  372. data/test/models/warehouse_thing.rb +0 -5
  373. data/test/models/zine.rb +0 -3
  374. data/test/schema/mysql_specific_schema.rb +0 -31
  375. data/test/schema/postgresql_specific_schema.rb +0 -114
  376. data/test/schema/schema.rb +0 -550
  377. data/test/schema/schema2.rb +0 -6
  378. data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -1,1684 +0,0 @@
1
- # encoding: utf-8
2
- require "cases/helper"
3
- require 'models/topic'
4
- require 'models/reply'
5
- require 'models/person'
6
- require 'models/developer'
7
- require 'models/warehouse_thing'
8
- require 'models/guid'
9
- require 'models/owner'
10
- require 'models/pet'
11
- require 'models/event'
12
- require 'models/man'
13
- require 'models/interest'
14
-
15
- # The following methods in Topic are used in test_conditional_validation_*
16
- class Topic
17
- has_many :unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
18
- has_many :silly_unique_replies, :dependent => :destroy, :foreign_key => "parent_id"
19
-
20
- def condition_is_true
21
- true
22
- end
23
-
24
- def condition_is_true_but_its_not
25
- false
26
- end
27
- end
28
-
29
- class ProtectedPerson < ActiveRecord::Base
30
- set_table_name 'people'
31
- attr_accessor :addon
32
- attr_protected :first_name
33
-
34
- def special_error
35
- this_method_does_not_exist!
36
- rescue
37
- errors.add(:special_error, "This method does not exist")
38
- end
39
- end
40
-
41
- class UniqueReply < Reply
42
- validates_uniqueness_of :content, :scope => 'parent_id'
43
- end
44
-
45
- class SillyUniqueReply < UniqueReply
46
- end
47
-
48
- class Wizard < ActiveRecord::Base
49
- self.abstract_class = true
50
-
51
- validates_uniqueness_of :name
52
- end
53
-
54
- class IneptWizard < Wizard
55
- validates_uniqueness_of :city
56
- end
57
-
58
- class Conjurer < IneptWizard
59
- end
60
-
61
- class Thaumaturgist < IneptWizard
62
- end
63
-
64
-
65
- class ValidationsTest < ActiveRecord::TestCase
66
- fixtures :topics, :developers, 'warehouse-things'
67
-
68
- # Most of the tests mess with the validations of Topic, so lets repair it all the time.
69
- # Other classes we mess with will be dealt with in the specific tests
70
- repair_validations(Topic)
71
-
72
- def test_single_field_validation
73
- r = Reply.new
74
- r.title = "There's no content!"
75
- assert !r.valid?, "A reply without content shouldn't be saveable"
76
-
77
- r.content = "Messa content!"
78
- assert r.valid?, "A reply with content should be saveable"
79
- end
80
-
81
- def test_single_attr_validation_and_error_msg
82
- r = Reply.new
83
- r.title = "There's no content!"
84
- assert !r.valid?
85
- assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
86
- assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
87
- assert_equal 1, r.errors.count
88
- end
89
-
90
- def test_double_attr_validation_and_error_msg
91
- r = Reply.new
92
- assert !r.valid?
93
-
94
- assert r.errors.invalid?("title"), "A reply without title should mark that attribute as invalid"
95
- assert_equal "Empty", r.errors.on("title"), "A reply without title should contain an error"
96
-
97
- assert r.errors.invalid?("content"), "A reply without content should mark that attribute as invalid"
98
- assert_equal "Empty", r.errors.on("content"), "A reply without content should contain an error"
99
-
100
- assert_equal 2, r.errors.count
101
- end
102
-
103
- def test_error_on_create
104
- r = Reply.new
105
- r.title = "Wrong Create"
106
- assert !r.valid?
107
- assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
108
- assert_equal "is Wrong Create", r.errors.on("title"), "A reply with a bad content should contain an error"
109
- end
110
-
111
- def test_error_on_update
112
- r = Reply.new
113
- r.title = "Bad"
114
- r.content = "Good"
115
- assert r.save, "First save should be successful"
116
-
117
- r.title = "Wrong Update"
118
- assert !r.save, "Second save should fail"
119
-
120
- assert r.errors.invalid?("title"), "A reply with a bad title should mark that attribute as invalid"
121
- assert_equal "is Wrong Update", r.errors.on("title"), "A reply with a bad content should contain an error"
122
- end
123
-
124
- def test_invalid_record_exception
125
- assert_raise(ActiveRecord::RecordInvalid) { Reply.create! }
126
- assert_raise(ActiveRecord::RecordInvalid) { Reply.new.save! }
127
-
128
- begin
129
- r = Reply.new
130
- r.save!
131
- flunk
132
- rescue ActiveRecord::RecordInvalid => invalid
133
- assert_equal r, invalid.record
134
- end
135
- end
136
-
137
- def test_exception_on_create_bang_many
138
- assert_raise(ActiveRecord::RecordInvalid) do
139
- Reply.create!([ { "title" => "OK" }, { "title" => "Wrong Create" }])
140
- end
141
- end
142
-
143
- def test_exception_on_create_bang_with_block
144
- assert_raise(ActiveRecord::RecordInvalid) do
145
- Reply.create!({ "title" => "OK" }) do |r|
146
- r.content = nil
147
- end
148
- end
149
- end
150
-
151
- def test_exception_on_create_bang_many_with_block
152
- assert_raise(ActiveRecord::RecordInvalid) do
153
- Reply.create!([{ "title" => "OK" }, { "title" => "Wrong Create" }]) do |r|
154
- r.content = nil
155
- end
156
- end
157
- end
158
-
159
- def test_scoped_create_without_attributes
160
- Reply.with_scope(:create => {}) do
161
- assert_raise(ActiveRecord::RecordInvalid) { Reply.create! }
162
- end
163
- end
164
-
165
- def test_create_with_exceptions_using_scope_for_protected_attributes
166
- assert_nothing_raised do
167
- ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
168
- person = ProtectedPerson.create! :addon => "Addon"
169
- assert_equal person.first_name, "Mary", "scope should ignore attr_protected"
170
- end
171
- end
172
- end
173
-
174
- def test_create_with_exceptions_using_scope_and_empty_attributes
175
- assert_nothing_raised do
176
- ProtectedPerson.with_scope( :create => { :first_name => "Mary" } ) do
177
- person = ProtectedPerson.create!
178
- assert_equal person.first_name, "Mary", "should be ok when no attributes are passed to create!"
179
- end
180
- end
181
- end
182
-
183
- def test_values_are_not_retrieved_unless_needed
184
- assert_nothing_raised do
185
- person = ProtectedPerson.new
186
- person.special_error
187
- assert_equal "This method does not exist", person.errors[:special_error]
188
- end
189
- end
190
-
191
- def test_single_error_string_per_attr_iteration
192
- r = Reply.new
193
- r.save
194
-
195
- errors = []
196
- r.errors.each { |attr, msg| errors << [attr, msg] }
197
-
198
- assert errors.include?(["title", "Empty"])
199
- assert errors.include?(["content", "Empty"])
200
- end
201
-
202
- def test_single_error_object_per_attr_iteration
203
- r = Reply.new
204
- r.save
205
-
206
- errors = []
207
- r.errors.each_error { |attr, error| errors << [attr, error.attribute] }
208
-
209
- assert errors.include?(["title", "title"])
210
- assert errors.include?(["content", "content"])
211
- end
212
-
213
- def test_multiple_errors_per_attr_iteration_with_full_error_composition
214
- r = Reply.new
215
- r.title = "Wrong Create"
216
- r.content = "Mismatch"
217
- r.save
218
-
219
- errors = []
220
- r.errors.each_full { |error| errors << error }
221
-
222
- assert_equal "Title is Wrong Create", errors[0]
223
- assert_equal "Title is Content Mismatch", errors[1]
224
- assert_equal 2, r.errors.count
225
- end
226
-
227
- def test_errors_on_base
228
- r = Reply.new
229
- r.content = "Mismatch"
230
- r.save
231
- r.errors.add_to_base "Reply is not dignifying"
232
-
233
- errors = []
234
- r.errors.each_full { |error| errors << error }
235
-
236
- assert_equal "Reply is not dignifying", r.errors.on_base
237
-
238
- assert errors.include?("Title Empty")
239
- assert errors.include?("Reply is not dignifying")
240
- assert_equal 2, r.errors.count
241
- end
242
-
243
- def test_create_without_validation
244
- reply = Reply.new
245
- assert !reply.save
246
- assert reply.save(false)
247
- end
248
-
249
- def test_create_without_validation_bang
250
- count = Reply.count
251
- assert_nothing_raised { Reply.new.save_without_validation! }
252
- assert count+1, Reply.count
253
- end
254
-
255
- def test_validates_each
256
- hits = 0
257
- Topic.validates_each(:title, :content, [:title, :content]) do |record, attr|
258
- record.errors.add attr, 'gotcha'
259
- hits += 1
260
- end
261
- t = Topic.new("title" => "valid", "content" => "whatever")
262
- assert !t.save
263
- assert_equal 4, hits
264
- assert_equal %w(gotcha gotcha), t.errors.on(:title)
265
- assert_equal %w(gotcha gotcha), t.errors.on(:content)
266
- end
267
-
268
- def test_no_title_confirmation
269
- Topic.validates_confirmation_of(:title)
270
-
271
- t = Topic.new(:author_name => "Plutarch")
272
- assert t.valid?
273
-
274
- t.title_confirmation = "Parallel Lives"
275
- assert !t.valid?
276
-
277
- t.title_confirmation = nil
278
- t.title = "Parallel Lives"
279
- assert t.valid?
280
-
281
- t.title_confirmation = "Parallel Lives"
282
- assert t.valid?
283
- end
284
-
285
- def test_title_confirmation
286
- Topic.validates_confirmation_of(:title)
287
-
288
- t = Topic.create("title" => "We should be confirmed","title_confirmation" => "")
289
- assert !t.save
290
-
291
- t.title_confirmation = "We should be confirmed"
292
- assert t.save
293
- end
294
-
295
- def test_terms_of_service_agreement_no_acceptance
296
- Topic.validates_acceptance_of(:terms_of_service, :on => :create)
297
-
298
- t = Topic.create("title" => "We should not be confirmed")
299
- assert t.save
300
- end
301
-
302
- def test_terms_of_service_agreement
303
- Topic.validates_acceptance_of(:terms_of_service, :on => :create)
304
-
305
- t = Topic.create("title" => "We should be confirmed","terms_of_service" => "")
306
- assert !t.save
307
- assert_equal "must be accepted", t.errors.on(:terms_of_service)
308
-
309
- t.terms_of_service = "1"
310
- assert t.save
311
- end
312
-
313
-
314
- def test_eula
315
- Topic.validates_acceptance_of(:eula, :message => "must be abided", :on => :create)
316
-
317
- t = Topic.create("title" => "We should be confirmed","eula" => "")
318
- assert !t.save
319
- assert_equal "must be abided", t.errors.on(:eula)
320
-
321
- t.eula = "1"
322
- assert t.save
323
- end
324
-
325
- def test_terms_of_service_agreement_with_accept_value
326
- Topic.validates_acceptance_of(:terms_of_service, :on => :create, :accept => "I agree.")
327
-
328
- t = Topic.create("title" => "We should be confirmed", "terms_of_service" => "")
329
- assert !t.save
330
- assert_equal "must be accepted", t.errors.on(:terms_of_service)
331
-
332
- t.terms_of_service = "I agree."
333
- assert t.save
334
- end
335
-
336
- def test_validates_acceptance_of_as_database_column
337
- repair_validations(Reply) do
338
- Reply.validates_acceptance_of(:author_name)
339
-
340
- reply = Reply.create("author_name" => "Dan Brown")
341
- assert_equal "Dan Brown", reply["author_name"]
342
- end
343
- end
344
-
345
- def test_validates_acceptance_of_with_non_existant_table
346
- Object.const_set :IncorporealModel, Class.new(ActiveRecord::Base)
347
-
348
- assert_nothing_raised ActiveRecord::StatementInvalid do
349
- IncorporealModel.validates_acceptance_of(:incorporeal_column)
350
- end
351
- end
352
-
353
- def test_validate_presences
354
- Topic.validates_presence_of(:title, :content)
355
-
356
- t = Topic.create
357
- assert !t.save
358
- assert_equal "can't be blank", t.errors.on(:title)
359
- assert_equal "can't be blank", t.errors.on(:content)
360
-
361
- t.title = "something"
362
- t.content = " "
363
-
364
- assert !t.save
365
- assert_equal "can't be blank", t.errors.on(:content)
366
-
367
- t.content = "like stuff"
368
-
369
- assert t.save
370
- end
371
-
372
- def test_validates_presence_of_belongs_to_association__parent_is_new_record
373
- repair_validations(Interest) do
374
- # Note that Interest and Man have the :inverse_of option set
375
- Interest.validates_presence_of(:man)
376
- man = Man.new(:name => 'John')
377
- interest = man.interests.build(:topic => 'Airplanes')
378
- assert interest.valid?, "Expected interest to be valid, but was not. Interest should have a man object associated"
379
- end
380
- end
381
-
382
- def test_validates_presence_of_belongs_to_association__existing_parent
383
- repair_validations(Interest) do
384
- Interest.validates_presence_of(:man)
385
- man = Man.create!(:name => 'John')
386
- interest = man.interests.build(:topic => 'Airplanes')
387
- assert interest.valid?, "Expected interest to be valid, but was not. Interest should have a man object associated"
388
- end
389
- end
390
-
391
- def test_validate_uniqueness
392
- Topic.validates_uniqueness_of(:title)
393
-
394
- t = Topic.new("title" => "I'm uniqué!")
395
- assert t.save, "Should save t as unique"
396
-
397
- t.content = "Remaining unique"
398
- assert t.save, "Should still save t as unique"
399
-
400
- t2 = Topic.new("title" => "I'm uniqué!")
401
- assert !t2.valid?, "Shouldn't be valid"
402
- assert !t2.save, "Shouldn't save t2 as unique"
403
- assert_equal "has already been taken", t2.errors.on(:title)
404
-
405
- t2.title = "Now Im really also unique"
406
- assert t2.save, "Should now save t2 as unique"
407
- end
408
-
409
- def test_validates_uniquness_with_newline_chars
410
- Topic.validates_uniqueness_of(:title, :case_sensitive => false)
411
-
412
- t = Topic.new("title" => "new\nline")
413
- assert t.save, "Should save t as unique"
414
- end
415
-
416
- def test_validate_uniqueness_with_scope
417
- repair_validations(Reply) do
418
- Reply.validates_uniqueness_of(:content, :scope => "parent_id")
419
-
420
- t = Topic.create("title" => "I'm unique!")
421
-
422
- r1 = t.replies.create "title" => "r1", "content" => "hello world"
423
- assert r1.valid?, "Saving r1"
424
-
425
- r2 = t.replies.create "title" => "r2", "content" => "hello world"
426
- assert !r2.valid?, "Saving r2 first time"
427
-
428
- r2.content = "something else"
429
- assert r2.save, "Saving r2 second time"
430
-
431
- t2 = Topic.create("title" => "I'm unique too!")
432
- r3 = t2.replies.create "title" => "r3", "content" => "hello world"
433
- assert r3.valid?, "Saving r3"
434
- end
435
- end
436
-
437
- def test_validate_uniqueness_with_reserved_word_as_scope
438
- repair_validations(Reply) do
439
- Topic.validates_uniqueness_of(:content, :scope => "group")
440
-
441
- t1 = Topic.create "title" => "t1", "content" => "hello world2"
442
- assert t1.valid?
443
-
444
- t2 = Topic.create "title" => "t2", "content" => "hello world2"
445
- assert !t2.valid?
446
- end
447
- end
448
-
449
- def test_validate_uniqueness_scoped_to_defining_class
450
- t = Topic.create("title" => "What, me worry?")
451
-
452
- r1 = t.unique_replies.create "title" => "r1", "content" => "a barrel of fun"
453
- assert r1.valid?, "Saving r1"
454
-
455
- r2 = t.silly_unique_replies.create "title" => "r2", "content" => "a barrel of fun"
456
- assert !r2.valid?, "Saving r2"
457
-
458
- # Should succeed as validates_uniqueness_of only applies to
459
- # UniqueReply and its subclasses
460
- r3 = t.replies.create "title" => "r2", "content" => "a barrel of fun"
461
- assert r3.valid?, "Saving r3"
462
- end
463
-
464
- def test_validate_uniqueness_with_scope_array
465
- repair_validations(Reply) do
466
- Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
467
-
468
- t = Topic.create("title" => "The earth is actually flat!")
469
-
470
- r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
471
- assert r1.valid?, "Saving r1"
472
-
473
- r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
474
- assert !r2.valid?, "Saving r2. Double reply by same author."
475
-
476
- r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
477
- assert r2.save, "Saving r2 the second time."
478
-
479
- r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
480
- assert !r3.valid?, "Saving r3"
481
-
482
- r3.author_name = "jj"
483
- assert r3.save, "Saving r3 the second time."
484
-
485
- r3.author_name = "jeremy"
486
- assert !r3.save, "Saving r3 the third time."
487
- end
488
- end
489
-
490
- def test_validate_case_insensitive_uniqueness
491
- Topic.validates_uniqueness_of(:title, :parent_id, :case_sensitive => false, :allow_nil => true)
492
-
493
- t = Topic.new("title" => "I'm unique!", :parent_id => 2)
494
- assert t.save, "Should save t as unique"
495
-
496
- t.content = "Remaining unique"
497
- assert t.save, "Should still save t as unique"
498
-
499
- t2 = Topic.new("title" => "I'm UNIQUE!", :parent_id => 1)
500
- assert !t2.valid?, "Shouldn't be valid"
501
- assert !t2.save, "Shouldn't save t2 as unique"
502
- assert t2.errors.on(:title)
503
- assert t2.errors.on(:parent_id)
504
- assert_equal "has already been taken", t2.errors.on(:title)
505
-
506
- t2.title = "I'm truly UNIQUE!"
507
- assert !t2.valid?, "Shouldn't be valid"
508
- assert !t2.save, "Shouldn't save t2 as unique"
509
- assert_nil t2.errors.on(:title)
510
- assert t2.errors.on(:parent_id)
511
-
512
- t2.parent_id = 4
513
- assert t2.save, "Should now save t2 as unique"
514
-
515
- t2.parent_id = nil
516
- t2.title = nil
517
- assert t2.valid?, "should validate with nil"
518
- assert t2.save, "should save with nil"
519
-
520
- with_kcode('UTF8') do
521
- t_utf8 = Topic.new("title" => "Я тоже уникальный!")
522
- assert t_utf8.save, "Should save t_utf8 as unique"
523
-
524
- # If database hasn't UTF-8 character set, this test fails
525
- if Topic.find(t_utf8, :select => 'LOWER(title) AS title').title == "я тоже уникальный!"
526
- t2_utf8 = Topic.new("title" => "я тоже УНИКАЛЬНЫЙ!")
527
- assert !t2_utf8.valid?, "Shouldn't be valid"
528
- assert !t2_utf8.save, "Shouldn't save t2_utf8 as unique"
529
- end
530
- end
531
- end
532
-
533
- def test_validate_case_sensitive_uniqueness
534
- Topic.validates_uniqueness_of(:title, :case_sensitive => true, :allow_nil => true)
535
-
536
- t = Topic.new("title" => "I'm unique!")
537
- assert t.save, "Should save t as unique"
538
-
539
- t.content = "Remaining unique"
540
- assert t.save, "Should still save t as unique"
541
-
542
- t2 = Topic.new("title" => "I'M UNIQUE!")
543
- assert t2.valid?, "Should be valid"
544
- assert t2.save, "Should save t2 as unique"
545
- assert !t2.errors.on(:title)
546
- assert !t2.errors.on(:parent_id)
547
- assert_not_equal "has already been taken", t2.errors.on(:title)
548
-
549
- t3 = Topic.new("title" => "I'M uNiQUe!")
550
- assert t3.valid?, "Should be valid"
551
- assert t3.save, "Should save t2 as unique"
552
- assert !t3.errors.on(:title)
553
- assert !t3.errors.on(:parent_id)
554
- assert_not_equal "has already been taken", t3.errors.on(:title)
555
- end
556
-
557
- def test_validate_case_sensitive_uniqueness_with_attribute_passed_as_integer
558
- Topic.validates_uniqueness_of(:title, :case_sensitve => true)
559
- t = Topic.create!('title' => 101)
560
-
561
- t2 = Topic.new('title' => 101)
562
- assert !t2.valid?
563
- assert t2.errors.on(:title)
564
- end
565
-
566
- def test_validate_uniqueness_with_non_standard_table_names
567
- i1 = WarehouseThing.create(:value => 1000)
568
- assert !i1.valid?, "i1 should not be valid"
569
- assert i1.errors.on(:value), "Should not be empty"
570
- end
571
-
572
- def test_validates_uniqueness_inside_with_scope
573
- Topic.validates_uniqueness_of(:title)
574
-
575
- Topic.with_scope(:find => { :conditions => { :author_name => "David" } }) do
576
- t1 = Topic.new("title" => "I'm unique!", "author_name" => "Mary")
577
- assert t1.save
578
- t2 = Topic.new("title" => "I'm unique!", "author_name" => "David")
579
- assert !t2.valid?
580
- end
581
- end
582
-
583
- def test_validate_uniqueness_with_columns_which_are_sql_keywords
584
- repair_validations(Guid) do
585
- Guid.validates_uniqueness_of :key
586
- g = Guid.new
587
- g.key = "foo"
588
- assert_nothing_raised { !g.valid? }
589
- end
590
- end
591
-
592
- def test_validate_uniqueness_with_limit
593
- # Event.title is limited to 5 characters
594
- e1 = Event.create(:title => "abcde")
595
- assert e1.valid?, "Could not create an event with a unique, 5 character title"
596
- e2 = Event.create(:title => "abcdefgh")
597
- assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique"
598
- end
599
-
600
- def test_validate_uniqueness_with_limit_and_utf8
601
- with_kcode('UTF8') do
602
- # Event.title is limited to 5 characters
603
- e1 = Event.create(:title => "一二三四五")
604
- assert e1.valid?, "Could not create an event with a unique, 5 character title"
605
- e2 = Event.create(:title => "一二三四五六七八")
606
- assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique"
607
- end
608
- end
609
-
610
- def test_validate_straight_inheritance_uniqueness
611
- w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork")
612
- assert w1.valid?, "Saving w1"
613
-
614
- # Should use validation from base class (which is abstract)
615
- w2 = IneptWizard.new(:name => "Rincewind", :city => "Quirm")
616
- assert !w2.valid?, "w2 shouldn't be valid"
617
- assert w2.errors.on(:name), "Should have errors for name"
618
- assert_equal "has already been taken", w2.errors.on(:name), "Should have uniqueness message for name"
619
-
620
- w3 = Conjurer.new(:name => "Rincewind", :city => "Quirm")
621
- assert !w3.valid?, "w3 shouldn't be valid"
622
- assert w3.errors.on(:name), "Should have errors for name"
623
- assert_equal "has already been taken", w3.errors.on(:name), "Should have uniqueness message for name"
624
-
625
- w4 = Conjurer.create(:name => "The Amazing Bonko", :city => "Quirm")
626
- assert w4.valid?, "Saving w4"
627
-
628
- w5 = Thaumaturgist.new(:name => "The Amazing Bonko", :city => "Lancre")
629
- assert !w5.valid?, "w5 shouldn't be valid"
630
- assert w5.errors.on(:name), "Should have errors for name"
631
- assert_equal "has already been taken", w5.errors.on(:name), "Should have uniqueness message for name"
632
-
633
- w6 = Thaumaturgist.new(:name => "Mustrum Ridcully", :city => "Quirm")
634
- assert !w6.valid?, "w6 shouldn't be valid"
635
- assert w6.errors.on(:city), "Should have errors for city"
636
- assert_equal "has already been taken", w6.errors.on(:city), "Should have uniqueness message for city"
637
- end
638
-
639
- def test_validate_format
640
- Topic.validates_format_of(:title, :content, :with => /^Validation\smacros \w+!$/, :message => "is bad data")
641
-
642
- t = Topic.create("title" => "i'm incorrect", "content" => "Validation macros rule!")
643
- assert !t.valid?, "Shouldn't be valid"
644
- assert !t.save, "Shouldn't save because it's invalid"
645
- assert_equal "is bad data", t.errors.on(:title)
646
- assert_nil t.errors.on(:content)
647
-
648
- t.title = "Validation macros rule!"
649
-
650
- assert t.save
651
- assert_nil t.errors.on(:title)
652
-
653
- assert_raise(ArgumentError) { Topic.validates_format_of(:title, :content) }
654
- end
655
-
656
- def test_validate_format_with_allow_blank
657
- Topic.validates_format_of(:title, :with => /^Validation\smacros \w+!$/, :allow_blank=>true)
658
- assert !Topic.create("title" => "Shouldn't be valid").valid?
659
- assert Topic.create("title" => "").valid?
660
- assert Topic.create("title" => nil).valid?
661
- assert Topic.create("title" => "Validation macros rule!").valid?
662
- end
663
-
664
- # testing ticket #3142
665
- def test_validate_format_numeric
666
- Topic.validates_format_of(:title, :content, :with => /^[1-9][0-9]*$/, :message => "is bad data")
667
-
668
- t = Topic.create("title" => "72x", "content" => "6789")
669
- assert !t.valid?, "Shouldn't be valid"
670
- assert !t.save, "Shouldn't save because it's invalid"
671
- assert_equal "is bad data", t.errors.on(:title)
672
- assert_nil t.errors.on(:content)
673
-
674
- t.title = "-11"
675
- assert !t.valid?, "Shouldn't be valid"
676
-
677
- t.title = "03"
678
- assert !t.valid?, "Shouldn't be valid"
679
-
680
- t.title = "z44"
681
- assert !t.valid?, "Shouldn't be valid"
682
-
683
- t.title = "5v7"
684
- assert !t.valid?, "Shouldn't be valid"
685
-
686
- t.title = "1"
687
-
688
- assert t.save
689
- assert_nil t.errors.on(:title)
690
- end
691
-
692
- def test_validate_format_with_formatted_message
693
- Topic.validates_format_of(:title, :with => /^Valid Title$/, :message => "can't be %{value}")
694
- t = Topic.create(:title => 'Invalid title')
695
- assert_equal "can't be Invalid title", t.errors.on(:title)
696
- end
697
-
698
- def test_validates_inclusion_of
699
- Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ) )
700
-
701
- assert !Topic.create("title" => "a!", "content" => "abc").valid?
702
- assert !Topic.create("title" => "a b", "content" => "abc").valid?
703
- assert !Topic.create("title" => nil, "content" => "def").valid?
704
-
705
- t = Topic.create("title" => "a", "content" => "I know you are but what am I?")
706
- assert t.valid?
707
- t.title = "uhoh"
708
- assert !t.valid?
709
- assert t.errors.on(:title)
710
- assert_equal "is not included in the list", t.errors["title"]
711
-
712
- assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => nil ) }
713
- assert_raise(ArgumentError) { Topic.validates_inclusion_of( :title, :in => 0) }
714
-
715
- assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => "hi!" ) }
716
- assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => {} ) }
717
- assert_nothing_raised(ArgumentError) { Topic.validates_inclusion_of( :title, :in => [] ) }
718
- end
719
-
720
- def test_validates_inclusion_of_with_allow_nil
721
- Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :allow_nil=>true )
722
-
723
- assert !Topic.create("title" => "a!", "content" => "abc").valid?
724
- assert !Topic.create("title" => "", "content" => "abc").valid?
725
- assert Topic.create("title" => nil, "content" => "abc").valid?
726
- end
727
-
728
- def test_numericality_with_getter_method
729
- repair_validations(Developer) do
730
- Developer.validates_numericality_of( :salary )
731
- developer = Developer.new("name" => "michael", "salary" => nil)
732
- developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end")
733
- assert developer.valid?
734
- end
735
- end
736
-
737
- def test_validates_length_of_with_allow_nil
738
- Topic.validates_length_of( :title, :is => 5, :allow_nil=>true )
739
-
740
- assert !Topic.create("title" => "ab").valid?
741
- assert !Topic.create("title" => "").valid?
742
- assert Topic.create("title" => nil).valid?
743
- assert Topic.create("title" => "abcde").valid?
744
- end
745
-
746
- def test_validates_length_of_with_allow_blank
747
- Topic.validates_length_of( :title, :is => 5, :allow_blank=>true )
748
-
749
- assert !Topic.create("title" => "ab").valid?
750
- assert Topic.create("title" => "").valid?
751
- assert Topic.create("title" => nil).valid?
752
- assert Topic.create("title" => "abcde").valid?
753
- end
754
-
755
- def test_validates_inclusion_of_with_formatted_message
756
- Topic.validates_inclusion_of( :title, :in => %w( a b c d e f g ), :message => "option %{value} is not in the list" )
757
-
758
- assert Topic.create("title" => "a", "content" => "abc").valid?
759
-
760
- t = Topic.create("title" => "uhoh", "content" => "abc")
761
- assert !t.valid?
762
- assert t.errors.on(:title)
763
- assert_equal "option uhoh is not in the list", t.errors["title"]
764
- end
765
-
766
- def test_numericality_with_allow_nil_and_getter_method
767
- repair_validations(Developer) do
768
- Developer.validates_numericality_of( :salary, :allow_nil => true)
769
- developer = Developer.new("name" => "michael", "salary" => nil)
770
- developer.instance_eval("def salary; read_attribute('salary') ? read_attribute('salary') : 100000; end")
771
- assert developer.valid?
772
- end
773
- end
774
-
775
- def test_validates_exclusion_of
776
- Topic.validates_exclusion_of( :title, :in => %w( abe monkey ) )
777
-
778
- assert Topic.create("title" => "something", "content" => "abc").valid?
779
- assert !Topic.create("title" => "monkey", "content" => "abc").valid?
780
- end
781
-
782
- def test_validates_exclusion_of_with_formatted_message
783
- Topic.validates_exclusion_of( :title, :in => %w( abe monkey ), :message => "option %{value} is restricted" )
784
-
785
- assert Topic.create("title" => "something", "content" => "abc")
786
-
787
- t = Topic.create("title" => "monkey")
788
- assert !t.valid?
789
- assert t.errors.on(:title)
790
- assert_equal "option monkey is restricted", t.errors["title"]
791
- end
792
-
793
- def test_validates_length_of_using_minimum
794
- Topic.validates_length_of :title, :minimum => 5
795
-
796
- t = Topic.create("title" => "valid", "content" => "whatever")
797
- assert t.valid?
798
-
799
- t.title = "not"
800
- assert !t.valid?
801
- assert t.errors.on(:title)
802
- assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
803
-
804
- t.title = ""
805
- assert !t.valid?
806
- assert t.errors.on(:title)
807
- assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
808
-
809
- t.title = nil
810
- assert !t.valid?
811
- assert t.errors.on(:title)
812
- assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
813
- end
814
-
815
- def test_optionally_validates_length_of_using_minimum
816
- Topic.validates_length_of :title, :minimum => 5, :allow_nil => true
817
-
818
- t = Topic.create("title" => "valid", "content" => "whatever")
819
- assert t.valid?
820
-
821
- t.title = nil
822
- assert t.valid?
823
- end
824
-
825
- def test_validates_length_of_using_maximum
826
- Topic.validates_length_of :title, :maximum => 5
827
-
828
- t = Topic.create("title" => "valid", "content" => "whatever")
829
- assert t.valid?
830
-
831
- t.title = "notvalid"
832
- assert !t.valid?
833
- assert t.errors.on(:title)
834
- assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
835
-
836
- t.title = ""
837
- assert t.valid?
838
-
839
- t.title = nil
840
- assert !t.valid?
841
- end
842
-
843
- def test_optionally_validates_length_of_using_maximum
844
- Topic.validates_length_of :title, :maximum => 5, :allow_nil => true
845
-
846
- t = Topic.create("title" => "valid", "content" => "whatever")
847
- assert t.valid?
848
-
849
- t.title = nil
850
- assert t.valid?
851
- end
852
-
853
- def test_validates_length_of_using_within
854
- Topic.validates_length_of(:title, :content, :within => 3..5)
855
-
856
- t = Topic.new("title" => "a!", "content" => "I'm ooooooooh so very long")
857
- assert !t.valid?
858
- assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
859
- assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
860
-
861
- t.title = nil
862
- t.content = nil
863
- assert !t.valid?
864
- assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
865
- assert_equal "is too short (minimum is 3 characters)", t.errors.on(:content)
866
-
867
- t.title = "abe"
868
- t.content = "mad"
869
- assert t.valid?
870
- end
871
-
872
- def test_optionally_validates_length_of_using_within
873
- Topic.validates_length_of :title, :content, :within => 3..5, :allow_nil => true
874
-
875
- t = Topic.create('title' => 'abc', 'content' => 'abcd')
876
- assert t.valid?
877
-
878
- t.title = nil
879
- assert t.valid?
880
- end
881
-
882
- def test_optionally_validates_length_of_using_within_on_create
883
- Topic.validates_length_of :title, :content, :within => 5..10, :on => :create, :too_long => "my string is too long: %{count}"
884
-
885
- t = Topic.create("title" => "thisisnotvalid", "content" => "whatever")
886
- assert !t.save
887
- assert t.errors.on(:title)
888
- assert_equal "my string is too long: 10", t.errors[:title]
889
-
890
- t.title = "butthisis"
891
- assert t.save
892
-
893
- t.title = "few"
894
- assert t.save
895
-
896
- t.content = "andthisislong"
897
- assert t.save
898
-
899
- t.content = t.title = "iamfine"
900
- assert t.save
901
- end
902
-
903
- def test_optionally_validates_length_of_using_within_on_update
904
- Topic.validates_length_of :title, :content, :within => 5..10, :on => :update, :too_short => "my string is too short: %{count}"
905
-
906
- t = Topic.create("title" => "vali", "content" => "whatever")
907
- assert !t.save
908
- assert t.errors.on(:title)
909
-
910
- t.title = "not"
911
- assert !t.save
912
- assert t.errors.on(:title)
913
- assert_equal "my string is too short: 5", t.errors[:title]
914
-
915
- t.title = "valid"
916
- t.content = "andthisistoolong"
917
- assert !t.save
918
- assert t.errors.on(:content)
919
-
920
- t.content = "iamfine"
921
- assert t.save
922
- end
923
-
924
- def test_validates_length_of_using_is
925
- Topic.validates_length_of :title, :is => 5
926
-
927
- t = Topic.create("title" => "valid", "content" => "whatever")
928
- assert t.valid?
929
-
930
- t.title = "notvalid"
931
- assert !t.valid?
932
- assert t.errors.on(:title)
933
- assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
934
-
935
- t.title = ""
936
- assert !t.valid?
937
-
938
- t.title = nil
939
- assert !t.valid?
940
- end
941
-
942
- def test_optionally_validates_length_of_using_is
943
- Topic.validates_length_of :title, :is => 5, :allow_nil => true
944
-
945
- t = Topic.create("title" => "valid", "content" => "whatever")
946
- assert t.valid?
947
-
948
- t.title = nil
949
- assert t.valid?
950
- end
951
-
952
- def test_validates_length_of_using_bignum
953
- bigmin = 2 ** 30
954
- bigmax = 2 ** 32
955
- bigrange = bigmin...bigmax
956
- assert_nothing_raised do
957
- Topic.validates_length_of :title, :is => bigmin + 5
958
- Topic.validates_length_of :title, :within => bigrange
959
- Topic.validates_length_of :title, :in => bigrange
960
- Topic.validates_length_of :title, :minimum => bigmin
961
- Topic.validates_length_of :title, :maximum => bigmax
962
- end
963
- end
964
-
965
- def test_validates_length_with_globally_modified_error_message
966
- defaults = ActiveSupport::Deprecation.silence { ActiveRecord::Errors.default_error_messages }
967
- original_message = defaults[:too_short]
968
- defaults[:too_short] = 'tu est trops petit hombre %{count}'
969
-
970
- Topic.validates_length_of :title, :minimum => 10
971
- t = Topic.create(:title => 'too short')
972
- assert !t.valid?
973
-
974
- assert_equal 'tu est trops petit hombre 10', t.errors['title']
975
-
976
- ensure
977
- defaults[:too_short] = original_message
978
- end
979
-
980
- def test_validates_size_of_association
981
- repair_validations(Owner) do
982
- assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
983
- o = Owner.new('name' => 'nopets')
984
- assert !o.save
985
- assert o.errors.on(:pets)
986
- pet = o.pets.build('name' => 'apet')
987
- assert o.valid?
988
- end
989
- end
990
-
991
- def test_validates_size_of_association_using_within
992
- repair_validations(Owner) do
993
- assert_nothing_raised { Owner.validates_size_of :pets, :within => 1..2 }
994
- o = Owner.new('name' => 'nopets')
995
- assert !o.save
996
- assert o.errors.on(:pets)
997
-
998
- pet = o.pets.build('name' => 'apet')
999
- assert o.valid?
1000
-
1001
- 2.times { o.pets.build('name' => 'apet') }
1002
- assert !o.save
1003
- assert o.errors.on(:pets)
1004
- end
1005
- end
1006
-
1007
- def test_validates_length_of_nasty_params
1008
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>6, :maximum=>9) }
1009
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :maximum=>9) }
1010
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :minimum=>9) }
1011
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>6, :is=>9) }
1012
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :minimum=>"a") }
1013
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :maximum=>"a") }
1014
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :within=>"a") }
1015
- assert_raise(ArgumentError) { Topic.validates_length_of(:title, :is=>"a") }
1016
- end
1017
-
1018
- def test_validates_length_of_custom_errors_for_minimum_with_message
1019
- Topic.validates_length_of( :title, :minimum=>5, :message=>"boo %{count}" )
1020
- t = Topic.create("title" => "uhoh", "content" => "whatever")
1021
- assert !t.valid?
1022
- assert t.errors.on(:title)
1023
- assert_equal "boo 5", t.errors["title"]
1024
- end
1025
-
1026
- def test_validates_length_of_custom_errors_for_minimum_with_too_short
1027
- Topic.validates_length_of( :title, :minimum=>5, :too_short=>"hoo %{count}" )
1028
- t = Topic.create("title" => "uhoh", "content" => "whatever")
1029
- assert !t.valid?
1030
- assert t.errors.on(:title)
1031
- assert_equal "hoo 5", t.errors["title"]
1032
- end
1033
-
1034
- def test_validates_length_of_custom_errors_for_maximum_with_message
1035
- Topic.validates_length_of( :title, :maximum=>5, :message=>"boo %{count}" )
1036
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1037
- assert !t.valid?
1038
- assert t.errors.on(:title)
1039
- assert_equal "boo 5", t.errors["title"]
1040
- end
1041
-
1042
- def test_validates_length_of_custom_errors_for_in
1043
- Topic.validates_length_of(:title, :in => 10..20, :message => "hoo %{count}")
1044
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1045
- assert !t.valid?
1046
- assert t.errors.on(:title)
1047
- assert_equal "hoo 10", t.errors["title"]
1048
-
1049
- t = Topic.create("title" => "uhohuhohuhohuhohuhohuhohuhohuhoh", "content" => "whatever")
1050
- assert !t.valid?
1051
- assert t.errors.on(:title)
1052
- assert_equal "hoo 20", t.errors["title"]
1053
- end
1054
-
1055
- def test_validates_length_of_custom_errors_for_maximum_with_too_long
1056
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}" )
1057
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1058
- assert !t.valid?
1059
- assert t.errors.on(:title)
1060
- assert_equal "hoo 5", t.errors["title"]
1061
- end
1062
-
1063
- def test_validates_length_of_custom_errors_for_is_with_message
1064
- Topic.validates_length_of( :title, :is=>5, :message=>"boo %{count}" )
1065
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1066
- assert !t.valid?
1067
- assert t.errors.on(:title)
1068
- assert_equal "boo 5", t.errors["title"]
1069
- end
1070
-
1071
- def test_validates_length_of_custom_errors_for_is_with_wrong_length
1072
- Topic.validates_length_of( :title, :is=>5, :wrong_length=>"hoo %{count}" )
1073
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1074
- assert !t.valid?
1075
- assert t.errors.on(:title)
1076
- assert_equal "hoo 5", t.errors["title"]
1077
- end
1078
-
1079
- def test_validates_length_of_using_minimum_utf8
1080
- with_kcode('UTF8') do
1081
- Topic.validates_length_of :title, :minimum => 5
1082
-
1083
- t = Topic.create("title" => "一二三四五", "content" => "whatever")
1084
- assert t.valid?
1085
-
1086
- t.title = "一二三四"
1087
- assert !t.valid?
1088
- assert t.errors.on(:title)
1089
- assert_equal "is too short (minimum is 5 characters)", t.errors["title"]
1090
- end
1091
- end
1092
-
1093
- def test_validates_length_of_using_maximum_utf8
1094
- with_kcode('UTF8') do
1095
- Topic.validates_length_of :title, :maximum => 5
1096
-
1097
- t = Topic.create("title" => "一二三四五", "content" => "whatever")
1098
- assert t.valid?
1099
-
1100
- t.title = "一二34五六"
1101
- assert !t.valid?
1102
- assert t.errors.on(:title)
1103
- assert_equal "is too long (maximum is 5 characters)", t.errors["title"]
1104
- end
1105
- end
1106
-
1107
- def test_validates_length_of_using_within_utf8
1108
- with_kcode('UTF8') do
1109
- Topic.validates_length_of(:title, :content, :within => 3..5)
1110
-
1111
- t = Topic.new("title" => "一二", "content" => "12三四五六七")
1112
- assert !t.valid?
1113
- assert_equal "is too short (minimum is 3 characters)", t.errors.on(:title)
1114
- assert_equal "is too long (maximum is 5 characters)", t.errors.on(:content)
1115
- t.title = "一二三"
1116
- t.content = "12三"
1117
- assert t.valid?
1118
- end
1119
- end
1120
-
1121
- def test_optionally_validates_length_of_using_within_utf8
1122
- with_kcode('UTF8') do
1123
- Topic.validates_length_of :title, :within => 3..5, :allow_nil => true
1124
-
1125
- t = Topic.create(:title => "一二三四五")
1126
- assert t.valid?, t.errors.inspect
1127
-
1128
- t = Topic.create(:title => "一二三")
1129
- assert t.valid?, t.errors.inspect
1130
-
1131
- t.title = nil
1132
- assert t.valid?, t.errors.inspect
1133
- end
1134
- end
1135
-
1136
- def test_optionally_validates_length_of_using_within_on_create_utf8
1137
- with_kcode('UTF8') do
1138
- Topic.validates_length_of :title, :within => 5..10, :on => :create, :too_long => "長すぎます: %{count}"
1139
-
1140
- t = Topic.create("title" => "一二三四五六七八九十A", "content" => "whatever")
1141
- assert !t.save
1142
- assert t.errors.on(:title)
1143
- assert_equal "長すぎます: 10", t.errors[:title]
1144
-
1145
- t.title = "一二三四五六七八九"
1146
- assert t.save
1147
-
1148
- t.title = "一二3"
1149
- assert t.save
1150
-
1151
- t.content = "一二三四五六七八九十"
1152
- assert t.save
1153
-
1154
- t.content = t.title = "一二三四五六"
1155
- assert t.save
1156
- end
1157
- end
1158
-
1159
- def test_optionally_validates_length_of_using_within_on_update_utf8
1160
- with_kcode('UTF8') do
1161
- Topic.validates_length_of :title, :within => 5..10, :on => :update, :too_short => "短すぎます: %{count}"
1162
-
1163
- t = Topic.create("title" => "一二三4", "content" => "whatever")
1164
- assert !t.save
1165
- assert t.errors.on(:title)
1166
-
1167
- t.title = "1二三4"
1168
- assert !t.save
1169
- assert t.errors.on(:title)
1170
- assert_equal "短すぎます: 5", t.errors[:title]
1171
-
1172
- t.title = "一二三四五六七八九十A"
1173
- assert !t.save
1174
- assert t.errors.on(:title)
1175
-
1176
- t.title = "一二345"
1177
- assert t.save
1178
- end
1179
- end
1180
-
1181
- def test_validates_length_of_using_is_utf8
1182
- with_kcode('UTF8') do
1183
- Topic.validates_length_of :title, :is => 5
1184
-
1185
- t = Topic.create("title" => "一二345", "content" => "whatever")
1186
- assert t.valid?
1187
-
1188
- t.title = "一二345六"
1189
- assert !t.valid?
1190
- assert t.errors.on(:title)
1191
- assert_equal "is the wrong length (should be 5 characters)", t.errors["title"]
1192
- end
1193
- end
1194
-
1195
- def test_validates_length_of_with_block
1196
- Topic.validates_length_of :content, :minimum => 5, :too_short=>"Your essay must be at least %{count} words.",
1197
- :tokenizer => lambda {|str| str.scan(/\w+/) }
1198
- t = Topic.create!(:content => "this content should be long enough")
1199
- assert t.valid?
1200
-
1201
- t.content = "not long enough"
1202
- assert !t.valid?
1203
- assert t.errors.on(:content)
1204
- assert_equal "Your essay must be at least 5 words.", t.errors[:content]
1205
- end
1206
-
1207
- def test_validates_size_of_association_utf8
1208
- repair_validations(Owner) do
1209
- with_kcode('UTF8') do
1210
- assert_nothing_raised { Owner.validates_size_of :pets, :minimum => 1 }
1211
- o = Owner.new('name' => 'あいうえおかきくけこ')
1212
- assert !o.save
1213
- assert o.errors.on(:pets)
1214
- o.pets.build('name' => 'あいうえおかきくけこ')
1215
- assert o.valid?
1216
- end
1217
- end
1218
- end
1219
-
1220
- def test_validates_associated_many
1221
- Topic.validates_associated( :replies )
1222
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1223
- t.replies << [r = Reply.new("title" => "A reply"), r2 = Reply.new("title" => "Another reply", "content" => "non-empty"), r3 = Reply.new("title" => "Yet another reply"), r4 = Reply.new("title" => "The last reply", "content" => "non-empty")]
1224
- assert !t.valid?
1225
- assert t.errors.on(:replies)
1226
- assert_equal 1, r.errors.count # make sure all associated objects have been validated
1227
- assert_equal 0, r2.errors.count
1228
- assert_equal 1, r3.errors.count
1229
- assert_equal 0, r4.errors.count
1230
- r.content = r3.content = "non-empty"
1231
- assert t.valid?
1232
- end
1233
-
1234
- def test_validates_associated_one
1235
- repair_validations(Reply) do
1236
- Reply.validates_associated( :topic )
1237
- Topic.validates_presence_of( :content )
1238
- r = Reply.new("title" => "A reply", "content" => "with content!")
1239
- r.topic = Topic.create("title" => "uhohuhoh")
1240
- assert !r.valid?
1241
- assert r.errors.on(:topic)
1242
- r.topic.content = "non-empty"
1243
- assert r.valid?
1244
- end
1245
- end
1246
-
1247
- def test_validate_block
1248
- Topic.validate { |topic| topic.errors.add("title", "will never be valid") }
1249
- t = Topic.create("title" => "Title", "content" => "whatever")
1250
- assert !t.valid?
1251
- assert t.errors.on(:title)
1252
- assert_equal "will never be valid", t.errors["title"]
1253
- end
1254
-
1255
- def test_invalid_validator
1256
- Topic.validate 3
1257
- assert_raise(ArgumentError) { t = Topic.create }
1258
- end
1259
-
1260
- def test_throw_away_typing
1261
- d = Developer.new("name" => "David", "salary" => "100,000")
1262
- assert !d.valid?
1263
- assert_equal 100, d.salary
1264
- assert_equal "100,000", d.salary_before_type_cast
1265
- end
1266
-
1267
- def test_validates_acceptance_of_with_custom_error_using_quotes
1268
- repair_validations(Developer) do
1269
- Developer.validates_acceptance_of :salary, :message=> "This string contains 'single' and \"double\" quotes"
1270
- d = Developer.new
1271
- d.salary = "0"
1272
- assert !d.valid?
1273
- assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:salary).last
1274
- end
1275
- end
1276
-
1277
- def test_validates_confirmation_of_with_custom_error_using_quotes
1278
- repair_validations(Developer) do
1279
- Developer.validates_confirmation_of :name, :message=> "confirm 'single' and \"double\" quotes"
1280
- d = Developer.new
1281
- d.name = "John"
1282
- d.name_confirmation = "Johnny"
1283
- assert !d.valid?
1284
- assert_equal "confirm 'single' and \"double\" quotes", d.errors.on(:name)
1285
- end
1286
- end
1287
-
1288
- def test_validates_format_of_with_custom_error_using_quotes
1289
- repair_validations(Developer) do
1290
- Developer.validates_format_of :name, :with => /^(A-Z*)$/, :message=> "format 'single' and \"double\" quotes"
1291
- d = Developer.new
1292
- d.name = d.name_confirmation = "John 32"
1293
- assert !d.valid?
1294
- assert_equal "format 'single' and \"double\" quotes", d.errors.on(:name)
1295
- end
1296
- end
1297
-
1298
- def test_validates_inclusion_of_with_custom_error_using_quotes
1299
- repair_validations(Developer) do
1300
- Developer.validates_inclusion_of :salary, :in => 1000..80000, :message=> "This string contains 'single' and \"double\" quotes"
1301
- d = Developer.new
1302
- d.salary = "90,000"
1303
- assert !d.valid?
1304
- assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:salary).last
1305
- end
1306
- end
1307
-
1308
- def test_validates_length_of_with_custom_too_long_using_quotes
1309
- repair_validations(Developer) do
1310
- Developer.validates_length_of :name, :maximum => 4, :too_long=> "This string contains 'single' and \"double\" quotes"
1311
- d = Developer.new
1312
- d.name = "Jeffrey"
1313
- assert !d.valid?
1314
- assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name)
1315
- end
1316
- end
1317
-
1318
- def test_validates_length_of_with_custom_too_short_using_quotes
1319
- repair_validations(Developer) do
1320
- Developer.validates_length_of :name, :minimum => 4, :too_short=> "This string contains 'single' and \"double\" quotes"
1321
- d = Developer.new
1322
- d.name = "Joe"
1323
- assert !d.valid?
1324
- assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name)
1325
- end
1326
- end
1327
-
1328
- def test_validates_length_of_with_custom_message_using_quotes
1329
- repair_validations(Developer) do
1330
- Developer.validates_length_of :name, :minimum => 4, :message=> "This string contains 'single' and \"double\" quotes"
1331
- d = Developer.new
1332
- d.name = "Joe"
1333
- assert !d.valid?
1334
- assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name)
1335
- end
1336
- end
1337
-
1338
- def test_validates_presence_of_with_custom_message_using_quotes
1339
- repair_validations(Developer) do
1340
- Developer.validates_presence_of :non_existent, :message=> "This string contains 'single' and \"double\" quotes"
1341
- d = Developer.new
1342
- d.name = "Joe"
1343
- assert !d.valid?
1344
- assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:non_existent)
1345
- end
1346
- end
1347
-
1348
- def test_validates_uniqueness_of_with_custom_message_using_quotes
1349
- repair_validations(Developer) do
1350
- Developer.validates_uniqueness_of :name, :message=> "This string contains 'single' and \"double\" quotes"
1351
- d = Developer.new
1352
- d.name = "David"
1353
- assert !d.valid?
1354
- assert_equal "This string contains 'single' and \"double\" quotes", d.errors.on(:name)
1355
- end
1356
- end
1357
-
1358
- def test_validates_associated_with_custom_message_using_quotes
1359
- repair_validations(Reply) do
1360
- Reply.validates_associated :topic, :message=> "This string contains 'single' and \"double\" quotes"
1361
- Topic.validates_presence_of :content
1362
- r = Reply.create("title" => "A reply", "content" => "with content!")
1363
- r.topic = Topic.create("title" => "uhohuhoh")
1364
- assert !r.valid?
1365
- assert_equal "This string contains 'single' and \"double\" quotes", r.errors.on(:topic)
1366
- end
1367
- end
1368
-
1369
- def test_if_validation_using_method_true
1370
- # When the method returns true
1371
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true )
1372
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1373
- assert !t.valid?
1374
- assert t.errors.on(:title)
1375
- assert_equal "hoo 5", t.errors["title"]
1376
- end
1377
-
1378
- def test_unless_validation_using_method_true
1379
- # When the method returns true
1380
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true )
1381
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1382
- assert t.valid?
1383
- assert !t.errors.on(:title)
1384
- end
1385
-
1386
- def test_if_validation_using_method_false
1387
- # When the method returns false
1388
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => :condition_is_true_but_its_not )
1389
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1390
- assert t.valid?
1391
- assert !t.errors.on(:title)
1392
- end
1393
-
1394
- def test_unless_validation_using_method_false
1395
- # When the method returns false
1396
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => :condition_is_true_but_its_not )
1397
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1398
- assert !t.valid?
1399
- assert t.errors.on(:title)
1400
- assert_equal "hoo 5", t.errors["title"]
1401
- end
1402
-
1403
- def test_if_validation_using_string_true
1404
- # When the evaluated string returns true
1405
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "a = 1; a == 1" )
1406
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1407
- assert !t.valid?
1408
- assert t.errors.on(:title)
1409
- assert_equal "hoo 5", t.errors["title"]
1410
- end
1411
-
1412
- def test_unless_validation_using_string_true
1413
- # When the evaluated string returns true
1414
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "a = 1; a == 1" )
1415
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1416
- assert t.valid?
1417
- assert !t.errors.on(:title)
1418
- end
1419
-
1420
- def test_if_validation_using_string_false
1421
- # When the evaluated string returns false
1422
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :if => "false")
1423
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1424
- assert t.valid?
1425
- assert !t.errors.on(:title)
1426
- end
1427
-
1428
- def test_unless_validation_using_string_false
1429
- # When the evaluated string returns false
1430
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}", :unless => "false")
1431
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1432
- assert !t.valid?
1433
- assert t.errors.on(:title)
1434
- assert_equal "hoo 5", t.errors["title"]
1435
- end
1436
-
1437
- def test_if_validation_using_block_true
1438
- # When the block returns true
1439
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
1440
- :if => Proc.new { |r| r.content.size > 4 } )
1441
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1442
- assert !t.valid?
1443
- assert t.errors.on(:title)
1444
- assert_equal "hoo 5", t.errors["title"]
1445
- end
1446
-
1447
- def test_unless_validation_using_block_true
1448
- # When the block returns true
1449
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
1450
- :unless => Proc.new { |r| r.content.size > 4 } )
1451
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1452
- assert t.valid?
1453
- assert !t.errors.on(:title)
1454
- end
1455
-
1456
- def test_if_validation_using_block_false
1457
- # When the block returns false
1458
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
1459
- :if => Proc.new { |r| r.title != "uhohuhoh"} )
1460
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1461
- assert t.valid?
1462
- assert !t.errors.on(:title)
1463
- end
1464
-
1465
- def test_unless_validation_using_block_false
1466
- # When the block returns false
1467
- Topic.validates_length_of( :title, :maximum=>5, :too_long=>"hoo %{count}",
1468
- :unless => Proc.new { |r| r.title != "uhohuhoh"} )
1469
- t = Topic.create("title" => "uhohuhoh", "content" => "whatever")
1470
- assert !t.valid?
1471
- assert t.errors.on(:title)
1472
- assert_equal "hoo 5", t.errors["title"]
1473
- end
1474
-
1475
- def test_validates_associated_missing
1476
- repair_validations(Reply) do
1477
- Reply.validates_presence_of(:topic)
1478
- r = Reply.create("title" => "A reply", "content" => "with content!")
1479
- assert !r.valid?
1480
- assert r.errors.on(:topic)
1481
-
1482
- r.topic = Topic.find :first
1483
- assert r.valid?
1484
- end
1485
- end
1486
-
1487
- def test_errors_to_xml
1488
- r = Reply.new :title => "Wrong Create"
1489
- assert !r.valid?
1490
- xml = r.errors.to_xml(:skip_instruct => true)
1491
- assert_equal "<errors>", xml.first(8)
1492
- assert xml.include?("<error>Title is Wrong Create</error>")
1493
- assert xml.include?("<error>Content Empty</error>")
1494
- end
1495
-
1496
- def test_validation_order
1497
- Topic.validates_presence_of :title, :author_name
1498
- Topic.validate {|topic| topic.errors.add('author_email_address', 'will never be valid')}
1499
- Topic.validates_length_of :title, :content, :minimum => 2
1500
-
1501
- t = Topic.new :title => ''
1502
- t.valid?
1503
- e = t.errors.instance_variable_get '@errors'
1504
- assert_equal 'title', key = e.keys.first
1505
- assert_equal "can't be blank", t.errors.on(key).first
1506
- assert_equal 'is too short (minimum is 2 characters)', t.errors.on(key).second
1507
- assert_equal 'author_name', key = e.keys.second
1508
- assert_equal "can't be blank", t.errors.on(key)
1509
- assert_equal 'author_email_address', key = e.keys.third
1510
- assert_equal 'will never be valid', t.errors.on(key)
1511
- assert_equal 'content', key = e.keys.fourth
1512
- assert_equal 'is too short (minimum is 2 characters)', t.errors.on(key)
1513
- end
1514
-
1515
- def test_invalid_should_be_the_opposite_of_valid
1516
- Topic.validates_presence_of :title
1517
-
1518
- t = Topic.new
1519
- assert t.invalid?
1520
- assert t.errors.invalid?(:title)
1521
-
1522
- t.title = 'Things are going to change'
1523
- assert !t.invalid?
1524
- end
1525
-
1526
- # previous implementation of validates_presence_of eval'd the
1527
- # string with the wrong binding, this regression test is to
1528
- # ensure that it works correctly
1529
- def test_validation_with_if_as_string
1530
- Topic.validates_presence_of(:title)
1531
- Topic.validates_presence_of(:author_name, :if => "title.to_s.match('important')")
1532
-
1533
- t = Topic.new
1534
- assert !t.valid?, "A topic without a title should not be valid"
1535
- assert !t.errors.invalid?("author_name"), "A topic without an 'important' title should not require an author"
1536
-
1537
- t.title = "Just a title"
1538
- assert t.valid?, "A topic with a basic title should be valid"
1539
-
1540
- t.title = "A very important title"
1541
- assert !t.valid?, "A topic with an important title, but without an author, should not be valid"
1542
- assert t.errors.invalid?("author_name"), "A topic with an 'important' title should require an author"
1543
-
1544
- t.author_name = "Hubert J. Farnsworth"
1545
- assert t.valid?, "A topic with an important title and author should be valid"
1546
- end
1547
- end
1548
-
1549
-
1550
- class ValidatesNumericalityTest < ActiveRecord::TestCase
1551
- NIL = [nil]
1552
- BLANK = ["", " ", " \t \r \n"]
1553
- BIGDECIMAL_STRINGS = %w(12345678901234567890.1234567890) # 30 significent digits
1554
- FLOAT_STRINGS = %w(0.0 +0.0 -0.0 10.0 10.5 -10.5 -0.0001 -090.1 90.1e1 -90.1e5 -90.1e-5 90e-5)
1555
- INTEGER_STRINGS = %w(0 +0 -0 10 +10 -10 0090 -090)
1556
- FLOATS = [0.0, 10.0, 10.5, -10.5, -0.0001] + FLOAT_STRINGS
1557
- INTEGERS = [0, 10, -10] + INTEGER_STRINGS
1558
- BIGDECIMAL = BIGDECIMAL_STRINGS.collect! { |bd| BigDecimal.new(bd) }
1559
- JUNK = ["not a number", "42 not a number", "0xdeadbeef", "00-1", "--3", "+-3", "+3-1", "-+019.0", "12.12.13.12", "123\nnot a number"]
1560
- INFINITY = [1.0/0.0]
1561
-
1562
- repair_validations(Topic)
1563
-
1564
- def test_default_validates_numericality_of
1565
- Topic.validates_numericality_of :approved
1566
-
1567
- invalid!(NIL + BLANK + JUNK)
1568
- valid!(FLOATS + INTEGERS + BIGDECIMAL + INFINITY)
1569
- end
1570
-
1571
- def test_validates_numericality_of_with_nil_allowed
1572
- Topic.validates_numericality_of :approved, :allow_nil => true
1573
-
1574
- invalid!(JUNK)
1575
- valid!(NIL + BLANK + FLOATS + INTEGERS + BIGDECIMAL + INFINITY)
1576
- end
1577
-
1578
- def test_validates_numericality_of_with_integer_only
1579
- Topic.validates_numericality_of :approved, :only_integer => true
1580
-
1581
- invalid!(NIL + BLANK + JUNK + FLOATS + BIGDECIMAL + INFINITY)
1582
- valid!(INTEGERS)
1583
- end
1584
-
1585
- def test_validates_numericality_of_with_integer_only_and_nil_allowed
1586
- Topic.validates_numericality_of :approved, :only_integer => true, :allow_nil => true
1587
-
1588
- invalid!(JUNK + FLOATS + BIGDECIMAL + INFINITY)
1589
- valid!(NIL + BLANK + INTEGERS)
1590
- end
1591
-
1592
- def test_validates_numericality_with_greater_than
1593
- Topic.validates_numericality_of :approved, :greater_than => 10
1594
-
1595
- invalid!([-10, 10], 'must be greater than 10')
1596
- valid!([11])
1597
- end
1598
-
1599
- def test_validates_numericality_with_greater_than_or_equal
1600
- Topic.validates_numericality_of :approved, :greater_than_or_equal_to => 10
1601
-
1602
- invalid!([-9, 9], 'must be greater than or equal to 10')
1603
- valid!([10])
1604
- end
1605
-
1606
- def test_validates_numericality_with_equal_to
1607
- Topic.validates_numericality_of :approved, :equal_to => 10
1608
-
1609
- invalid!([-10, 11] + INFINITY, 'must be equal to 10')
1610
- valid!([10])
1611
- end
1612
-
1613
- def test_validates_numericality_with_less_than
1614
- Topic.validates_numericality_of :approved, :less_than => 10
1615
-
1616
- invalid!([10], 'must be less than 10')
1617
- valid!([-9, 9])
1618
- end
1619
-
1620
- def test_validates_numericality_with_less_than_or_equal_to
1621
- Topic.validates_numericality_of :approved, :less_than_or_equal_to => 10
1622
-
1623
- invalid!([11], 'must be less than or equal to 10')
1624
- valid!([-10, 10])
1625
- end
1626
-
1627
- def test_validates_numericality_with_odd
1628
- Topic.validates_numericality_of :approved, :odd => true
1629
-
1630
- invalid!([-2, 2], 'must be odd')
1631
- valid!([-1, 1])
1632
- end
1633
-
1634
- def test_validates_numericality_with_even
1635
- Topic.validates_numericality_of :approved, :even => true
1636
-
1637
- invalid!([-1, 1], 'must be even')
1638
- valid!([-2, 2])
1639
- end
1640
-
1641
- def test_validates_numericality_with_greater_than_less_than_and_even
1642
- Topic.validates_numericality_of :approved, :greater_than => 1, :less_than => 4, :even => true
1643
-
1644
- invalid!([1, 3, 4])
1645
- valid!([2])
1646
- end
1647
-
1648
- def test_validates_numericality_with_numeric_message
1649
- Topic.validates_numericality_of :approved, :less_than => 4, :message => "smaller than %{count}"
1650
- topic = Topic.new("title" => "numeric test", "approved" => 10)
1651
-
1652
- assert !topic.valid?
1653
- assert_equal "smaller than 4", topic.errors.on(:approved)
1654
-
1655
- Topic.validates_numericality_of :approved, :greater_than => 4, :message => "greater than %{count}"
1656
- topic = Topic.new("title" => "numeric test", "approved" => 1)
1657
-
1658
- assert !topic.valid?
1659
- assert_equal "greater than 4", topic.errors.on(:approved)
1660
- end
1661
-
1662
- private
1663
- def invalid!(values, error=nil)
1664
- with_each_topic_approved_value(values) do |topic, value|
1665
- assert !topic.valid?, "#{value.inspect} not rejected as a number"
1666
- assert topic.errors.on(:approved)
1667
- assert_equal error, topic.errors.on(:approved) if error
1668
- end
1669
- end
1670
-
1671
- def valid!(values)
1672
- with_each_topic_approved_value(values) do |topic, value|
1673
- assert topic.valid?, "#{value.inspect} not accepted as a number"
1674
- end
1675
- end
1676
-
1677
- def with_each_topic_approved_value(values)
1678
- topic = Topic.new("title" => "numeric test", "content" => "whatever")
1679
- values.each do |value|
1680
- topic.approved = value
1681
- yield topic, value
1682
- end
1683
- end
1684
- end