ibm_db 3.0.5-x86-mingw32 → 4.0.0-x86-mingw32

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 (586) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +4 -0
  3. data/LICENSE +1 -1
  4. data/MANIFEST +14 -14
  5. data/ParameterizedQueries README +6 -6
  6. data/README +208 -225
  7. data/ext/Makefile.nt32 +181 -181
  8. data/ext/Makefile.nt32.191 +212 -212
  9. data/ext/extconf.rb +291 -291
  10. data/ext/ibm_db.c +11887 -11887
  11. data/ext/ruby_ibm_db.h +241 -241
  12. data/ext/ruby_ibm_db_cli.c +866 -866
  13. data/ext/ruby_ibm_db_cli.h +500 -500
  14. data/init.rb +41 -41
  15. data/lib/IBM_DB.rb +27 -27
  16. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3452 -3177
  17. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -2
  18. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  19. data/lib/mswin32/ibm_db.rb +91 -123
  20. data/lib/mswin32/rb2x/i386/ibm_db.so +0 -0
  21. data/test/active_record/connection_adapters/fake_adapter.rb +49 -46
  22. data/test/assets/example.log +1 -1
  23. data/test/assets/test.txt +1 -1
  24. data/test/cases/adapter_test.rb +351 -276
  25. data/test/cases/adapters/mysql2/active_schema_test.rb +193 -0
  26. data/test/cases/adapters/mysql2/bind_parameter_test.rb +50 -0
  27. data/test/cases/adapters/mysql2/boolean_test.rb +100 -0
  28. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +63 -0
  29. data/test/cases/adapters/mysql2/charset_collation_test.rb +54 -0
  30. data/test/cases/adapters/mysql2/connection_test.rb +210 -0
  31. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +45 -0
  32. data/test/cases/adapters/mysql2/enum_test.rb +26 -0
  33. data/test/cases/adapters/mysql2/explain_test.rb +21 -0
  34. data/test/cases/adapters/mysql2/json_test.rb +195 -0
  35. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +83 -0
  36. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  37. data/test/cases/adapters/mysql2/schema_migrations_test.rb +59 -0
  38. data/test/cases/adapters/mysql2/schema_test.rb +126 -0
  39. data/test/cases/adapters/mysql2/sp_test.rb +36 -0
  40. data/test/cases/adapters/mysql2/sql_types_test.rb +14 -0
  41. data/test/cases/adapters/mysql2/table_options_test.rb +42 -0
  42. data/test/cases/adapters/mysql2/unsigned_type_test.rb +66 -0
  43. data/test/cases/adapters/postgresql/active_schema_test.rb +98 -0
  44. data/test/cases/adapters/postgresql/array_test.rb +339 -0
  45. data/test/cases/adapters/postgresql/bit_string_test.rb +82 -0
  46. data/test/cases/adapters/postgresql/bytea_test.rb +134 -0
  47. data/test/cases/adapters/postgresql/case_insensitive_test.rb +26 -0
  48. data/test/cases/adapters/postgresql/change_schema_test.rb +38 -0
  49. data/test/cases/adapters/postgresql/cidr_test.rb +25 -0
  50. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  51. data/test/cases/adapters/postgresql/collation_test.rb +53 -0
  52. data/test/cases/adapters/postgresql/composite_test.rb +132 -0
  53. data/test/cases/adapters/postgresql/connection_test.rb +257 -0
  54. data/test/cases/adapters/postgresql/datatype_test.rb +92 -0
  55. data/test/cases/adapters/postgresql/domain_test.rb +47 -0
  56. data/test/cases/adapters/postgresql/enum_test.rb +91 -0
  57. data/test/cases/adapters/postgresql/explain_test.rb +20 -0
  58. data/test/cases/adapters/postgresql/extension_migration_test.rb +63 -0
  59. data/test/cases/adapters/postgresql/full_text_test.rb +44 -0
  60. data/test/cases/adapters/postgresql/geometric_test.rb +378 -0
  61. data/test/cases/adapters/postgresql/hstore_test.rb +382 -0
  62. data/test/cases/adapters/postgresql/infinity_test.rb +69 -0
  63. data/test/cases/adapters/postgresql/integer_test.rb +25 -0
  64. data/test/cases/adapters/postgresql/json_test.rb +237 -0
  65. data/test/cases/adapters/postgresql/ltree_test.rb +53 -0
  66. data/test/cases/adapters/postgresql/money_test.rb +96 -0
  67. data/test/cases/adapters/postgresql/network_test.rb +94 -0
  68. data/test/cases/adapters/postgresql/numbers_test.rb +49 -0
  69. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +405 -0
  70. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  71. data/test/cases/adapters/postgresql/quoting_test.rb +44 -0
  72. data/test/cases/adapters/postgresql/range_test.rb +343 -0
  73. data/test/cases/adapters/postgresql/referential_integrity_test.rb +111 -0
  74. data/test/cases/adapters/postgresql/rename_table_test.rb +34 -0
  75. data/test/cases/adapters/postgresql/schema_authorization_test.rb +119 -0
  76. data/test/cases/adapters/postgresql/schema_test.rb +597 -0
  77. data/test/cases/adapters/postgresql/serial_test.rb +154 -0
  78. data/test/cases/adapters/postgresql/statement_pool_test.rb +41 -0
  79. data/test/cases/adapters/postgresql/timestamp_test.rb +90 -0
  80. data/test/cases/adapters/postgresql/type_lookup_test.rb +33 -0
  81. data/test/cases/adapters/postgresql/utils_test.rb +62 -0
  82. data/test/cases/adapters/postgresql/uuid_test.rb +294 -0
  83. data/test/cases/adapters/postgresql/xml_test.rb +54 -0
  84. data/test/cases/adapters/sqlite3/collation_test.rb +53 -0
  85. data/test/cases/adapters/sqlite3/copy_table_test.rb +98 -0
  86. data/test/cases/adapters/sqlite3/explain_test.rb +21 -0
  87. data/test/cases/adapters/sqlite3/quoting_test.rb +101 -0
  88. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +441 -0
  89. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  90. data/test/cases/adapters/sqlite3/statement_pool_test.rb +20 -0
  91. data/test/cases/aggregations_test.rb +168 -158
  92. data/test/cases/ar_schema_test.rb +146 -161
  93. data/test/cases/associations/association_scope_test.rb +16 -21
  94. data/test/cases/associations/belongs_to_associations_test.rb +1141 -1029
  95. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +41 -0
  96. data/test/cases/associations/callbacks_test.rb +190 -192
  97. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
  98. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
  99. data/test/cases/associations/eager_load_nested_include_test.rb +126 -128
  100. data/test/cases/associations/eager_singularization_test.rb +148 -148
  101. data/test/cases/associations/eager_test.rb +1514 -1429
  102. data/test/cases/associations/extension_test.rb +87 -82
  103. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1004 -972
  104. data/test/cases/associations/has_many_associations_test.rb +2501 -2182
  105. data/test/cases/associations/has_many_through_associations_test.rb +1271 -1204
  106. data/test/cases/associations/has_one_associations_test.rb +707 -610
  107. data/test/cases/associations/has_one_through_associations_test.rb +383 -380
  108. data/test/cases/associations/inner_join_association_test.rb +139 -139
  109. data/test/cases/associations/inverse_associations_test.rb +733 -706
  110. data/test/cases/associations/join_model_test.rb +777 -754
  111. data/test/cases/associations/left_outer_join_association_test.rb +88 -0
  112. data/test/cases/associations/nested_through_associations_test.rb +579 -579
  113. data/test/cases/associations/required_test.rb +102 -82
  114. data/test/cases/associations_test.rb +385 -380
  115. data/test/cases/attribute_decorators_test.rb +125 -125
  116. data/test/cases/attribute_methods/read_test.rb +60 -60
  117. data/test/cases/attribute_methods_test.rb +1009 -952
  118. data/test/cases/attribute_set_test.rb +270 -210
  119. data/test/cases/attribute_test.rb +246 -180
  120. data/test/cases/attributes_test.rb +253 -136
  121. data/test/cases/autosave_association_test.rb +1708 -1595
  122. data/test/cases/base_test.rb +1713 -1664
  123. data/test/cases/batches_test.rb +489 -212
  124. data/test/cases/binary_test.rb +44 -52
  125. data/test/cases/bind_parameter_test.rb +110 -100
  126. data/test/cases/cache_key_test.rb +25 -0
  127. data/test/cases/calculations_test.rb +798 -646
  128. data/test/cases/callbacks_test.rb +636 -543
  129. data/test/cases/clone_test.rb +40 -40
  130. data/test/cases/coders/json_test.rb +15 -0
  131. data/test/cases/coders/yaml_column_test.rb +63 -63
  132. data/test/cases/collection_cache_key_test.rb +115 -0
  133. data/test/cases/column_alias_test.rb +17 -17
  134. data/test/cases/column_definition_test.rb +92 -123
  135. data/test/cases/comment_test.rb +143 -0
  136. data/test/cases/connection_adapters/adapter_leasing_test.rb +56 -54
  137. data/test/cases/connection_adapters/connection_handler_test.rb +160 -53
  138. data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
  139. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +255 -293
  140. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +69 -65
  141. data/test/cases/connection_adapters/quoting_test.rb +13 -13
  142. data/test/cases/connection_adapters/schema_cache_test.rb +61 -56
  143. data/test/cases/connection_adapters/type_lookup_test.rb +118 -110
  144. data/test/cases/connection_management_test.rb +112 -122
  145. data/test/cases/connection_pool_test.rb +521 -346
  146. data/test/cases/connection_specification/resolver_test.rb +131 -116
  147. data/test/cases/core_test.rb +112 -112
  148. data/test/cases/counter_cache_test.rb +214 -209
  149. data/test/cases/custom_locking_test.rb +17 -17
  150. data/test/cases/database_statements_test.rb +34 -19
  151. data/test/cases/{invalid_date_test.rb → date_test.rb} +44 -32
  152. data/test/cases/date_time_precision_test.rb +106 -0
  153. data/test/cases/date_time_test.rb +61 -61
  154. data/test/cases/defaults_test.rb +218 -223
  155. data/test/cases/dirty_test.rb +763 -785
  156. data/test/cases/disconnected_test.rb +30 -28
  157. data/test/cases/dup_test.rb +157 -157
  158. data/test/cases/enum_test.rb +444 -290
  159. data/test/cases/errors_test.rb +16 -0
  160. data/test/cases/explain_subscriber_test.rb +64 -64
  161. data/test/cases/explain_test.rb +87 -76
  162. data/test/cases/finder_respond_to_test.rb +60 -60
  163. data/test/cases/finder_test.rb +1294 -1169
  164. data/test/cases/fixture_set/file_test.rb +156 -138
  165. data/test/cases/fixtures_test.rb +988 -908
  166. data/test/cases/forbidden_attributes_protection_test.rb +165 -99
  167. data/test/cases/habtm_destroy_order_test.rb +61 -61
  168. data/test/cases/helper.rb +204 -210
  169. data/test/cases/hot_compatibility_test.rb +142 -54
  170. data/test/cases/i18n_test.rb +45 -45
  171. data/test/cases/inheritance_test.rb +606 -375
  172. data/test/cases/integration_test.rb +155 -139
  173. data/test/cases/invalid_connection_test.rb +24 -22
  174. data/test/cases/invertible_migration_test.rb +387 -295
  175. data/test/cases/json_serialization_test.rb +311 -302
  176. data/test/cases/locking_test.rb +493 -477
  177. data/test/cases/log_subscriber_test.rb +225 -136
  178. data/test/cases/migration/change_schema_test.rb +458 -512
  179. data/test/cases/migration/change_table_test.rb +256 -224
  180. data/test/cases/migration/column_attributes_test.rb +176 -192
  181. data/test/cases/migration/column_positioning_test.rb +56 -56
  182. data/test/cases/migration/columns_test.rb +310 -304
  183. data/test/cases/migration/command_recorder_test.rb +350 -305
  184. data/test/cases/migration/compatibility_test.rb +118 -0
  185. data/test/cases/migration/create_join_table_test.rb +157 -148
  186. data/test/cases/migration/foreign_key_test.rb +360 -328
  187. data/test/cases/migration/helper.rb +39 -39
  188. data/test/cases/migration/index_test.rb +218 -216
  189. data/test/cases/migration/logger_test.rb +36 -36
  190. data/test/cases/migration/pending_migrations_test.rb +52 -53
  191. data/test/cases/migration/references_foreign_key_test.rb +216 -169
  192. data/test/cases/migration/references_index_test.rb +101 -101
  193. data/test/cases/migration/references_statements_test.rb +136 -116
  194. data/test/cases/migration/rename_table_test.rb +93 -93
  195. data/test/cases/migration_test.rb +1157 -959
  196. data/test/cases/migrator_test.rb +470 -388
  197. data/test/cases/mixin_test.rb +68 -70
  198. data/test/cases/modules_test.rb +172 -173
  199. data/test/cases/multiparameter_attributes_test.rb +372 -350
  200. data/test/cases/multiple_db_test.rb +122 -115
  201. data/test/cases/nested_attributes_test.rb +1098 -1070
  202. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
  203. data/test/cases/persistence_test.rb +1001 -909
  204. data/test/cases/pooled_connections_test.rb +81 -81
  205. data/test/cases/primary_keys_test.rb +376 -237
  206. data/test/cases/query_cache_test.rb +446 -326
  207. data/test/cases/quoting_test.rb +202 -156
  208. data/test/cases/readonly_test.rb +119 -118
  209. data/test/cases/reaper_test.rb +85 -85
  210. data/test/cases/reflection_test.rb +509 -463
  211. data/test/cases/relation/delegation_test.rb +63 -68
  212. data/test/cases/relation/merging_test.rb +157 -161
  213. data/test/cases/relation/mutation_test.rb +183 -165
  214. data/test/cases/relation/or_test.rb +92 -0
  215. data/test/cases/relation/predicate_builder_test.rb +16 -14
  216. data/test/cases/relation/record_fetch_warning_test.rb +40 -0
  217. data/test/cases/relation/where_chain_test.rb +105 -181
  218. data/test/cases/relation/where_clause_test.rb +182 -0
  219. data/test/cases/relation/where_test.rb +322 -300
  220. data/test/cases/relation_test.rb +328 -319
  221. data/test/cases/relations_test.rb +2026 -1815
  222. data/test/cases/reload_models_test.rb +22 -22
  223. data/test/cases/result_test.rb +90 -80
  224. data/test/cases/sanitize_test.rb +176 -83
  225. data/test/cases/schema_dumper_test.rb +457 -463
  226. data/test/cases/schema_loading_test.rb +52 -0
  227. data/test/cases/scoping/default_scoping_test.rb +528 -454
  228. data/test/cases/scoping/named_scoping_test.rb +561 -524
  229. data/test/cases/scoping/relation_scoping_test.rb +400 -357
  230. data/test/cases/secure_token_test.rb +32 -0
  231. data/test/cases/serialization_test.rb +104 -104
  232. data/test/cases/serialized_attribute_test.rb +364 -277
  233. data/test/cases/statement_cache_test.rb +136 -98
  234. data/test/cases/store_test.rb +195 -194
  235. data/test/cases/suppressor_test.rb +63 -0
  236. data/test/cases/tasks/database_tasks_test.rb +462 -398
  237. data/test/cases/tasks/mysql_rake_test.rb +345 -324
  238. data/test/cases/tasks/postgresql_rake_test.rb +304 -250
  239. data/test/cases/tasks/sqlite_rake_test.rb +220 -193
  240. data/test/cases/test_case.rb +131 -123
  241. data/test/cases/test_fixtures_test.rb +36 -0
  242. data/test/cases/time_precision_test.rb +102 -0
  243. data/test/cases/timestamp_test.rb +501 -467
  244. data/test/cases/touch_later_test.rb +121 -0
  245. data/test/cases/transaction_callbacks_test.rb +518 -452
  246. data/test/cases/transaction_isolation_test.rb +106 -106
  247. data/test/cases/transactions_test.rb +834 -817
  248. data/test/cases/type/adapter_specific_registry_test.rb +133 -0
  249. data/test/cases/type/date_time_test.rb +14 -0
  250. data/test/cases/type/integer_test.rb +27 -121
  251. data/test/cases/type/string_test.rb +22 -36
  252. data/test/cases/type/type_map_test.rb +177 -177
  253. data/test/cases/type_test.rb +39 -0
  254. data/test/cases/types_test.rb +24 -141
  255. data/test/cases/unconnected_test.rb +33 -33
  256. data/test/cases/validations/absence_validation_test.rb +73 -0
  257. data/test/cases/validations/association_validation_test.rb +97 -86
  258. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
  259. data/test/cases/validations/i18n_validation_test.rb +86 -90
  260. data/test/cases/validations/length_validation_test.rb +79 -47
  261. data/test/cases/validations/presence_validation_test.rb +103 -68
  262. data/test/cases/validations/uniqueness_validation_test.rb +548 -457
  263. data/test/cases/validations_repair_helper.rb +19 -23
  264. data/test/cases/validations_test.rb +194 -165
  265. data/test/cases/view_test.rb +216 -119
  266. data/test/cases/yaml_serialization_test.rb +121 -126
  267. data/test/config.example.yml +97 -0
  268. data/test/config.rb +5 -5
  269. data/test/fixtures/accounts.yml +29 -29
  270. data/test/fixtures/admin/accounts.yml +2 -2
  271. data/test/fixtures/admin/users.yml +10 -10
  272. data/test/fixtures/author_addresses.original +11 -0
  273. data/test/fixtures/author_addresses.yml +17 -17
  274. data/test/fixtures/author_favorites.yml +3 -3
  275. data/test/fixtures/authors.original +17 -0
  276. data/test/fixtures/authors.yml +23 -23
  277. data/test/fixtures/bad_posts.yml +9 -0
  278. data/test/fixtures/binaries.yml +133 -133
  279. data/test/fixtures/books.yml +31 -11
  280. data/test/fixtures/bulbs.yml +5 -5
  281. data/test/fixtures/cars.yml +9 -9
  282. data/test/fixtures/categories.yml +19 -19
  283. data/test/fixtures/categories/special_categories.yml +9 -9
  284. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
  285. data/test/fixtures/categories_ordered.yml +7 -7
  286. data/test/fixtures/categories_posts.yml +31 -31
  287. data/test/fixtures/categorizations.yml +23 -23
  288. data/test/fixtures/clubs.yml +8 -8
  289. data/test/fixtures/collections.yml +3 -3
  290. data/test/fixtures/colleges.yml +3 -3
  291. data/test/fixtures/comments.yml +65 -65
  292. data/test/fixtures/companies.yml +67 -67
  293. data/test/fixtures/computers.yml +10 -10
  294. data/test/fixtures/content.yml +3 -0
  295. data/test/fixtures/content_positions.yml +3 -0
  296. data/test/fixtures/courses.yml +8 -8
  297. data/test/fixtures/customers.yml +25 -25
  298. data/test/fixtures/dashboards.yml +6 -6
  299. data/test/fixtures/dead_parrots.yml +5 -0
  300. data/test/fixtures/developers.yml +22 -22
  301. data/test/fixtures/developers_projects.yml +16 -16
  302. data/test/fixtures/dog_lovers.yml +7 -7
  303. data/test/fixtures/dogs.yml +4 -4
  304. data/test/fixtures/doubloons.yml +3 -3
  305. data/test/fixtures/edges.yml +5 -5
  306. data/test/fixtures/entrants.yml +14 -14
  307. data/test/fixtures/essays.yml +6 -6
  308. data/test/fixtures/faces.yml +11 -11
  309. data/test/fixtures/fk_test_has_fk.yml +3 -3
  310. data/test/fixtures/fk_test_has_pk.yml +1 -1
  311. data/test/fixtures/friendships.yml +4 -4
  312. data/test/fixtures/funny_jokes.yml +10 -10
  313. data/test/fixtures/interests.yml +33 -33
  314. data/test/fixtures/items.yml +3 -3
  315. data/test/fixtures/jobs.yml +7 -7
  316. data/test/fixtures/legacy_things.yml +3 -3
  317. data/test/fixtures/live_parrots.yml +4 -0
  318. data/test/fixtures/mateys.yml +4 -4
  319. data/test/fixtures/member_details.yml +8 -8
  320. data/test/fixtures/member_types.yml +6 -6
  321. data/test/fixtures/members.yml +11 -11
  322. data/test/fixtures/memberships.yml +34 -34
  323. data/test/fixtures/men.yml +5 -5
  324. data/test/fixtures/minimalistics.yml +2 -2
  325. data/test/fixtures/minivans.yml +5 -5
  326. data/test/fixtures/mixed_case_monkeys.yml +6 -6
  327. data/test/fixtures/mixins.yml +29 -29
  328. data/test/fixtures/movies.yml +7 -7
  329. data/test/fixtures/naked/yml/accounts.yml +1 -1
  330. data/test/fixtures/naked/yml/companies.yml +1 -1
  331. data/test/fixtures/naked/yml/courses.yml +1 -1
  332. data/test/fixtures/naked/yml/parrots.yml +2 -0
  333. data/test/fixtures/naked/yml/trees.yml +3 -0
  334. data/test/fixtures/nodes.yml +29 -0
  335. data/test/fixtures/organizations.yml +5 -5
  336. data/test/fixtures/other_comments.yml +6 -0
  337. data/test/fixtures/other_dogs.yml +2 -0
  338. data/test/fixtures/other_posts.yml +7 -0
  339. data/test/fixtures/other_topics.yml +42 -42
  340. data/test/fixtures/owners.yml +9 -9
  341. data/test/fixtures/parrots.yml +27 -27
  342. data/test/fixtures/parrots_pirates.yml +7 -7
  343. data/test/fixtures/people.yml +24 -24
  344. data/test/fixtures/peoples_treasures.yml +3 -3
  345. data/test/fixtures/pets.yml +19 -19
  346. data/test/fixtures/pirates.yml +15 -12
  347. data/test/fixtures/posts.yml +80 -80
  348. data/test/fixtures/price_estimates.yml +16 -7
  349. data/test/fixtures/products.yml +4 -4
  350. data/test/fixtures/projects.yml +7 -7
  351. data/test/fixtures/ratings.yml +14 -14
  352. data/test/fixtures/readers.yml +11 -11
  353. data/test/fixtures/references.yml +17 -17
  354. data/test/fixtures/reserved_words/distinct.yml +5 -5
  355. data/test/fixtures/reserved_words/distinct_select.yml +11 -11
  356. data/test/fixtures/reserved_words/group.yml +14 -14
  357. data/test/fixtures/reserved_words/select.yml +8 -8
  358. data/test/fixtures/reserved_words/values.yml +7 -7
  359. data/test/fixtures/ships.yml +6 -6
  360. data/test/fixtures/speedometers.yml +8 -8
  361. data/test/fixtures/sponsors.yml +12 -12
  362. data/test/fixtures/string_key_objects.yml +7 -7
  363. data/test/fixtures/subscribers.yml +10 -10
  364. data/test/fixtures/subscriptions.yml +12 -12
  365. data/test/fixtures/taggings.yml +78 -78
  366. data/test/fixtures/tags.yml +11 -11
  367. data/test/fixtures/tasks.yml +7 -7
  368. data/test/fixtures/teapots.yml +3 -3
  369. data/test/fixtures/to_be_linked/accounts.yml +2 -2
  370. data/test/fixtures/to_be_linked/users.yml +10 -10
  371. data/test/fixtures/topics.yml +49 -49
  372. data/test/fixtures/toys.yml +14 -14
  373. data/test/fixtures/traffic_lights.yml +9 -9
  374. data/test/fixtures/treasures.yml +10 -10
  375. data/test/fixtures/trees.yml +3 -0
  376. data/test/fixtures/uuid_children.yml +3 -3
  377. data/test/fixtures/uuid_parents.yml +2 -2
  378. data/test/fixtures/variants.yml +4 -4
  379. data/test/fixtures/vegetables.yml +19 -19
  380. data/test/fixtures/vertices.yml +3 -3
  381. data/test/fixtures/warehouse_things.yml +2 -2
  382. data/test/fixtures/zines.yml +5 -5
  383. data/test/migrations/10_urban/9_add_expressions.rb +11 -11
  384. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
  385. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
  386. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -9
  387. data/test/migrations/missing/1_people_have_last_names.rb +9 -9
  388. data/test/migrations/missing/3_we_need_reminders.rb +12 -12
  389. data/test/migrations/missing/4_innocent_jointable.rb +12 -12
  390. data/test/migrations/rename/1_we_need_things.rb +11 -11
  391. data/test/migrations/rename/2_rename_things.rb +9 -9
  392. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
  393. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
  394. data/test/migrations/to_copy2/1_create_articles.rb +7 -7
  395. data/test/migrations/to_copy2/2_create_comments.rb +7 -7
  396. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
  397. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
  398. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
  399. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
  400. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
  401. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
  402. data/test/migrations/valid/2_we_need_reminders.rb +12 -12
  403. data/test/migrations/valid/3_innocent_jointable.rb +12 -12
  404. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
  405. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -12
  406. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -12
  407. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
  408. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
  409. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
  410. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
  411. data/test/models/admin.rb +5 -5
  412. data/test/models/admin/account.rb +3 -3
  413. data/test/models/admin/randomly_named_c1.rb +6 -2
  414. data/test/models/admin/user.rb +40 -40
  415. data/test/models/aircraft.rb +5 -4
  416. data/test/models/arunit2_model.rb +3 -3
  417. data/test/models/author.rb +209 -212
  418. data/test/models/auto_id.rb +4 -4
  419. data/test/models/autoloadable/extra_firm.rb +2 -2
  420. data/test/models/binary.rb +2 -2
  421. data/test/models/bird.rb +12 -12
  422. data/test/models/book.rb +23 -18
  423. data/test/models/boolean.rb +2 -2
  424. data/test/models/bulb.rb +52 -51
  425. data/test/models/cake_designer.rb +3 -3
  426. data/test/models/car.rb +29 -26
  427. data/test/models/carrier.rb +2 -2
  428. data/test/models/cat.rb +10 -0
  429. data/test/models/categorization.rb +19 -19
  430. data/test/models/category.rb +35 -35
  431. data/test/models/chef.rb +8 -7
  432. data/test/models/citation.rb +3 -3
  433. data/test/models/club.rb +25 -23
  434. data/test/models/college.rb +10 -10
  435. data/test/models/column.rb +3 -3
  436. data/test/models/column_name.rb +3 -3
  437. data/test/models/comment.rb +76 -64
  438. data/test/models/company.rb +230 -228
  439. data/test/models/company_in_module.rb +98 -98
  440. data/test/models/computer.rb +3 -3
  441. data/test/models/contact.rb +41 -41
  442. data/test/models/content.rb +40 -0
  443. data/test/models/contract.rb +20 -20
  444. data/test/models/country.rb +7 -7
  445. data/test/models/course.rb +6 -6
  446. data/test/models/customer.rb +83 -77
  447. data/test/models/customer_carrier.rb +14 -14
  448. data/test/models/dashboard.rb +3 -3
  449. data/test/models/default.rb +2 -2
  450. data/test/models/department.rb +4 -4
  451. data/test/models/developer.rb +274 -255
  452. data/test/models/dog.rb +5 -5
  453. data/test/models/dog_lover.rb +5 -5
  454. data/test/models/doubloon.rb +12 -12
  455. data/test/models/drink_designer.rb +3 -3
  456. data/test/models/edge.rb +5 -5
  457. data/test/models/electron.rb +5 -5
  458. data/test/models/engine.rb +4 -4
  459. data/test/models/entrant.rb +3 -3
  460. data/test/models/essay.rb +5 -5
  461. data/test/models/event.rb +3 -3
  462. data/test/models/eye.rb +37 -37
  463. data/test/models/face.rb +9 -9
  464. data/test/models/friendship.rb +6 -6
  465. data/test/models/guid.rb +2 -2
  466. data/test/models/guitar.rb +4 -0
  467. data/test/models/hotel.rb +11 -9
  468. data/test/models/image.rb +3 -3
  469. data/test/models/interest.rb +5 -5
  470. data/test/models/invoice.rb +4 -4
  471. data/test/models/item.rb +7 -7
  472. data/test/models/job.rb +7 -7
  473. data/test/models/joke.rb +7 -7
  474. data/test/models/keyboard.rb +3 -3
  475. data/test/models/legacy_thing.rb +3 -3
  476. data/test/models/lesson.rb +11 -11
  477. data/test/models/line_item.rb +3 -3
  478. data/test/models/liquid.rb +4 -4
  479. data/test/models/man.rb +11 -11
  480. data/test/models/matey.rb +4 -4
  481. data/test/models/member.rb +42 -41
  482. data/test/models/member_detail.rb +8 -7
  483. data/test/models/member_type.rb +3 -3
  484. data/test/models/membership.rb +35 -35
  485. data/test/models/mentor.rb +3 -0
  486. data/test/models/minimalistic.rb +2 -2
  487. data/test/models/minivan.rb +9 -9
  488. data/test/models/mixed_case_monkey.rb +3 -3
  489. data/test/models/mocktail_designer.rb +2 -0
  490. data/test/models/molecule.rb +6 -6
  491. data/test/models/movie.rb +5 -5
  492. data/test/models/node.rb +5 -0
  493. data/test/models/non_primary_key.rb +2 -0
  494. data/test/models/notification.rb +3 -0
  495. data/test/models/order.rb +4 -4
  496. data/test/models/organization.rb +14 -14
  497. data/test/models/other_dog.rb +5 -0
  498. data/test/models/owner.rb +37 -34
  499. data/test/models/parrot.rb +28 -29
  500. data/test/models/person.rb +142 -143
  501. data/test/models/personal_legacy_thing.rb +4 -4
  502. data/test/models/pet.rb +18 -15
  503. data/test/models/pet_treasure.rb +6 -0
  504. data/test/models/pirate.rb +92 -92
  505. data/test/models/possession.rb +3 -3
  506. data/test/models/post.rb +273 -264
  507. data/test/models/price_estimate.rb +4 -4
  508. data/test/models/professor.rb +5 -5
  509. data/test/models/project.rb +40 -31
  510. data/test/models/publisher.rb +2 -2
  511. data/test/models/publisher/article.rb +4 -4
  512. data/test/models/publisher/magazine.rb +3 -3
  513. data/test/models/randomly_named_c1.rb +1 -1
  514. data/test/models/rating.rb +4 -4
  515. data/test/models/reader.rb +23 -23
  516. data/test/models/recipe.rb +3 -0
  517. data/test/models/record.rb +2 -2
  518. data/test/models/reference.rb +22 -22
  519. data/test/models/reply.rb +61 -61
  520. data/test/models/ship.rb +39 -33
  521. data/test/models/ship_part.rb +8 -8
  522. data/test/models/shop.rb +17 -17
  523. data/test/models/shop_account.rb +6 -6
  524. data/test/models/speedometer.rb +6 -6
  525. data/test/models/sponsor.rb +7 -7
  526. data/test/models/string_key_object.rb +3 -3
  527. data/test/models/student.rb +4 -4
  528. data/test/models/subject.rb +16 -16
  529. data/test/models/subscriber.rb +8 -8
  530. data/test/models/subscription.rb +4 -4
  531. data/test/models/tag.rb +13 -7
  532. data/test/models/tagging.rb +13 -13
  533. data/test/models/task.rb +5 -5
  534. data/test/models/topic.rb +118 -124
  535. data/test/models/toy.rb +6 -6
  536. data/test/models/traffic_light.rb +4 -4
  537. data/test/models/treasure.rb +14 -14
  538. data/test/models/treaty.rb +7 -7
  539. data/test/models/tree.rb +3 -0
  540. data/test/models/tuning_peg.rb +4 -0
  541. data/test/models/tyre.rb +11 -11
  542. data/test/models/user.rb +14 -0
  543. data/test/models/uuid_child.rb +3 -3
  544. data/test/models/uuid_item.rb +6 -0
  545. data/test/models/uuid_parent.rb +3 -3
  546. data/test/models/vegetables.rb +24 -24
  547. data/test/models/vehicle.rb +6 -6
  548. data/test/models/vertex.rb +9 -9
  549. data/test/models/warehouse_thing.rb +5 -5
  550. data/test/models/wheel.rb +3 -3
  551. data/test/models/without_table.rb +3 -3
  552. data/test/models/zine.rb +3 -3
  553. data/test/schema/mysql2_specific_schema.rb +68 -58
  554. data/test/schema/oracle_specific_schema.rb +40 -43
  555. data/test/schema/postgresql_specific_schema.rb +114 -202
  556. data/test/schema/schema.rb +1057 -952
  557. data/test/schema/schema.rb.original +1057 -0
  558. data/test/schema/sqlite_specific_schema.rb +18 -22
  559. data/test/support/config.rb +43 -43
  560. data/test/support/connection.rb +23 -22
  561. data/test/support/connection_helper.rb +14 -14
  562. data/test/support/ddl_helper.rb +8 -8
  563. data/test/support/schema_dumping_helper.rb +20 -20
  564. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  565. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  566. metadata +129 -28
  567. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  568. data/lib/mswin32/rb21x/i386/ibm_db.so +0 -0
  569. data/lib/mswin32/rb22x/i386/ibm_db.so +0 -0
  570. data/lib/mswin32/rb23x/i386/ibm_db.so +0 -0
  571. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +0 -26
  572. data/test/cases/attribute_methods/serialization_test.rb +0 -29
  573. data/test/cases/migration/change_schema_test - Copy.rb +0 -448
  574. data/test/cases/migration/foreign_key_test - Changed.rb +0 -325
  575. data/test/cases/migration/table_and_index_test.rb +0 -24
  576. data/test/cases/relation/where_test2.rb +0 -36
  577. data/test/cases/type/decimal_test.rb +0 -56
  578. data/test/cases/type/unsigned_integer_test.rb +0 -18
  579. data/test/cases/xml_serialization_test.rb +0 -457
  580. data/test/connections/native_ibm_db/connection.rb +0 -44
  581. data/test/fixtures/naked/csv/accounts.csv +0 -1
  582. data/test/schema/i5/ibm_db_specific_schema.rb +0 -137
  583. data/test/schema/ids/ibm_db_specific_schema.rb +0 -140
  584. data/test/schema/luw/ibm_db_specific_schema.rb +0 -137
  585. data/test/schema/mysql_specific_schema.rb +0 -70
  586. data/test/schema/zOS/ibm_db_specific_schema.rb +0 -208
@@ -1,68 +1,103 @@
1
- # encoding: utf-8
2
- require "cases/helper"
3
- require 'models/man'
4
- require 'models/face'
5
- require 'models/interest'
6
- require 'models/speedometer'
7
- require 'models/dashboard'
8
-
9
- class PresenceValidationTest < ActiveRecord::TestCase
10
- class Boy < Man; end
11
-
12
- repair_validations(Boy)
13
-
14
- def test_validates_presence_of_non_association
15
- Boy.validates_presence_of(:name)
16
- b = Boy.new
17
- assert b.invalid?
18
-
19
- b.name = "Alex"
20
- assert b.valid?
21
- end
22
-
23
- def test_validates_presence_of_has_one
24
- Boy.validates_presence_of(:face)
25
- b = Boy.new
26
- assert b.invalid?, "should not be valid if has_one association missing"
27
- assert_equal 1, b.errors[:face].size, "validates_presence_of should only add one error"
28
- end
29
-
30
- def test_validates_presence_of_has_one_marked_for_destruction
31
- Boy.validates_presence_of(:face)
32
- b = Boy.new
33
- f = Face.new
34
- b.face = f
35
- assert b.valid?
36
-
37
- f.mark_for_destruction
38
- assert b.invalid?
39
- end
40
-
41
- def test_validates_presence_of_has_many_marked_for_destruction
42
- Boy.validates_presence_of(:interests)
43
- b = Boy.new
44
- b.interests << [i1 = Interest.new, i2 = Interest.new]
45
- assert b.valid?
46
-
47
- i1.mark_for_destruction
48
- assert b.valid?
49
-
50
- i2.mark_for_destruction
51
- assert b.invalid?
52
- end
53
-
54
- def test_validates_presence_doesnt_convert_to_array
55
- speedometer = Class.new(Speedometer)
56
- speedometer.validates_presence_of :dashboard
57
-
58
- dash = Dashboard.new
59
-
60
- # dashboard has to_a method
61
- def dash.to_a; ['(/)', '(\)']; end
62
-
63
- s = speedometer.new
64
- s.dashboard = dash
65
-
66
- assert_nothing_raised { s.valid? }
67
- end
68
- end
1
+ require "cases/helper"
2
+ require 'models/man'
3
+ require 'models/face'
4
+ require 'models/interest'
5
+ require 'models/speedometer'
6
+ require 'models/dashboard'
7
+
8
+ class PresenceValidationTest < ActiveRecord::TestCase
9
+ class Boy < Man; end
10
+
11
+ repair_validations(Boy)
12
+
13
+ def test_validates_presence_of_non_association
14
+ Boy.validates_presence_of(:name)
15
+ b = Boy.new
16
+ assert b.invalid?
17
+
18
+ b.name = "Alex"
19
+ assert b.valid?
20
+ end
21
+
22
+ def test_validates_presence_of_has_one
23
+ Boy.validates_presence_of(:face)
24
+ b = Boy.new
25
+ assert b.invalid?, "should not be valid if has_one association missing"
26
+ assert_equal 1, b.errors[:face].size, "validates_presence_of should only add one error"
27
+ end
28
+
29
+ def test_validates_presence_of_has_one_marked_for_destruction
30
+ Boy.validates_presence_of(:face)
31
+ b = Boy.new
32
+ f = Face.new
33
+ b.face = f
34
+ assert b.valid?
35
+
36
+ f.mark_for_destruction
37
+ assert b.invalid?
38
+ end
39
+
40
+ def test_validates_presence_of_has_many_marked_for_destruction
41
+ Boy.validates_presence_of(:interests)
42
+ b = Boy.new
43
+ b.interests << [i1 = Interest.new, i2 = Interest.new]
44
+ assert b.valid?
45
+
46
+ i1.mark_for_destruction
47
+ assert b.valid?
48
+
49
+ i2.mark_for_destruction
50
+ assert b.invalid?
51
+ end
52
+
53
+ def test_validates_presence_doesnt_convert_to_array
54
+ speedometer = Class.new(Speedometer)
55
+ speedometer.validates_presence_of :dashboard
56
+
57
+ dash = Dashboard.new
58
+
59
+ # dashboard has to_a method
60
+ def dash.to_a; ['(/)', '(\)']; end
61
+
62
+ s = speedometer.new
63
+ s.dashboard = dash
64
+
65
+ assert_nothing_raised { s.valid? }
66
+ end
67
+
68
+ def test_validates_presence_of_virtual_attribute_on_model
69
+ repair_validations(Interest) do
70
+ Interest.send(:attr_accessor, :abbreviation)
71
+ Interest.validates_presence_of(:topic)
72
+ Interest.validates_presence_of(:abbreviation)
73
+
74
+ interest = Interest.create!(topic: 'Thought Leadering', abbreviation: 'tl')
75
+ assert interest.valid?
76
+
77
+ interest.abbreviation = ''
78
+
79
+ assert interest.invalid?
80
+ end
81
+ end
82
+
83
+ def test_validations_run_on_persisted_record
84
+ repair_validations(Interest) do
85
+ interest = Interest.new
86
+ interest.save!
87
+ assert_predicate interest, :valid?
88
+
89
+ Interest.validates_presence_of(:topic)
90
+
91
+ assert_not_predicate interest, :valid?
92
+ end
93
+ end
94
+
95
+ def test_validates_presence_with_on_context
96
+ repair_validations(Interest) do
97
+ Interest.validates_presence_of(:topic, on: :required_name)
98
+ interest = Interest.new
99
+ interest.save!
100
+ assert_not interest.valid?(:required_name)
101
+ end
102
+ end
103
+ end
@@ -1,457 +1,548 @@
1
- # encoding: utf-8
2
- require "cases/helper"
3
- require 'models/topic'
4
- require 'models/reply'
5
- require 'models/warehouse_thing'
6
- require 'models/guid'
7
- require 'models/event'
8
- require 'models/dashboard'
9
-
10
- class Wizard < ActiveRecord::Base
11
- self.abstract_class = true
12
-
13
- validates_uniqueness_of :name
14
- end
15
-
16
- class IneptWizard < Wizard
17
- validates_uniqueness_of :city
18
- end
19
-
20
- class Conjurer < IneptWizard
21
- end
22
-
23
- class Thaumaturgist < IneptWizard
24
- end
25
-
26
- class ReplyTitle; end
27
-
28
- class ReplyWithTitleObject < Reply
29
- validates_uniqueness_of :content, :scope => :title
30
-
31
- def title; ReplyTitle.new; end
32
- end
33
-
34
- class Employee < ActiveRecord::Base
35
- self.table_name = 'postgresql_arrays'
36
- validates_uniqueness_of :nicknames
37
- end
38
-
39
- class TopicWithUniqEvent < Topic
40
- belongs_to :event, foreign_key: :parent_id
41
- validates :event, uniqueness: true
42
- end
43
-
44
- class BigIntTest < ActiveRecord::Base
45
- INT_MAX_VALUE = 2147483647
46
- self.table_name = 'cars'
47
- validates :engines_count, uniqueness: true, inclusion: { in: 0..INT_MAX_VALUE }
48
- end
49
-
50
- class BigIntReverseTest < ActiveRecord::Base
51
- INT_MAX_VALUE = 2147483647
52
- self.table_name = 'cars'
53
- validates :engines_count, inclusion: { in: 0..INT_MAX_VALUE }
54
- validates :engines_count, uniqueness: true
55
- end
56
-
57
- class UniquenessValidationTest < ActiveRecord::TestCase
58
- INT_MAX_VALUE = 2147483647
59
-
60
- fixtures :topics, 'warehouse_things'
61
-
62
- repair_validations(Topic, Reply)
63
-
64
- def test_validate_uniqueness
65
- Topic.validates_uniqueness_of(:title)
66
-
67
- t = Topic.new("title" => "I'm uniqué!")
68
- assert t.save, "Should save t as unique"
69
-
70
- t.content = "Remaining unique"
71
- assert t.save, "Should still save t as unique"
72
-
73
- t2 = Topic.new("title" => "I'm uniqué!")
74
- assert !t2.valid?, "Shouldn't be valid"
75
- assert !t2.save, "Shouldn't save t2 as unique"
76
- assert_equal ["has already been taken"], t2.errors[:title]
77
-
78
- t2.title = "Now I am really also unique"
79
- assert t2.save, "Should now save t2 as unique"
80
- end
81
-
82
- def test_validate_uniqueness_with_alias_attribute
83
- Topic.alias_attribute :new_title, :title
84
- Topic.validates_uniqueness_of(:new_title)
85
-
86
- topic = Topic.new(new_title: 'abc')
87
- assert topic.valid?
88
- end
89
-
90
- def test_validates_uniqueness_with_nil_value
91
- Topic.validates_uniqueness_of(:title)
92
-
93
- t = Topic.new("title" => nil)
94
- assert t.save, "Should save t as unique"
95
-
96
- t2 = Topic.new("title" => nil)
97
- assert !t2.valid?, "Shouldn't be valid"
98
- assert !t2.save, "Shouldn't save t2 as unique"
99
- assert_equal ["has already been taken"], t2.errors[:title]
100
- end
101
-
102
- def test_validates_uniqueness_with_validates
103
- Topic.validates :title, :uniqueness => true
104
- Topic.create!('title' => 'abc')
105
-
106
- t2 = Topic.new('title' => 'abc')
107
- assert !t2.valid?
108
- assert t2.errors[:title]
109
- end
110
-
111
- def test_validate_uniqueness_when_integer_out_of_range
112
- entry = BigIntTest.create(engines_count: INT_MAX_VALUE + 1)
113
- assert_equal entry.errors[:engines_count], ['is not included in the list']
114
- end
115
-
116
- def test_validate_uniqueness_when_integer_out_of_range_show_order_does_not_matter
117
- entry = BigIntReverseTest.create(engines_count: INT_MAX_VALUE + 1)
118
- assert_equal entry.errors[:engines_count], ['is not included in the list']
119
- end
120
-
121
- def test_validates_uniqueness_with_newline_chars
122
- Topic.validates_uniqueness_of(:title, :case_sensitive => false)
123
-
124
- t = Topic.new("title" => "new\nline")
125
- assert t.save, "Should save t as unique"
126
- end
127
-
128
- def test_validate_uniqueness_with_scope
129
- Reply.validates_uniqueness_of(:content, :scope => "parent_id")
130
-
131
- t = Topic.create("title" => "I'm unique!")
132
-
133
- r1 = t.replies.create "title" => "r1", "content" => "hello world"
134
- assert r1.valid?, "Saving r1"
135
-
136
- r2 = t.replies.create "title" => "r2", "content" => "hello world"
137
- assert !r2.valid?, "Saving r2 first time"
138
-
139
- r2.content = "something else"
140
- assert r2.save, "Saving r2 second time"
141
-
142
- t2 = Topic.create("title" => "I'm unique too!")
143
- r3 = t2.replies.create "title" => "r3", "content" => "hello world"
144
- assert r3.valid?, "Saving r3"
145
- end
146
-
147
- def test_validate_uniqueness_with_object_scope
148
- Reply.validates_uniqueness_of(:content, :scope => :topic)
149
-
150
- t = Topic.create("title" => "I'm unique!")
151
-
152
- r1 = t.replies.create "title" => "r1", "content" => "hello world"
153
- assert r1.valid?, "Saving r1"
154
-
155
- r2 = t.replies.create "title" => "r2", "content" => "hello world"
156
- assert !r2.valid?, "Saving r2 first time"
157
- end
158
-
159
- def test_validate_uniqueness_with_composed_attribute_scope
160
- r1 = ReplyWithTitleObject.create "title" => "r1", "content" => "hello world"
161
- assert r1.valid?, "Saving r1"
162
-
163
- r2 = ReplyWithTitleObject.create "title" => "r1", "content" => "hello world"
164
- assert !r2.valid?, "Saving r2 first time"
165
- end
166
-
167
- def test_validate_uniqueness_with_object_arg
168
- Reply.validates_uniqueness_of(:topic)
169
-
170
- t = Topic.create("title" => "I'm unique!")
171
-
172
- r1 = t.replies.create "title" => "r1", "content" => "hello world"
173
- assert r1.valid?, "Saving r1"
174
-
175
- r2 = t.replies.create "title" => "r2", "content" => "hello world"
176
- assert !r2.valid?, "Saving r2 first time"
177
- end
178
-
179
- def test_validate_uniqueness_scoped_to_defining_class
180
- t = Topic.create("title" => "What, me worry?")
181
-
182
- r1 = t.unique_replies.create "title" => "r1", "content" => "a barrel of fun"
183
- assert r1.valid?, "Saving r1"
184
-
185
- r2 = t.silly_unique_replies.create "title" => "r2", "content" => "a barrel of fun"
186
- assert !r2.valid?, "Saving r2"
187
-
188
- # Should succeed as validates_uniqueness_of only applies to
189
- # UniqueReply and its subclasses
190
- r3 = t.replies.create "title" => "r2", "content" => "a barrel of fun"
191
- assert r3.valid?, "Saving r3"
192
- end
193
-
194
- def test_validate_uniqueness_with_scope_array
195
- Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
196
-
197
- t = Topic.create("title" => "The earth is actually flat!")
198
-
199
- r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
200
- assert r1.valid?, "Saving r1"
201
-
202
- r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
203
- assert !r2.valid?, "Saving r2. Double reply by same author."
204
-
205
- r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
206
- assert r2.save, "Saving r2 the second time."
207
-
208
- r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
209
- assert !r3.valid?, "Saving r3"
210
-
211
- r3.author_name = "jj"
212
- assert r3.save, "Saving r3 the second time."
213
-
214
- r3.author_name = "jeremy"
215
- assert !r3.save, "Saving r3 the third time."
216
- end
217
-
218
- def test_validate_case_insensitive_uniqueness
219
- Topic.validates_uniqueness_of(:title, :parent_id, :case_sensitive => false, :allow_nil => true)
220
-
221
- t = Topic.new("title" => "I'm unique!", :parent_id => 2)
222
- assert t.save, "Should save t as unique"
223
-
224
- t.content = "Remaining unique"
225
- assert t.save, "Should still save t as unique"
226
-
227
- t2 = Topic.new("title" => "I'm UNIQUE!", :parent_id => 1)
228
- assert !t2.valid?, "Shouldn't be valid"
229
- assert !t2.save, "Shouldn't save t2 as unique"
230
- assert t2.errors[:title].any?
231
- assert t2.errors[:parent_id].any?
232
- assert_equal ["has already been taken"], t2.errors[:title]
233
-
234
- t2.title = "I'm truly UNIQUE!"
235
- assert !t2.valid?, "Shouldn't be valid"
236
- assert !t2.save, "Shouldn't save t2 as unique"
237
- assert t2.errors[:title].empty?
238
- assert t2.errors[:parent_id].any?
239
-
240
- t2.parent_id = 4
241
- assert t2.save, "Should now save t2 as unique"
242
-
243
- t2.parent_id = nil
244
- t2.title = nil
245
- assert t2.valid?, "should validate with nil"
246
- assert t2.save, "should save with nil"
247
-
248
- t_utf8 = Topic.new("title" => тоже уникальный!")
249
- assert t_utf8.save, "Should save t_utf8 as unique"
250
-
251
- # If database hasn't UTF-8 character set, this test fails
252
- if Topic.all.merge!(:select => 'LOWER(title) AS title').find(t_utf8.id).title == "я тоже уникальный!"
253
- t2_utf8 = Topic.new("title" => "я тоже УНИКАЛЬНЫЙ!")
254
- assert !t2_utf8.valid?, "Shouldn't be valid"
255
- assert !t2_utf8.save, "Shouldn't save t2_utf8 as unique"
256
- end
257
- end
258
-
259
- def test_validate_case_sensitive_uniqueness_with_special_sql_like_chars
260
- Topic.validates_uniqueness_of(:title, :case_sensitive => true)
261
-
262
- t = Topic.new("title" => "I'm unique!")
263
- assert t.save, "Should save t as unique"
264
-
265
- t2 = Topic.new("title" => "I'm %")
266
- assert t2.save, "Should save t2 as unique"
267
-
268
- t3 = Topic.new("title" => "I'm uniqu_!")
269
- assert t3.save, "Should save t3 as unique"
270
- end
271
-
272
- def test_validate_case_insensitive_uniqueness_with_special_sql_like_chars
273
- Topic.validates_uniqueness_of(:title, :case_sensitive => false)
274
-
275
- t = Topic.new("title" => "I'm unique!")
276
- assert t.save, "Should save t as unique"
277
-
278
- t2 = Topic.new("title" => "I'm %")
279
- assert t2.save, "Should save t2 as unique"
280
-
281
- t3 = Topic.new("title" => "I'm uniqu_!")
282
- assert t3.save, "Should save t3 as unique"
283
- end
284
-
285
- def test_validate_case_sensitive_uniqueness
286
- Topic.validates_uniqueness_of(:title, :case_sensitive => true, :allow_nil => true)
287
-
288
- t = Topic.new("title" => "I'm unique!")
289
- assert t.save, "Should save t as unique"
290
-
291
- t.content = "Remaining unique"
292
- assert t.save, "Should still save t as unique"
293
-
294
- t2 = Topic.new("title" => "I'M UNIQUE!")
295
- assert t2.valid?, "Should be valid"
296
- assert t2.save, "Should save t2 as unique"
297
- assert t2.errors[:title].empty?
298
- assert t2.errors[:parent_id].empty?
299
- assert_not_equal ["has already been taken"], t2.errors[:title]
300
-
301
- t3 = Topic.new("title" => "I'M uNiQUe!")
302
- assert t3.valid?, "Should be valid"
303
- assert t3.save, "Should save t2 as unique"
304
- assert t3.errors[:title].empty?
305
- assert t3.errors[:parent_id].empty?
306
- assert_not_equal ["has already been taken"], t3.errors[:title]
307
- end
308
-
309
- def test_validate_case_sensitive_uniqueness_with_attribute_passed_as_integer
310
- Topic.validates_uniqueness_of(:title, :case_sensitive => true)
311
- Topic.create!('title' => 101)
312
-
313
- t2 = Topic.new('title' => 101)
314
- assert !t2.valid?
315
- assert t2.errors[:title]
316
- end
317
-
318
- def test_validate_uniqueness_with_non_standard_table_names
319
- i1 = WarehouseThing.create(:value => 1000)
320
- assert !i1.valid?, "i1 should not be valid"
321
- assert i1.errors[:value].any?, "Should not be empty"
322
- end
323
-
324
- def test_validates_uniqueness_inside_scoping
325
- Topic.validates_uniqueness_of(:title)
326
-
327
- Topic.where(:author_name => "David").scoping do
328
- t1 = Topic.new("title" => "I'm unique!", "author_name" => "Mary")
329
- assert t1.save
330
- t2 = Topic.new("title" => "I'm unique!", "author_name" => "David")
331
- assert !t2.valid?
332
- end
333
- end
334
-
335
- def test_validate_uniqueness_with_columns_which_are_sql_keywords
336
- repair_validations(Guid) do
337
- Guid.validates_uniqueness_of :key
338
- g = Guid.new
339
- g.key = "foo"
340
- assert_nothing_raised { !g.valid? }
341
- end
342
- end
343
-
344
- def test_validate_uniqueness_with_limit
345
- # Event.title is limited to 5 characters
346
- e1 = Event.create(:title => "abcde")
347
- assert e1.valid?, "Could not create an event with a unique, 5 character title"
348
- e2 = Event.create(:title => "abcdefgh")
349
- assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique"
350
- end
351
-
352
- def test_validate_uniqueness_with_limit_and_utf8
353
- unless current_adapter?(:IBM_DBAdapter)
354
- # Limit for the varchar field is number of bytes and not characters for DB2. Hence the below test cases is expected to fail.
355
- # Event.title is limited to 5 characters
356
- e1 = Event.create(:title => "一二三四五")
357
- assert e1.valid?, "Could not create an event with a unique, 5 character title"
358
- e2 = Event.create(:title => "一二三四五六七八")
359
- assert !e2.valid?, "Created an event whose title, with limit taken into account, is not unique"
360
- end
361
- end
362
-
363
- def test_validate_straight_inheritance_uniqueness
364
- w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork")
365
- assert w1.valid?, "Saving w1"
366
-
367
- # Should use validation from base class (which is abstract)
368
- w2 = IneptWizard.new(:name => "Rincewind", :city => "Quirm")
369
- assert !w2.valid?, "w2 shouldn't be valid"
370
- assert w2.errors[:name].any?, "Should have errors for name"
371
- assert_equal ["has already been taken"], w2.errors[:name], "Should have uniqueness message for name"
372
-
373
- w3 = Conjurer.new(:name => "Rincewind", :city => "Quirm")
374
- assert !w3.valid?, "w3 shouldn't be valid"
375
- assert w3.errors[:name].any?, "Should have errors for name"
376
- assert_equal ["has already been taken"], w3.errors[:name], "Should have uniqueness message for name"
377
-
378
- w4 = Conjurer.create(:name => "The Amazing Bonko", :city => "Quirm")
379
- assert w4.valid?, "Saving w4"
380
-
381
- w5 = Thaumaturgist.new(:name => "The Amazing Bonko", :city => "Lancre")
382
- assert !w5.valid?, "w5 shouldn't be valid"
383
- assert w5.errors[:name].any?, "Should have errors for name"
384
- assert_equal ["has already been taken"], w5.errors[:name], "Should have uniqueness message for name"
385
-
386
- w6 = Thaumaturgist.new(:name => "Mustrum Ridcully", :city => "Quirm")
387
- assert !w6.valid?, "w6 shouldn't be valid"
388
- assert w6.errors[:city].any?, "Should have errors for city"
389
- assert_equal ["has already been taken"], w6.errors[:city], "Should have uniqueness message for city"
390
- end
391
-
392
- def test_validate_uniqueness_with_conditions
393
- Topic.validates_uniqueness_of :title, conditions: -> { where(approved: true) }
394
- Topic.create("title" => "I'm a topic", "approved" => true)
395
- Topic.create("title" => "I'm an unapproved topic", "approved" => false)
396
-
397
- t3 = Topic.new("title" => "I'm a topic", "approved" => true)
398
- assert !t3.valid?, "t3 shouldn't be valid"
399
-
400
- t4 = Topic.new("title" => "I'm an unapproved topic", "approved" => false)
401
- assert t4.valid?, "t4 should be valid"
402
- end
403
-
404
- def test_validate_uniqueness_with_non_callable_conditions_is_not_supported
405
- assert_raises(ArgumentError) {
406
- Topic.validates_uniqueness_of :title, conditions: Topic.where(approved: true)
407
- }
408
- end
409
-
410
- if current_adapter? :PostgreSQLAdapter
411
- def test_validate_uniqueness_with_array_column
412
- e1 = Employee.create("nicknames" => ["john", "johnny"], "commission_by_quarter" => [1000, 1200])
413
- assert e1.persisted?, "Saving e1"
414
-
415
- e2 = Employee.create("nicknames" => ["john", "johnny"], "commission_by_quarter" => [2200])
416
- assert !e2.persisted?, "e2 shouldn't be valid"
417
- assert e2.errors[:nicknames].any?, "Should have errors for nicknames"
418
- assert_equal ["has already been taken"], e2.errors[:nicknames], "Should have uniqueness message for nicknames"
419
- end
420
- end
421
-
422
- def test_validate_uniqueness_on_existing_relation
423
- event = Event.create
424
- assert TopicWithUniqEvent.create(event: event).valid?
425
-
426
- topic = TopicWithUniqEvent.new(event: event)
427
- assert_not topic.valid?
428
- assert_equal ['has already been taken'], topic.errors[:event]
429
- end
430
-
431
- def test_validate_uniqueness_on_empty_relation
432
- topic = TopicWithUniqEvent.new
433
- assert topic.valid?
434
- end
435
-
436
- def test_validate_uniqueness_without_primary_key
437
- klass = Class.new(ActiveRecord::Base) do
438
- self.table_name = "dashboards"
439
-
440
- validates_uniqueness_of :dashboard_id
441
-
442
- def self.name; "Dashboard" end
443
- end
444
-
445
- abc = klass.create!(dashboard_id: "abc")
446
- assert klass.new(dashboard_id: "xyz").valid?
447
- assert_not klass.new(dashboard_id: "abc").valid?
448
-
449
- abc.dashboard_id = "def"
450
-
451
- e = assert_raises ActiveRecord::UnknownPrimaryKey do
452
- abc.save!
453
- end
454
- assert_match(/\AUnknown primary key for table dashboards in model/, e.message)
455
- assert_match(/Can not validate uniqueness for persisted record without primary key.\z/, e.message)
456
- end
457
- end
1
+ require "cases/helper"
2
+ require "models/topic"
3
+ require "models/reply"
4
+ require "models/warehouse_thing"
5
+ require "models/guid"
6
+ require "models/event"
7
+ require "models/dashboard"
8
+ require "models/uuid_item"
9
+ require "models/author"
10
+ require "models/person"
11
+ require "models/essay"
12
+
13
+ class Wizard < ActiveRecord::Base
14
+ self.abstract_class = true
15
+
16
+ validates_uniqueness_of :name
17
+ end
18
+
19
+ class IneptWizard < Wizard
20
+ validates_uniqueness_of :city
21
+ end
22
+
23
+ class Conjurer < IneptWizard
24
+ end
25
+
26
+ class Thaumaturgist < IneptWizard
27
+ end
28
+
29
+ class ReplyTitle; end
30
+
31
+ class ReplyWithTitleObject < Reply
32
+ validates_uniqueness_of :content, :scope => :title
33
+
34
+ def title; ReplyTitle.new; end
35
+ end
36
+
37
+ class TopicWithUniqEvent < Topic
38
+ belongs_to :event, foreign_key: :parent_id
39
+ validates :event, uniqueness: true
40
+ end
41
+
42
+ class BigIntTest < ActiveRecord::Base
43
+ INT_MAX_VALUE = 2147483647
44
+ self.table_name = 'cars'
45
+ validates :engines_count, uniqueness: true, inclusion: { in: 0..INT_MAX_VALUE }
46
+ end
47
+
48
+ class BigIntReverseTest < ActiveRecord::Base
49
+ INT_MAX_VALUE = 2147483647
50
+ self.table_name = 'cars'
51
+ validates :engines_count, inclusion: { in: 0..INT_MAX_VALUE }
52
+ validates :engines_count, uniqueness: true
53
+ end
54
+
55
+ class CoolTopic < Topic
56
+ validates_uniqueness_of :id
57
+ end
58
+
59
+ class TopicWithAfterCreate < Topic
60
+ after_create :set_author
61
+
62
+ def set_author
63
+ update_attributes!(:author_name => "#{title} #{id}")
64
+ end
65
+ end
66
+
67
+ class UniquenessValidationTest < ActiveRecord::TestCase
68
+ INT_MAX_VALUE = 2147483647
69
+
70
+ fixtures :topics, 'warehouse_things'
71
+
72
+ repair_validations(Topic, Reply)
73
+
74
+ def test_validate_uniqueness
75
+ Topic.validates_uniqueness_of(:title)
76
+
77
+ t = Topic.new("title" => "I'm uniqué!")
78
+ assert t.save, "Should save t as unique"
79
+
80
+ t.content = "Remaining unique"
81
+ assert t.save, "Should still save t as unique"
82
+
83
+ t2 = Topic.new("title" => "I'm uniqué!")
84
+ assert !t2.valid?, "Shouldn't be valid"
85
+ assert !t2.save, "Shouldn't save t2 as unique"
86
+ assert_equal ["has already been taken"], t2.errors[:title]
87
+
88
+ t2.title = "Now I am really also unique"
89
+ assert t2.save, "Should now save t2 as unique"
90
+ end
91
+
92
+ def test_validate_uniqueness_with_alias_attribute
93
+ Topic.alias_attribute :new_title, :title
94
+ Topic.validates_uniqueness_of(:new_title)
95
+
96
+ topic = Topic.new(new_title: 'abc')
97
+ assert topic.valid?
98
+ end
99
+
100
+ def test_validates_uniqueness_with_nil_value
101
+ Topic.validates_uniqueness_of(:title)
102
+
103
+ t = Topic.new("title" => nil)
104
+ assert t.save, "Should save t as unique"
105
+
106
+ t2 = Topic.new("title" => nil)
107
+ assert !t2.valid?, "Shouldn't be valid"
108
+ assert !t2.save, "Shouldn't save t2 as unique"
109
+ assert_equal ["has already been taken"], t2.errors[:title]
110
+ end
111
+
112
+ def test_validates_uniqueness_with_validates
113
+ Topic.validates :title, :uniqueness => true
114
+ Topic.create!('title' => 'abc')
115
+
116
+ t2 = Topic.new('title' => 'abc')
117
+ assert !t2.valid?
118
+ assert t2.errors[:title]
119
+ end
120
+
121
+ def test_validate_uniqueness_when_integer_out_of_range
122
+ entry = BigIntTest.create(engines_count: INT_MAX_VALUE + 1)
123
+ assert_equal entry.errors[:engines_count], ['is not included in the list']
124
+ end
125
+
126
+ def test_validate_uniqueness_when_integer_out_of_range_show_order_does_not_matter
127
+ entry = BigIntReverseTest.create(engines_count: INT_MAX_VALUE + 1)
128
+ assert_equal entry.errors[:engines_count], ['is not included in the list']
129
+ end
130
+
131
+ def test_validates_uniqueness_with_newline_chars
132
+ Topic.validates_uniqueness_of(:title, :case_sensitive => false)
133
+
134
+ t = Topic.new("title" => "new\nline")
135
+ assert t.save, "Should save t as unique"
136
+ end
137
+
138
+ def test_validate_uniqueness_with_scope
139
+ Reply.validates_uniqueness_of(:content, :scope => "parent_id")
140
+
141
+ t = Topic.create("title" => "I'm unique!")
142
+
143
+ r1 = t.replies.create "title" => "r1", "content" => "hello world"
144
+ assert r1.valid?, "Saving r1"
145
+
146
+ r2 = t.replies.create "title" => "r2", "content" => "hello world"
147
+ assert !r2.valid?, "Saving r2 first time"
148
+
149
+ r2.content = "something else"
150
+ assert r2.save, "Saving r2 second time"
151
+
152
+ t2 = Topic.create("title" => "I'm unique too!")
153
+ r3 = t2.replies.create "title" => "r3", "content" => "hello world"
154
+ assert r3.valid?, "Saving r3"
155
+ end
156
+
157
+ def test_validate_uniqueness_with_object_scope
158
+ Reply.validates_uniqueness_of(:content, :scope => :topic)
159
+
160
+ t = Topic.create("title" => "I'm unique!")
161
+
162
+ r1 = t.replies.create "title" => "r1", "content" => "hello world"
163
+ assert r1.valid?, "Saving r1"
164
+
165
+ r2 = t.replies.create "title" => "r2", "content" => "hello world"
166
+ assert !r2.valid?, "Saving r2 first time"
167
+ end
168
+
169
+ def test_validate_uniqueness_with_polymorphic_object_scope
170
+ Essay.validates_uniqueness_of(:name, scope: :writer)
171
+
172
+ a = Author.create(name: "Sergey")
173
+ p = Person.create(first_name: "Sergey")
174
+
175
+ e1 = a.essays.create(name: "Essay")
176
+ assert e1.valid?, "Saving e1"
177
+
178
+ e2 = p.essays.create(name: "Essay")
179
+ assert e2.valid?, "Saving e2"
180
+ end
181
+
182
+ def test_validate_uniqueness_with_composed_attribute_scope
183
+ r1 = ReplyWithTitleObject.create "title" => "r1", "content" => "hello world"
184
+ assert r1.valid?, "Saving r1"
185
+
186
+ r2 = ReplyWithTitleObject.create "title" => "r1", "content" => "hello world"
187
+ assert !r2.valid?, "Saving r2 first time"
188
+ end
189
+
190
+ def test_validate_uniqueness_with_object_arg
191
+ Reply.validates_uniqueness_of(:topic)
192
+
193
+ t = Topic.create("title" => "I'm unique!")
194
+
195
+ r1 = t.replies.create "title" => "r1", "content" => "hello world"
196
+ assert r1.valid?, "Saving r1"
197
+
198
+ r2 = t.replies.create "title" => "r2", "content" => "hello world"
199
+ assert !r2.valid?, "Saving r2 first time"
200
+ end
201
+
202
+ def test_validate_uniqueness_scoped_to_defining_class
203
+ t = Topic.create("title" => "What, me worry?")
204
+
205
+ r1 = t.unique_replies.create "title" => "r1", "content" => "a barrel of fun"
206
+ assert r1.valid?, "Saving r1"
207
+
208
+ r2 = t.silly_unique_replies.create "title" => "r2", "content" => "a barrel of fun"
209
+ assert !r2.valid?, "Saving r2"
210
+
211
+ # Should succeed as validates_uniqueness_of only applies to
212
+ # UniqueReply and its subclasses
213
+ r3 = t.replies.create "title" => "r2", "content" => "a barrel of fun"
214
+ assert r3.valid?, "Saving r3"
215
+ end
216
+
217
+ def test_validate_uniqueness_with_scope_array
218
+ Reply.validates_uniqueness_of(:author_name, :scope => [:author_email_address, :parent_id])
219
+
220
+ t = Topic.create("title" => "The earth is actually flat!")
221
+
222
+ r1 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply"
223
+ assert r1.valid?, "Saving r1"
224
+
225
+ r2 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy@rubyonrails.com", "title" => "You're crazy!", "content" => "Crazy reply again..."
226
+ assert !r2.valid?, "Saving r2. Double reply by same author."
227
+
228
+ r2.author_email_address = "jeremy_alt_email@rubyonrails.com"
229
+ assert r2.save, "Saving r2 the second time."
230
+
231
+ r3 = t.replies.create "author_name" => "jeremy", "author_email_address" => "jeremy_alt_email@rubyonrails.com", "title" => "You're wrong", "content" => "It's cubic"
232
+ assert !r3.valid?, "Saving r3"
233
+
234
+ r3.author_name = "jj"
235
+ assert r3.save, "Saving r3 the second time."
236
+
237
+ r3.author_name = "jeremy"
238
+ assert !r3.save, "Saving r3 the third time."
239
+ end
240
+
241
+ def test_validate_case_insensitive_uniqueness
242
+ Topic.validates_uniqueness_of(:title, :parent_id, :case_sensitive => false, :allow_nil => true)
243
+
244
+ t = Topic.new("title" => "I'm unique!", :parent_id => 2)
245
+ assert t.save, "Should save t as unique"
246
+
247
+ t.content = "Remaining unique"
248
+ assert t.save, "Should still save t as unique"
249
+
250
+ t2 = Topic.new("title" => "I'm UNIQUE!", :parent_id => 1)
251
+ assert !t2.valid?, "Shouldn't be valid"
252
+ assert !t2.save, "Shouldn't save t2 as unique"
253
+ assert t2.errors[:title].any?
254
+ assert t2.errors[:parent_id].any?
255
+ assert_equal ["has already been taken"], t2.errors[:title]
256
+
257
+ t2.title = "I'm truly UNIQUE!"
258
+ assert !t2.valid?, "Shouldn't be valid"
259
+ assert !t2.save, "Shouldn't save t2 as unique"
260
+ assert t2.errors[:title].empty?
261
+ assert t2.errors[:parent_id].any?
262
+
263
+ t2.parent_id = 4
264
+ assert t2.save, "Should now save t2 as unique"
265
+
266
+ t2.parent_id = nil
267
+ t2.title = nil
268
+ assert t2.valid?, "should validate with nil"
269
+ assert t2.save, "should save with nil"
270
+
271
+ t_utf8 = Topic.new("title" => "Я тоже уникальный!")
272
+ assert t_utf8.save, "Should save t_utf8 as unique"
273
+
274
+ # If database hasn't UTF-8 character set, this test fails
275
+ if Topic.all.merge!(:select => 'LOWER(title) AS title').find(t_utf8.id).title == "я тоже уникальный!"
276
+ t2_utf8 = Topic.new("title" => тоже УНИКАЛЬНЫЙ!")
277
+ assert !t2_utf8.valid?, "Shouldn't be valid"
278
+ assert !t2_utf8.save, "Shouldn't save t2_utf8 as unique"
279
+ end
280
+ end
281
+
282
+ def test_validate_case_sensitive_uniqueness_with_special_sql_like_chars
283
+ Topic.validates_uniqueness_of(:title, :case_sensitive => true)
284
+
285
+ t = Topic.new("title" => "I'm unique!")
286
+ assert t.save, "Should save t as unique"
287
+
288
+ t2 = Topic.new("title" => "I'm %")
289
+ assert t2.save, "Should save t2 as unique"
290
+
291
+ t3 = Topic.new("title" => "I'm uniqu_!")
292
+ assert t3.save, "Should save t3 as unique"
293
+ end
294
+
295
+ def test_validate_case_insensitive_uniqueness_with_special_sql_like_chars
296
+ Topic.validates_uniqueness_of(:title, :case_sensitive => false)
297
+
298
+ t = Topic.new("title" => "I'm unique!")
299
+ assert t.save, "Should save t as unique"
300
+
301
+ t2 = Topic.new("title" => "I'm %")
302
+ assert t2.save, "Should save t2 as unique"
303
+
304
+ t3 = Topic.new("title" => "I'm uniqu_!")
305
+ assert t3.save, "Should save t3 as unique"
306
+ end
307
+
308
+ def test_validate_case_sensitive_uniqueness
309
+ Topic.validates_uniqueness_of(:title, :case_sensitive => true, :allow_nil => true)
310
+
311
+ t = Topic.new("title" => "I'm unique!")
312
+ assert t.save, "Should save t as unique"
313
+
314
+ t.content = "Remaining unique"
315
+ assert t.save, "Should still save t as unique"
316
+
317
+ t2 = Topic.new("title" => "I'M UNIQUE!")
318
+ assert t2.valid?, "Should be valid"
319
+ assert t2.save, "Should save t2 as unique"
320
+ assert t2.errors[:title].empty?
321
+ assert t2.errors[:parent_id].empty?
322
+ assert_not_equal ["has already been taken"], t2.errors[:title]
323
+
324
+ t3 = Topic.new("title" => "I'M uNiQUe!")
325
+ assert t3.valid?, "Should be valid"
326
+ assert t3.save, "Should save t2 as unique"
327
+ assert t3.errors[:title].empty?
328
+ assert t3.errors[:parent_id].empty?
329
+ assert_not_equal ["has already been taken"], t3.errors[:title]
330
+ end
331
+
332
+ def test_validate_case_sensitive_uniqueness_with_attribute_passed_as_integer
333
+ Topic.validates_uniqueness_of(:title, :case_sensitive => true)
334
+ Topic.create!('title' => 101)
335
+
336
+ t2 = Topic.new('title' => 101)
337
+ assert !t2.valid?
338
+ assert t2.errors[:title]
339
+ end
340
+
341
+ def test_validate_uniqueness_with_non_standard_table_names
342
+ i1 = WarehouseThing.create(:value => 1000)
343
+ assert !i1.valid?, "i1 should not be valid"
344
+ assert i1.errors[:value].any?, "Should not be empty"
345
+ end
346
+
347
+ def test_validates_uniqueness_inside_scoping
348
+ Topic.validates_uniqueness_of(:title)
349
+
350
+ Topic.where(:author_name => "David").scoping do
351
+ t1 = Topic.new("title" => "I'm unique!", "author_name" => "Mary")
352
+ assert t1.save
353
+ t2 = Topic.new("title" => "I'm unique!", "author_name" => "David")
354
+ assert !t2.valid?
355
+ end
356
+ end
357
+
358
+ def test_validate_uniqueness_with_columns_which_are_sql_keywords
359
+ repair_validations(Guid) do
360
+ Guid.validates_uniqueness_of :key
361
+ g = Guid.new
362
+ g.key = "foo"
363
+ assert_nothing_raised { !g.valid? }
364
+ end
365
+ end
366
+
367
+ def test_validate_uniqueness_with_limit
368
+ if current_adapter?(:SQLite3Adapter)
369
+ # Event.title has limit 5, but SQLite doesn't truncate.
370
+ e1 = Event.create(title: "abcdefgh")
371
+ assert e1.valid?, "Could not create an event with a unique 8 characters title"
372
+
373
+ e2 = Event.create(title: "abcdefgh")
374
+ assert_not e2.valid?, "Created an event whose title is not unique"
375
+ elsif current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter, :SQLServerAdapter)
376
+ assert_raise(ActiveRecord::ValueTooLong) do
377
+ Event.create(title: "abcdefgh")
378
+ end
379
+ else
380
+ assert_raise(ActiveRecord::StatementInvalid) do
381
+ Event.create(title: "abcdefgh")
382
+ end
383
+ end
384
+ end
385
+
386
+ def test_validate_uniqueness_with_limit_and_utf8
387
+ if current_adapter?(:SQLite3Adapter)
388
+ # Event.title has limit 5, but does SQLite doesn't truncate.
389
+ e1 = Event.create(title: "一二三四五六七八")
390
+ assert e1.valid?, "Could not create an event with a unique 8 characters title"
391
+
392
+ e2 = Event.create(title: "一二三四五六七八")
393
+ assert_not e2.valid?, "Created an event whose title is not unique"
394
+ elsif current_adapter?(:Mysql2Adapter, :PostgreSQLAdapter, :OracleAdapter, :SQLServerAdapter)
395
+ assert_raise(ActiveRecord::ValueTooLong) do
396
+ Event.create(title: "一二三四五六七八")
397
+ end
398
+ else
399
+ assert_raise(ActiveRecord::StatementInvalid) do
400
+ Event.create(title: "一二三四五六七八")
401
+ end
402
+ end
403
+ end
404
+
405
+ def test_validate_straight_inheritance_uniqueness
406
+ w1 = IneptWizard.create(:name => "Rincewind", :city => "Ankh-Morpork")
407
+ assert w1.valid?, "Saving w1"
408
+
409
+ # Should use validation from base class (which is abstract)
410
+ w2 = IneptWizard.new(:name => "Rincewind", :city => "Quirm")
411
+ assert !w2.valid?, "w2 shouldn't be valid"
412
+ assert w2.errors[:name].any?, "Should have errors for name"
413
+ assert_equal ["has already been taken"], w2.errors[:name], "Should have uniqueness message for name"
414
+
415
+ w3 = Conjurer.new(:name => "Rincewind", :city => "Quirm")
416
+ assert !w3.valid?, "w3 shouldn't be valid"
417
+ assert w3.errors[:name].any?, "Should have errors for name"
418
+ assert_equal ["has already been taken"], w3.errors[:name], "Should have uniqueness message for name"
419
+
420
+ w4 = Conjurer.create(:name => "The Amazing Bonko", :city => "Quirm")
421
+ assert w4.valid?, "Saving w4"
422
+
423
+ w5 = Thaumaturgist.new(:name => "The Amazing Bonko", :city => "Lancre")
424
+ assert !w5.valid?, "w5 shouldn't be valid"
425
+ assert w5.errors[:name].any?, "Should have errors for name"
426
+ assert_equal ["has already been taken"], w5.errors[:name], "Should have uniqueness message for name"
427
+
428
+ w6 = Thaumaturgist.new(:name => "Mustrum Ridcully", :city => "Quirm")
429
+ assert !w6.valid?, "w6 shouldn't be valid"
430
+ assert w6.errors[:city].any?, "Should have errors for city"
431
+ assert_equal ["has already been taken"], w6.errors[:city], "Should have uniqueness message for city"
432
+ end
433
+
434
+ def test_validate_uniqueness_with_conditions
435
+ Topic.validates_uniqueness_of :title, conditions: -> { where(approved: true) }
436
+ Topic.create("title" => "I'm a topic", "approved" => true)
437
+ Topic.create("title" => "I'm an unapproved topic", "approved" => false)
438
+
439
+ t3 = Topic.new("title" => "I'm a topic", "approved" => true)
440
+ assert !t3.valid?, "t3 shouldn't be valid"
441
+
442
+ t4 = Topic.new("title" => "I'm an unapproved topic", "approved" => false)
443
+ assert t4.valid?, "t4 should be valid"
444
+ end
445
+
446
+ def test_validate_uniqueness_with_non_callable_conditions_is_not_supported
447
+ assert_raises(ArgumentError) {
448
+ Topic.validates_uniqueness_of :title, conditions: Topic.where(approved: true)
449
+ }
450
+ end
451
+
452
+ def test_validate_uniqueness_on_existing_relation
453
+ event = Event.create
454
+ assert TopicWithUniqEvent.create(event: event).valid?
455
+
456
+ topic = TopicWithUniqEvent.new(event: event)
457
+ assert_not topic.valid?
458
+ assert_equal ['has already been taken'], topic.errors[:event]
459
+ end
460
+
461
+ def test_validate_uniqueness_on_empty_relation
462
+ topic = TopicWithUniqEvent.new
463
+ assert topic.valid?
464
+ end
465
+
466
+ def test_validate_uniqueness_of_custom_primary_key
467
+ klass = Class.new(ActiveRecord::Base) do
468
+ self.table_name = "keyboards"
469
+ self.primary_key = :key_number
470
+
471
+ validates_uniqueness_of :key_number
472
+
473
+ def self.name
474
+ "Keyboard"
475
+ end
476
+ end
477
+
478
+ klass.create!(key_number: 10)
479
+ key2 = klass.create!(key_number: 11)
480
+
481
+ key2.key_number = 10
482
+ assert_not key2.valid?
483
+ end
484
+
485
+ def test_validate_uniqueness_without_primary_key
486
+ klass = Class.new(ActiveRecord::Base) do
487
+ self.table_name = "dashboards"
488
+
489
+ validates_uniqueness_of :dashboard_id
490
+
491
+ def self.name; "Dashboard" end
492
+ end
493
+
494
+ abc = klass.create!(dashboard_id: "abc")
495
+ assert klass.new(dashboard_id: "xyz").valid?
496
+ assert_not klass.new(dashboard_id: "abc").valid?
497
+
498
+ abc.dashboard_id = "def"
499
+
500
+ e = assert_raises ActiveRecord::UnknownPrimaryKey do
501
+ abc.save!
502
+ end
503
+ assert_match(/\AUnknown primary key for table dashboards in model/, e.message)
504
+ assert_match(/Can not validate uniqueness for persisted record without primary key.\z/, e.message)
505
+ end
506
+
507
+ def test_validate_uniqueness_ignores_itself_when_primary_key_changed
508
+ Topic.validates_uniqueness_of(:title)
509
+
510
+ t = Topic.new("title" => "This is a unique title")
511
+ assert t.save, "Should save t as unique"
512
+
513
+ t.id += 1
514
+ assert t.valid?, "Should be valid"
515
+ assert t.save, "Should still save t as unique"
516
+ end
517
+
518
+ def test_validate_uniqueness_with_after_create_performing_save
519
+ TopicWithAfterCreate.validates_uniqueness_of(:title)
520
+ topic = TopicWithAfterCreate.create!(:title => "Title1")
521
+ assert topic.author_name.start_with?("Title1")
522
+
523
+ topic2 = TopicWithAfterCreate.new(:title => "Title1")
524
+ refute topic2.valid?
525
+ assert_equal(["has already been taken"], topic2.errors[:title])
526
+ end
527
+
528
+ def test_validate_uniqueness_uuid
529
+ skip unless current_adapter?(:PostgreSQLAdapter)
530
+ item = UuidItem.create!(uuid: SecureRandom.uuid, title: 'item1')
531
+ item.update(title: 'item1-title2')
532
+ assert_empty item.errors
533
+
534
+ item2 = UuidValidatingItem.create!(uuid: SecureRandom.uuid, title: 'item2')
535
+ item2.update(title: 'item2-title2')
536
+ assert_empty item2.errors
537
+ end
538
+
539
+ def test_validate_uniqueness_regular_id
540
+ item = CoolTopic.create!(title: 'MyItem')
541
+ assert_empty item.errors
542
+
543
+ item2 = CoolTopic.new(id: item.id, title: 'MyItem2')
544
+ refute item2.valid?
545
+
546
+ assert_equal(["has already been taken"], item2.errors[:id])
547
+ end
548
+ end