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,144 +1,144 @@
1
- require "cases/helper"
2
- require "models/pirate"
3
- require "models/bird"
4
-
5
- class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase
6
- Pirate.has_many(:birds_with_add_load,
7
- :class_name => "Bird",
8
- :before_add => proc { |p,b|
9
- @@add_callback_called << b
10
- p.birds_with_add_load.to_a
11
- })
12
- Pirate.has_many(:birds_with_add,
13
- :class_name => "Bird",
14
- :before_add => proc { |p,b| @@add_callback_called << b })
15
-
16
- Pirate.accepts_nested_attributes_for(:birds_with_add_load,
17
- :birds_with_add,
18
- :allow_destroy => true)
19
-
20
- def setup
21
- @@add_callback_called = []
22
- @pirate = Pirate.new.tap do |pirate|
23
- pirate.catchphrase = "Don't call me!"
24
- pirate.birds_attributes = [{:name => 'Bird1'},{:name => 'Bird2'}]
25
- pirate.save!
26
- end
27
- @birds = @pirate.birds.to_a
28
- end
29
-
30
- def bird_to_update
31
- @birds[0]
32
- end
33
-
34
- def bird_to_destroy
35
- @birds[1]
36
- end
37
-
38
- def existing_birds_attributes
39
- @birds.map do |bird|
40
- bird.attributes.slice("id","name")
41
- end
42
- end
43
-
44
- def new_birds
45
- @pirate.birds_with_add.to_a - @birds
46
- end
47
-
48
- def new_bird_attributes
49
- [{'name' => "New Bird"}]
50
- end
51
-
52
- def destroy_bird_attributes
53
- [{'id' => bird_to_destroy.id.to_s, "_destroy" => true}]
54
- end
55
-
56
- def update_new_and_destroy_bird_attributes
57
- [{'id' => @birds[0].id.to_s, 'name' => 'New Name'},
58
- {'name' => "New Bird"},
59
- {'id' => bird_to_destroy.id.to_s, "_destroy" => true}]
60
- end
61
-
62
- # Characterizing when :before_add callback is called
63
- test ":before_add called for new bird when not loaded" do
64
- assert_not @pirate.birds_with_add.loaded?
65
- @pirate.birds_with_add_attributes = new_bird_attributes
66
- assert_new_bird_with_callback_called
67
- end
68
-
69
- test ":before_add called for new bird when loaded" do
70
- @pirate.birds_with_add.load_target
71
- @pirate.birds_with_add_attributes = new_bird_attributes
72
- assert_new_bird_with_callback_called
73
- end
74
-
75
- def assert_new_bird_with_callback_called
76
- assert_equal(1, new_birds.size)
77
- assert_equal(new_birds, @@add_callback_called)
78
- end
79
-
80
- test ":before_add not called for identical assignment when not loaded" do
81
- assert_not @pirate.birds_with_add.loaded?
82
- @pirate.birds_with_add_attributes = existing_birds_attributes
83
- assert_callbacks_not_called
84
- end
85
-
86
- test ":before_add not called for identical assignment when loaded" do
87
- @pirate.birds_with_add.load_target
88
- @pirate.birds_with_add_attributes = existing_birds_attributes
89
- assert_callbacks_not_called
90
- end
91
-
92
- test ":before_add not called for destroy assignment when not loaded" do
93
- assert_not @pirate.birds_with_add.loaded?
94
- @pirate.birds_with_add_attributes = destroy_bird_attributes
95
- assert_callbacks_not_called
96
- end
97
-
98
- test ":before_add not called for deletion assignment when loaded" do
99
- @pirate.birds_with_add.load_target
100
- @pirate.birds_with_add_attributes = destroy_bird_attributes
101
- assert_callbacks_not_called
102
- end
103
-
104
- def assert_callbacks_not_called
105
- assert_empty new_birds
106
- assert_empty @@add_callback_called
107
- end
108
-
109
- # Ensuring that the records in the association target are updated,
110
- # whether the association is loaded before or not
111
- test "Assignment updates records in target when not loaded" do
112
- assert_not @pirate.birds_with_add.loaded?
113
- @pirate.birds_with_add_attributes = update_new_and_destroy_bird_attributes
114
- assert_assignment_affects_records_in_target(:birds_with_add)
115
- end
116
-
117
- test "Assignment updates records in target when loaded" do
118
- @pirate.birds_with_add.load_target
119
- @pirate.birds_with_add_attributes = update_new_and_destroy_bird_attributes
120
- assert_assignment_affects_records_in_target(:birds_with_add)
121
- end
122
-
123
- test("Assignment updates records in target when not loaded" +
124
- " and callback loads target") do
125
- assert_not @pirate.birds_with_add_load.loaded?
126
- @pirate.birds_with_add_load_attributes = update_new_and_destroy_bird_attributes
127
- assert_assignment_affects_records_in_target(:birds_with_add_load)
128
- end
129
-
130
- test("Assignment updates records in target when loaded" +
131
- " and callback loads target") do
132
- @pirate.birds_with_add_load.load_target
133
- @pirate.birds_with_add_load_attributes = update_new_and_destroy_bird_attributes
134
- assert_assignment_affects_records_in_target(:birds_with_add_load)
135
- end
136
-
137
- def assert_assignment_affects_records_in_target(association_name)
138
- association = @pirate.send(association_name)
139
- assert association.detect {|b| b == bird_to_update }.name_changed?,
140
- 'Update record not updated'
141
- assert association.detect {|b| b == bird_to_destroy }.marked_for_destruction?,
142
- 'Destroy record not marked for destruction'
143
- end
144
- end
1
+ require "cases/helper"
2
+ require "models/pirate"
3
+ require "models/bird"
4
+
5
+ class NestedAttributesWithCallbacksTest < ActiveRecord::TestCase
6
+ Pirate.has_many(:birds_with_add_load,
7
+ :class_name => "Bird",
8
+ :before_add => proc { |p,b|
9
+ @@add_callback_called << b
10
+ p.birds_with_add_load.to_a
11
+ })
12
+ Pirate.has_many(:birds_with_add,
13
+ :class_name => "Bird",
14
+ :before_add => proc { |p,b| @@add_callback_called << b })
15
+
16
+ Pirate.accepts_nested_attributes_for(:birds_with_add_load,
17
+ :birds_with_add,
18
+ :allow_destroy => true)
19
+
20
+ def setup
21
+ @@add_callback_called = []
22
+ @pirate = Pirate.new.tap do |pirate|
23
+ pirate.catchphrase = "Don't call me!"
24
+ pirate.birds_attributes = [{:name => 'Bird1'},{:name => 'Bird2'}]
25
+ pirate.save!
26
+ end
27
+ @birds = @pirate.birds.to_a
28
+ end
29
+
30
+ def bird_to_update
31
+ @birds[0]
32
+ end
33
+
34
+ def bird_to_destroy
35
+ @birds[1]
36
+ end
37
+
38
+ def existing_birds_attributes
39
+ @birds.map do |bird|
40
+ bird.attributes.slice("id","name")
41
+ end
42
+ end
43
+
44
+ def new_birds
45
+ @pirate.birds_with_add.to_a - @birds
46
+ end
47
+
48
+ def new_bird_attributes
49
+ [{'name' => "New Bird"}]
50
+ end
51
+
52
+ def destroy_bird_attributes
53
+ [{'id' => bird_to_destroy.id.to_s, "_destroy" => true}]
54
+ end
55
+
56
+ def update_new_and_destroy_bird_attributes
57
+ [{'id' => @birds[0].id.to_s, 'name' => 'New Name'},
58
+ {'name' => "New Bird"},
59
+ {'id' => bird_to_destroy.id.to_s, "_destroy" => true}]
60
+ end
61
+
62
+ # Characterizing when :before_add callback is called
63
+ test ":before_add called for new bird when not loaded" do
64
+ assert_not @pirate.birds_with_add.loaded?
65
+ @pirate.birds_with_add_attributes = new_bird_attributes
66
+ assert_new_bird_with_callback_called
67
+ end
68
+
69
+ test ":before_add called for new bird when loaded" do
70
+ @pirate.birds_with_add.load_target
71
+ @pirate.birds_with_add_attributes = new_bird_attributes
72
+ assert_new_bird_with_callback_called
73
+ end
74
+
75
+ def assert_new_bird_with_callback_called
76
+ assert_equal(1, new_birds.size)
77
+ assert_equal(new_birds, @@add_callback_called)
78
+ end
79
+
80
+ test ":before_add not called for identical assignment when not loaded" do
81
+ assert_not @pirate.birds_with_add.loaded?
82
+ @pirate.birds_with_add_attributes = existing_birds_attributes
83
+ assert_callbacks_not_called
84
+ end
85
+
86
+ test ":before_add not called for identical assignment when loaded" do
87
+ @pirate.birds_with_add.load_target
88
+ @pirate.birds_with_add_attributes = existing_birds_attributes
89
+ assert_callbacks_not_called
90
+ end
91
+
92
+ test ":before_add not called for destroy assignment when not loaded" do
93
+ assert_not @pirate.birds_with_add.loaded?
94
+ @pirate.birds_with_add_attributes = destroy_bird_attributes
95
+ assert_callbacks_not_called
96
+ end
97
+
98
+ test ":before_add not called for deletion assignment when loaded" do
99
+ @pirate.birds_with_add.load_target
100
+ @pirate.birds_with_add_attributes = destroy_bird_attributes
101
+ assert_callbacks_not_called
102
+ end
103
+
104
+ def assert_callbacks_not_called
105
+ assert_empty new_birds
106
+ assert_empty @@add_callback_called
107
+ end
108
+
109
+ # Ensuring that the records in the association target are updated,
110
+ # whether the association is loaded before or not
111
+ test "Assignment updates records in target when not loaded" do
112
+ assert_not @pirate.birds_with_add.loaded?
113
+ @pirate.birds_with_add_attributes = update_new_and_destroy_bird_attributes
114
+ assert_assignment_affects_records_in_target(:birds_with_add)
115
+ end
116
+
117
+ test "Assignment updates records in target when loaded" do
118
+ @pirate.birds_with_add.load_target
119
+ @pirate.birds_with_add_attributes = update_new_and_destroy_bird_attributes
120
+ assert_assignment_affects_records_in_target(:birds_with_add)
121
+ end
122
+
123
+ test("Assignment updates records in target when not loaded" +
124
+ " and callback loads target") do
125
+ assert_not @pirate.birds_with_add_load.loaded?
126
+ @pirate.birds_with_add_load_attributes = update_new_and_destroy_bird_attributes
127
+ assert_assignment_affects_records_in_target(:birds_with_add_load)
128
+ end
129
+
130
+ test("Assignment updates records in target when loaded" +
131
+ " and callback loads target") do
132
+ @pirate.birds_with_add_load.load_target
133
+ @pirate.birds_with_add_load_attributes = update_new_and_destroy_bird_attributes
134
+ assert_assignment_affects_records_in_target(:birds_with_add_load)
135
+ end
136
+
137
+ def assert_assignment_affects_records_in_target(association_name)
138
+ association = @pirate.send(association_name)
139
+ assert association.detect {|b| b == bird_to_update }.name_changed?,
140
+ 'Update record not updated'
141
+ assert association.detect {|b| b == bird_to_destroy }.marked_for_destruction?,
142
+ 'Destroy record not marked for destruction'
143
+ end
144
+ end
@@ -1,909 +1,1001 @@
1
- require "cases/helper"
2
- require 'models/aircraft'
3
- require 'models/post'
4
- require 'models/comment'
5
- require 'models/author'
6
- require 'models/topic'
7
- require 'models/reply'
8
- require 'models/category'
9
- require 'models/company'
10
- require 'models/developer'
11
- require 'models/computer'
12
- require 'models/project'
13
- require 'models/minimalistic'
14
- require 'models/warehouse_thing'
15
- require 'models/parrot'
16
- require 'models/minivan'
17
- require 'models/owner'
18
- require 'models/person'
19
- require 'models/pet'
20
- require 'models/toy'
21
- require 'rexml/document'
22
-
23
- class PersistenceTest < ActiveRecord::TestCase
24
- fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse_things', :authors, :author_addresses, :categorizations, :categories, :posts, :minivans, :pets, :toys
25
-
26
- # Oracle UPDATE does not support ORDER BY
27
- unless current_adapter?(:OracleAdapter)
28
- def test_update_all_ignores_order_without_limit_from_association
29
- author = authors(:david)
30
- assert_nothing_raised do
31
- assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all([ "body = ?", "bulk update!" ])
32
- end
33
- end
34
-
35
- def test_update_all_doesnt_ignore_order
36
- assert_equal authors(:david).id + 1, authors(:mary).id # make sure there is going to be a duplicate PK error
37
- test_update_with_order_succeeds = lambda do |order|
38
- begin
39
- Author.order(order).update_all('id = id + 1')
40
- rescue ActiveRecord::ActiveRecordError
41
- false
42
- end
43
- end
44
-
45
- if !current_adapter?(:IBM_DBAdapter) && test_update_with_order_succeeds.call('id DESC')
46
- # The update below goes on successfully in DB2.
47
- assert !test_update_with_order_succeeds.call('id ASC') # test that this wasn't a fluke and using an incorrect order results in an exception
48
- else
49
- # test that we're failing because the current Arel's engine doesn't support UPDATE ORDER BY queries is using subselects instead
50
- assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\Z/i) do
51
- test_update_with_order_succeeds.call('id DESC')
52
- end
53
- end
54
- end
55
-
56
- def test_update_all_with_order_and_limit_updates_subset_only
57
- author = authors(:david)
58
- assert_nothing_raised do
59
- assert_equal 1, author.posts_sorted_by_id_limited.size
60
- assert_equal 2, author.posts_sorted_by_id_limited.limit(2).to_a.size
61
- assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ])
62
- assert_equal "bulk update!", posts(:welcome).body
63
- assert_not_equal "bulk update!", posts(:thinking).body
64
- end
65
- end
66
- end
67
-
68
- def test_update_many
69
- topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
70
- updated = Topic.update(topic_data.keys, topic_data.values)
71
-
72
- assert_equal 2, updated.size
73
- assert_equal "1 updated", Topic.find(1).content
74
- assert_equal "2 updated", Topic.find(2).content
75
- end
76
-
77
- def test_delete_all
78
- assert Topic.count > 0
79
-
80
- assert_equal Topic.count, Topic.delete_all
81
- end
82
-
83
- def test_delete_all_with_joins_and_where_part_is_hash
84
- where_args = {:toys => {:name => 'Bone'}}
85
- count = Pet.joins(:toys).where(where_args).count
86
-
87
- assert_equal count, 1
88
- assert_equal count, Pet.joins(:toys).where(where_args).delete_all
89
- end
90
-
91
- def test_delete_all_with_joins_and_where_part_is_not_hash
92
- where_args = ['toys.name = ?', 'Bone']
93
- count = Pet.joins(:toys).where(where_args).count
94
-
95
- assert_equal count, 1
96
- assert_equal count, Pet.joins(:toys).where(where_args).delete_all
97
- end
98
-
99
- def test_increment_attribute
100
- assert_equal 50, accounts(:signals37).credit_limit
101
- accounts(:signals37).increment! :credit_limit
102
- assert_equal 51, accounts(:signals37, :reload).credit_limit
103
-
104
- accounts(:signals37).increment(:credit_limit).increment!(:credit_limit)
105
- assert_equal 53, accounts(:signals37, :reload).credit_limit
106
- end
107
-
108
- def test_increment_nil_attribute
109
- assert_nil topics(:first).parent_id
110
- topics(:first).increment! :parent_id
111
- assert_equal 1, topics(:first).parent_id
112
- end
113
-
114
- def test_increment_attribute_by
115
- assert_equal 50, accounts(:signals37).credit_limit
116
- accounts(:signals37).increment! :credit_limit, 5
117
- assert_equal 55, accounts(:signals37, :reload).credit_limit
118
-
119
- accounts(:signals37).increment(:credit_limit, 1).increment!(:credit_limit, 3)
120
- assert_equal 59, accounts(:signals37, :reload).credit_limit
121
- end
122
-
123
- def test_destroy_all
124
- conditions = "author_name = 'Mary'"
125
- topics_by_mary = Topic.all.merge!(:where => conditions, :order => 'id').to_a
126
- assert ! topics_by_mary.empty?
127
-
128
- assert_difference('Topic.count', -topics_by_mary.size) do
129
- destroyed = Topic.destroy_all(conditions).sort_by(&:id)
130
- assert_equal topics_by_mary, destroyed
131
- assert destroyed.all? { |topic| topic.frozen? }, "destroyed topics should be frozen"
132
- end
133
- end
134
-
135
- def test_destroy_many
136
- clients = Client.all.merge!(:order => 'id').find([2, 3])
137
-
138
- assert_difference('Client.count', -2) do
139
- destroyed = Client.destroy([2, 3]).sort_by(&:id)
140
- assert_equal clients, destroyed
141
- assert destroyed.all? { |client| client.frozen? }, "destroyed clients should be frozen"
142
- end
143
- end
144
-
145
- def test_becomes
146
- assert_kind_of Reply, topics(:first).becomes(Reply)
147
- assert_equal "The First Topic", topics(:first).becomes(Reply).title
148
- end
149
-
150
- def test_becomes_includes_errors
151
- company = Company.new(:name => nil)
152
- assert !company.valid?
153
- original_errors = company.errors
154
- client = company.becomes(Client)
155
- assert_equal original_errors, client.errors
156
- end
157
-
158
- def test_dupd_becomes_persists_changes_from_the_original
159
- original = topics(:first)
160
- copy = original.dup.becomes(Reply)
161
- copy.save!
162
- assert_equal "The First Topic", Topic.find(copy.id).title
163
- end
164
-
165
- def test_becomes_includes_changed_attributes
166
- company = Company.new(name: "37signals")
167
- client = company.becomes(Client)
168
- assert_equal "37signals", client.name
169
- assert_equal %w{name}, client.changed
170
- end
171
-
172
- def test_delete_many
173
- original_count = Topic.count
174
- Topic.delete(deleting = [1, 2])
175
- assert_equal original_count - deleting.size, Topic.count
176
- end
177
-
178
- def test_decrement_attribute
179
- assert_equal 50, accounts(:signals37).credit_limit
180
-
181
- accounts(:signals37).decrement!(:credit_limit)
182
- assert_equal 49, accounts(:signals37, :reload).credit_limit
183
-
184
- accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit)
185
- assert_equal 47, accounts(:signals37, :reload).credit_limit
186
- end
187
-
188
- def test_decrement_attribute_by
189
- assert_equal 50, accounts(:signals37).credit_limit
190
- accounts(:signals37).decrement! :credit_limit, 5
191
- assert_equal 45, accounts(:signals37, :reload).credit_limit
192
-
193
- accounts(:signals37).decrement(:credit_limit, 1).decrement!(:credit_limit, 3)
194
- assert_equal 41, accounts(:signals37, :reload).credit_limit
195
- end
196
-
197
- def test_create
198
- topic = Topic.new
199
- topic.title = "New Topic"
200
- topic.save
201
- topic_reloaded = Topic.find(topic.id)
202
- assert_equal("New Topic", topic_reloaded.title)
203
- end
204
-
205
- def test_save!
206
- topic = Topic.new(:title => "New Topic")
207
- assert topic.save!
208
-
209
- reply = WrongReply.new
210
- assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
211
- end
212
-
213
- def test_save_null_string_attributes
214
- topic = Topic.find(1)
215
- topic.attributes = { "title" => "null", "author_name" => "null" }
216
- topic.save!
217
- topic.reload
218
- assert_equal("null", topic.title)
219
- assert_equal("null", topic.author_name)
220
- end
221
-
222
- def test_save_nil_string_attributes
223
- topic = Topic.find(1)
224
- topic.title = nil
225
- topic.save!
226
- topic.reload
227
- assert_nil topic.title
228
- end
229
-
230
- def test_save_for_record_with_only_primary_key
231
- minimalistic = Minimalistic.new
232
- assert_nothing_raised { minimalistic.save }
233
- end
234
-
235
- def test_save_for_record_with_only_primary_key_that_is_provided
236
- assert_nothing_raised { Minimalistic.create!(:id => 2) }
237
- end
238
-
239
- def test_save_with_duping_of_destroyed_object
240
- developer = Developer.first
241
- developer.destroy
242
- new_developer = developer.dup
243
- new_developer.save
244
- assert new_developer.persisted?
245
- assert_not new_developer.destroyed?
246
- end
247
-
248
- def test_create_many
249
- topics = Topic.create([ { "title" => "first" }, { "title" => "second" }])
250
- assert_equal 2, topics.size
251
- assert_equal "first", topics.first.title
252
- end
253
-
254
- def test_create_columns_not_equal_attributes
255
- topic = Topic.instantiate(
256
- 'title' => 'Another New Topic',
257
- 'does_not_exist' => 'test'
258
- )
259
- assert_nothing_raised { topic.save }
260
- end
261
-
262
- def test_create_through_factory_with_block
263
- topic = Topic.create("title" => "New Topic") do |t|
264
- t.author_name = "David"
265
- end
266
- assert_equal("New Topic", topic.title)
267
- assert_equal("David", topic.author_name)
268
- end
269
-
270
- def test_create_many_through_factory_with_block
271
- topics = Topic.create([ { "title" => "first" }, { "title" => "second" }]) do |t|
272
- t.author_name = "David"
273
- end
274
- assert_equal 2, topics.size
275
- topic1, topic2 = Topic.find(topics[0].id), Topic.find(topics[1].id)
276
- assert_equal "first", topic1.title
277
- assert_equal "David", topic1.author_name
278
- assert_equal "second", topic2.title
279
- assert_equal "David", topic2.author_name
280
- end
281
-
282
- def test_update_object
283
- topic = Topic.new
284
- topic.title = "Another New Topic"
285
- topic.written_on = "2003-12-12 23:23:00"
286
- topic.save
287
- topic_reloaded = Topic.find(topic.id)
288
- assert_equal("Another New Topic", topic_reloaded.title)
289
-
290
- topic_reloaded.title = "Updated topic"
291
- topic_reloaded.save
292
-
293
- topic_reloaded_again = Topic.find(topic.id)
294
-
295
- assert_equal("Updated topic", topic_reloaded_again.title)
296
- end
297
-
298
- def test_update_columns_not_equal_attributes
299
- topic = Topic.new
300
- topic.title = "Still another topic"
301
- topic.save
302
-
303
- topic_reloaded = Topic.instantiate(topic.attributes.merge('does_not_exist' => 'test'))
304
- topic_reloaded.title = 'A New Topic'
305
- assert_nothing_raised { topic_reloaded.save }
306
- end
307
-
308
- def test_update_for_record_with_only_primary_key
309
- minimalistic = minimalistics(:first)
310
- assert_nothing_raised { minimalistic.save }
311
- end
312
-
313
- def test_update_sti_type
314
- assert_instance_of Reply, topics(:second)
315
-
316
- topic = topics(:second).becomes!(Topic)
317
- assert_instance_of Topic, topic
318
- topic.save!
319
- assert_instance_of Topic, Topic.find(topic.id)
320
- end
321
-
322
- def test_preserve_original_sti_type
323
- reply = topics(:second)
324
- assert_equal "Reply", reply.type
325
-
326
- topic = reply.becomes(Topic)
327
- assert_equal "Reply", reply.type
328
-
329
- assert_instance_of Topic, topic
330
- assert_equal "Reply", topic.type
331
- end
332
-
333
- def test_update_sti_subclass_type
334
- assert_instance_of Topic, topics(:first)
335
-
336
- reply = topics(:first).becomes!(Reply)
337
- assert_instance_of Reply, reply
338
- reply.save!
339
- assert_instance_of Reply, Reply.find(reply.id)
340
- end
341
-
342
- def test_update_after_create
343
- klass = Class.new(Topic) do
344
- def self.name; 'Topic'; end
345
- after_create do
346
- update_attribute("author_name", "David")
347
- end
348
- end
349
- topic = klass.new
350
- topic.title = "Another New Topic"
351
- topic.save
352
-
353
- topic_reloaded = Topic.find(topic.id)
354
- assert_equal("Another New Topic", topic_reloaded.title)
355
- assert_equal("David", topic_reloaded.author_name)
356
- end
357
-
358
- def test_delete
359
- topic = Topic.find(1)
360
- assert_equal topic, topic.delete, 'topic.delete did not return self'
361
- assert topic.frozen?, 'topic not frozen after delete'
362
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
363
- end
364
-
365
- def test_delete_doesnt_run_callbacks
366
- Topic.find(1).delete
367
- assert_not_nil Topic.find(2)
368
- end
369
-
370
- def test_destroy
371
- topic = Topic.find(1)
372
- assert_equal topic, topic.destroy, 'topic.destroy did not return self'
373
- assert topic.frozen?, 'topic not frozen after destroy'
374
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
375
- end
376
-
377
- def test_destroy!
378
- topic = Topic.find(1)
379
- assert_equal topic, topic.destroy!, 'topic.destroy! did not return self'
380
- assert topic.frozen?, 'topic not frozen after destroy!'
381
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
382
- end
383
-
384
- def test_record_not_found_exception
385
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(99999) }
386
- end
387
-
388
- def test_update_all
389
- assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
390
- assert_equal "bulk updated!", Topic.find(1).content
391
- assert_equal "bulk updated!", Topic.find(2).content
392
-
393
- assert_equal Topic.count, Topic.update_all(['content = ?', 'bulk updated again!'])
394
- assert_equal "bulk updated again!", Topic.find(1).content
395
- assert_equal "bulk updated again!", Topic.find(2).content
396
-
397
- assert_equal Topic.count, Topic.update_all(['content = ?', nil])
398
- assert_nil Topic.find(1).content
399
- end
400
-
401
- def test_update_all_with_hash
402
- assert_not_nil Topic.find(1).last_read
403
- assert_equal Topic.count, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil)
404
- assert_equal "bulk updated with hash!", Topic.find(1).content
405
- assert_equal "bulk updated with hash!", Topic.find(2).content
406
- assert_nil Topic.find(1).last_read
407
- assert_nil Topic.find(2).last_read
408
- end
409
-
410
- def test_update_all_with_non_standard_table_name
411
- assert_equal 1, WarehouseThing.where(id: 1).update_all(['value = ?', 0])
412
- assert_equal 0, WarehouseThing.find(1).value
413
- end
414
-
415
- def test_delete_new_record
416
- client = Client.new
417
- client.delete
418
- assert client.frozen?
419
- end
420
-
421
- def test_delete_record_with_associations
422
- client = Client.find(3)
423
- client.delete
424
- assert client.frozen?
425
- assert_kind_of Firm, client.firm
426
- assert_raise(RuntimeError) { client.name = "something else" }
427
- end
428
-
429
- def test_destroy_new_record
430
- client = Client.new
431
- client.destroy
432
- assert client.frozen?
433
- end
434
-
435
- def test_destroy_record_with_associations
436
- client = Client.find(3)
437
- client.destroy
438
- assert client.frozen?
439
- assert_kind_of Firm, client.firm
440
- assert_raise(RuntimeError) { client.name = "something else" }
441
- end
442
-
443
- def test_update_attribute
444
- assert !Topic.find(1).approved?
445
- Topic.find(1).update_attribute("approved", true)
446
- assert Topic.find(1).approved?
447
-
448
- Topic.find(1).update_attribute(:approved, false)
449
- assert !Topic.find(1).approved?
450
- end
451
-
452
- def test_update_attribute_for_readonly_attribute
453
- minivan = Minivan.find('m1')
454
- assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
455
- end
456
-
457
- def test_update_attribute_with_one_updated
458
- t = Topic.first
459
- t.update_attribute(:title, 'super_title')
460
- assert_equal 'super_title', t.title
461
- assert !t.changed?, "topic should not have changed"
462
- assert !t.title_changed?, "title should not have changed"
463
- assert_nil t.title_change, 'title change should be nil'
464
-
465
- t.reload
466
- assert_equal 'super_title', t.title
467
- end
468
-
469
- def test_update_attribute_for_updated_at_on
470
- developer = Developer.find(1)
471
- prev_month = Time.now.prev_month.change(usec: 0)
472
-
473
- developer.update_attribute(:updated_at, prev_month)
474
- assert_equal prev_month, developer.updated_at
475
-
476
- developer.update_attribute(:salary, 80001)
477
- assert_not_equal prev_month, developer.updated_at
478
-
479
- developer.reload
480
- assert_not_equal prev_month, developer.updated_at
481
- end
482
-
483
- def test_update_column
484
- topic = Topic.find(1)
485
- topic.update_column("approved", true)
486
- assert topic.approved?
487
- topic.reload
488
- assert topic.approved?
489
-
490
- topic.update_column(:approved, false)
491
- assert !topic.approved?
492
- topic.reload
493
- assert !topic.approved?
494
- end
495
-
496
- def test_update_column_should_not_use_setter_method
497
- dev = Developer.find(1)
498
- dev.instance_eval { def salary=(value); write_attribute(:salary, value * 2); end }
499
-
500
- dev.update_column(:salary, 80000)
501
- assert_equal 80000, dev.salary
502
-
503
- dev.reload
504
- assert_equal 80000, dev.salary
505
- end
506
-
507
- def test_update_column_should_raise_exception_if_new_record
508
- topic = Topic.new
509
- assert_raises(ActiveRecord::ActiveRecordError) { topic.update_column("approved", false) }
510
- end
511
-
512
- def test_update_column_should_not_leave_the_object_dirty
513
- topic = Topic.find(1)
514
- topic.update_column("content", "--- Have a nice day\n...\n")
515
-
516
- topic.reload
517
- topic.update_column(:content, "--- You too\n...\n")
518
- assert_equal [], topic.changed
519
-
520
- topic.reload
521
- topic.update_column("content", "--- Have a nice day\n...\n")
522
- assert_equal [], topic.changed
523
- end
524
-
525
- def test_update_column_with_model_having_primary_key_other_than_id
526
- minivan = Minivan.find('m1')
527
- new_name = 'sebavan'
528
-
529
- minivan.update_column(:name, new_name)
530
- assert_equal new_name, minivan.name
531
- end
532
-
533
- def test_update_column_for_readonly_attribute
534
- minivan = Minivan.find('m1')
535
- prev_color = minivan.color
536
- assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_column(:color, 'black') }
537
- assert_equal prev_color, minivan.color
538
- end
539
-
540
- def test_update_column_should_not_modify_updated_at
541
- developer = Developer.find(1)
542
- prev_month = Time.now.prev_month.change(usec: 0)
543
-
544
- developer.update_column(:updated_at, prev_month)
545
- assert_equal prev_month, developer.updated_at
546
-
547
- developer.update_column(:salary, 80001)
548
- assert_equal prev_month, developer.updated_at
549
-
550
- developer.reload
551
- assert_equal prev_month.to_i, developer.updated_at.to_i
552
- end
553
-
554
- def test_update_column_with_one_changed_and_one_updated
555
- t = Topic.order('id').limit(1).first
556
- author_name = t.author_name
557
- t.author_name = 'John'
558
- t.update_column(:title, 'super_title')
559
- assert_equal 'John', t.author_name
560
- assert_equal 'super_title', t.title
561
- assert t.changed?, "topic should have changed"
562
- assert t.author_name_changed?, "author_name should have changed"
563
-
564
- t.reload
565
- assert_equal author_name, t.author_name
566
- assert_equal 'super_title', t.title
567
- end
568
-
569
- def test_update_column_with_default_scope
570
- developer = DeveloperCalledDavid.first
571
- developer.name = 'John'
572
- developer.save!
573
-
574
- assert developer.update_column(:name, 'Will'), 'did not update record due to default scope'
575
- end
576
-
577
- def test_update_columns
578
- topic = Topic.find(1)
579
- topic.update_columns({ "approved" => true, title: "Sebastian Topic" })
580
- assert topic.approved?
581
- assert_equal "Sebastian Topic", topic.title
582
- topic.reload
583
- assert topic.approved?
584
- assert_equal "Sebastian Topic", topic.title
585
- end
586
-
587
- def test_update_columns_should_not_use_setter_method
588
- dev = Developer.find(1)
589
- dev.instance_eval { def salary=(value); write_attribute(:salary, value * 2); end }
590
-
591
- dev.update_columns(salary: 80000)
592
- assert_equal 80000, dev.salary
593
-
594
- dev.reload
595
- assert_equal 80000, dev.salary
596
- end
597
-
598
- def test_update_columns_should_raise_exception_if_new_record
599
- topic = Topic.new
600
- assert_raises(ActiveRecord::ActiveRecordError) { topic.update_columns({ approved: false }) }
601
- end
602
-
603
- def test_update_columns_should_not_leave_the_object_dirty
604
- topic = Topic.find(1)
605
- topic.update({ "content" => "--- Have a nice day\n...\n", :author_name => "Jose" })
606
-
607
- topic.reload
608
- topic.update_columns({ content: "--- You too\n...\n", "author_name" => "Sebastian" })
609
- assert_equal [], topic.changed
610
-
611
- topic.reload
612
- topic.update_columns({ content: "--- Have a nice day\n...\n", author_name: "Jose" })
613
- assert_equal [], topic.changed
614
- end
615
-
616
- def test_update_columns_with_model_having_primary_key_other_than_id
617
- minivan = Minivan.find('m1')
618
- new_name = 'sebavan'
619
-
620
- minivan.update_columns(name: new_name)
621
- assert_equal new_name, minivan.name
622
- end
623
-
624
- def test_update_columns_with_one_readonly_attribute
625
- minivan = Minivan.find('m1')
626
- prev_color = minivan.color
627
- prev_name = minivan.name
628
- assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_columns({ name: "My old minivan", color: 'black' }) }
629
- assert_equal prev_color, minivan.color
630
- assert_equal prev_name, minivan.name
631
-
632
- minivan.reload
633
- assert_equal prev_color, minivan.color
634
- assert_equal prev_name, minivan.name
635
- end
636
-
637
- def test_update_columns_should_not_modify_updated_at
638
- developer = Developer.find(1)
639
- prev_month = Time.now.prev_month.change(usec: 0)
640
-
641
- developer.update_columns(updated_at: prev_month)
642
- assert_equal prev_month, developer.updated_at
643
-
644
- developer.update_columns(salary: 80000)
645
- assert_equal prev_month, developer.updated_at
646
- assert_equal 80000, developer.salary
647
-
648
- developer.reload
649
- assert_equal prev_month.to_i, developer.updated_at.to_i
650
- assert_equal 80000, developer.salary
651
- end
652
-
653
- def test_update_columns_with_one_changed_and_one_updated
654
- t = Topic.order('id').limit(1).first
655
- author_name = t.author_name
656
- t.author_name = 'John'
657
- t.update_columns(title: 'super_title')
658
- assert_equal 'John', t.author_name
659
- assert_equal 'super_title', t.title
660
- assert t.changed?, "topic should have changed"
661
- assert t.author_name_changed?, "author_name should have changed"
662
-
663
- t.reload
664
- assert_equal author_name, t.author_name
665
- assert_equal 'super_title', t.title
666
- end
667
-
668
- def test_update_columns_changing_id
669
- topic = Topic.find(1)
670
- topic.update_columns(id: 123)
671
- assert_equal 123, topic.id
672
- topic.reload
673
- assert_equal 123, topic.id
674
- end
675
-
676
- def test_update_columns_returns_boolean
677
- topic = Topic.find(1)
678
- assert_equal true, topic.update_columns(title: "New title")
679
- end
680
-
681
- def test_update_columns_with_default_scope
682
- developer = DeveloperCalledDavid.first
683
- developer.name = 'John'
684
- developer.save!
685
-
686
- assert developer.update_columns(name: 'Will'), 'did not update record due to default scope'
687
- end
688
-
689
- def test_update
690
- topic = Topic.find(1)
691
- assert !topic.approved?
692
- assert_equal "The First Topic", topic.title
693
-
694
- topic.update("approved" => true, "title" => "The First Topic Updated")
695
- topic.reload
696
- assert topic.approved?
697
- assert_equal "The First Topic Updated", topic.title
698
-
699
- topic.update(approved: false, title: "The First Topic")
700
- topic.reload
701
- assert !topic.approved?
702
- assert_equal "The First Topic", topic.title
703
- end
704
-
705
- def test_update_attributes
706
- topic = Topic.find(1)
707
- assert !topic.approved?
708
- assert_equal "The First Topic", topic.title
709
-
710
- topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
711
- topic.reload
712
- assert topic.approved?
713
- assert_equal "The First Topic Updated", topic.title
714
-
715
- topic.update_attributes(approved: false, title: "The First Topic")
716
- topic.reload
717
- assert !topic.approved?
718
- assert_equal "The First Topic", topic.title
719
-
720
- assert_raise(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid) do
721
- topic.update_attributes(id: 3, title: "Hm is it possible?")
722
- end
723
- assert_not_equal "Hm is it possible?", Topic.find(3).title
724
-
725
- topic.update_attributes(id: 1234)
726
- assert_nothing_raised { topic.reload }
727
- assert_equal topic.title, Topic.find(1234).title
728
- end
729
-
730
- def test_update_attributes_parameters
731
- topic = Topic.find(1)
732
- assert_nothing_raised do
733
- topic.update_attributes({})
734
- end
735
-
736
- assert_raises(ArgumentError) do
737
- topic.update_attributes(nil)
738
- end
739
- end
740
-
741
- def test_update!
742
- Reply.validates_presence_of(:title)
743
- reply = Reply.find(2)
744
- assert_equal "The Second Topic of the day", reply.title
745
- assert_equal "Have a nice day", reply.content
746
-
747
- reply.update!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
748
- reply.reload
749
- assert_equal "The Second Topic of the day updated", reply.title
750
- assert_equal "Have a nice evening", reply.content
751
-
752
- reply.update!(title: "The Second Topic of the day", content: "Have a nice day")
753
- reply.reload
754
- assert_equal "The Second Topic of the day", reply.title
755
- assert_equal "Have a nice day", reply.content
756
-
757
- assert_raise(ActiveRecord::RecordInvalid) { reply.update!(title: nil, content: "Have a nice evening") }
758
- ensure
759
- Reply.clear_validators!
760
- end
761
-
762
- def test_update_attributes!
763
- Reply.validates_presence_of(:title)
764
- reply = Reply.find(2)
765
- assert_equal "The Second Topic of the day", reply.title
766
- assert_equal "Have a nice day", reply.content
767
-
768
- reply.update_attributes!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
769
- reply.reload
770
- assert_equal "The Second Topic of the day updated", reply.title
771
- assert_equal "Have a nice evening", reply.content
772
-
773
- reply.update_attributes!(title: "The Second Topic of the day", content: "Have a nice day")
774
- reply.reload
775
- assert_equal "The Second Topic of the day", reply.title
776
- assert_equal "Have a nice day", reply.content
777
-
778
- assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(title: nil, content: "Have a nice evening") }
779
- ensure
780
- Reply.clear_validators!
781
- end
782
-
783
- def test_destroyed_returns_boolean
784
- developer = Developer.first
785
- assert_equal false, developer.destroyed?
786
- developer.destroy
787
- assert_equal true, developer.destroyed?
788
-
789
- developer = Developer.last
790
- assert_equal false, developer.destroyed?
791
- developer.delete
792
- assert_equal true, developer.destroyed?
793
- end
794
-
795
- def test_persisted_returns_boolean
796
- developer = Developer.new(:name => "Jose")
797
- assert_equal false, developer.persisted?
798
- developer.save!
799
- assert_equal true, developer.persisted?
800
-
801
- developer = Developer.first
802
- assert_equal true, developer.persisted?
803
- developer.destroy
804
- assert_equal false, developer.persisted?
805
-
806
- developer = Developer.last
807
- assert_equal true, developer.persisted?
808
- developer.delete
809
- assert_equal false, developer.persisted?
810
- end
811
-
812
- def test_class_level_destroy
813
- should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
814
- Topic.find(1).replies << should_be_destroyed_reply
815
-
816
- Topic.destroy(1)
817
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
818
- assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
819
- end
820
-
821
- def test_class_level_delete
822
- should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
823
- Topic.find(1).replies << should_be_destroyed_reply
824
-
825
- Topic.delete(1)
826
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
827
- assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
828
- end
829
-
830
- def test_create_with_custom_timestamps
831
- custom_datetime = 1.hour.ago.beginning_of_day
832
-
833
- %w(created_at created_on updated_at updated_on).each do |attribute|
834
- parrot = LiveParrot.create(:name => "colombian", attribute => custom_datetime)
835
- assert_equal custom_datetime, parrot[attribute]
836
- end
837
- end
838
-
839
- def test_persist_inherited_class_with_different_table_name
840
- minimalistic_aircrafts = Class.new(Minimalistic) do
841
- self.table_name = "aircraft"
842
- end
843
-
844
- assert_difference "Aircraft.count", 1 do
845
- aircraft = minimalistic_aircrafts.create(name: "Wright Flyer")
846
- aircraft.name = "Wright Glider"
847
- aircraft.save
848
- end
849
-
850
- assert_equal "Wright Glider", Aircraft.last.name
851
- end
852
-
853
- def test_instantiate_creates_a_new_instance
854
- post = Post.instantiate("title" => "appropriate documentation", "type" => "SpecialPost")
855
- assert_equal "appropriate documentation", post.title
856
- assert_instance_of SpecialPost, post
857
-
858
- # body was not initialized
859
- assert_raises ActiveModel::MissingAttributeError do
860
- post.body
861
- end
862
- end
863
-
864
- def test_reload_removes_custom_selects
865
- post = Post.select('posts.*, 1 as wibble').last!
866
-
867
- assert_equal 1, post[:wibble]
868
- assert_nil post.reload[:wibble]
869
- end
870
-
871
- def test_find_via_reload
872
- post = Post.new
873
-
874
- assert post.new_record?
875
-
876
- post.id = 1
877
- post.reload
878
-
879
- assert_equal "Welcome to the weblog", post.title
880
- assert_not post.new_record?
881
- end
882
-
883
- def test_reload_via_querycache
884
- ActiveRecord::Base.connection.enable_query_cache!
885
- ActiveRecord::Base.connection.clear_query_cache
886
- assert ActiveRecord::Base.connection.query_cache_enabled, 'cache should be on'
887
- parrot = Parrot.create(:name => 'Shane')
888
-
889
- # populate the cache with the SELECT result
890
- found_parrot = Parrot.find(parrot.id)
891
- assert_equal parrot.id, found_parrot.id
892
-
893
- # Manually update the 'name' attribute in the DB directly
894
- assert_equal 1, ActiveRecord::Base.connection.query_cache.length
895
- ActiveRecord::Base.uncached do
896
- found_parrot.name = 'Mary'
897
- found_parrot.save
898
- end
899
-
900
- # Now reload, and verify that it gets the DB version, and not the querycache version
901
- found_parrot.reload
902
- assert_equal 'Mary', found_parrot.name
903
-
904
- found_parrot = Parrot.find(parrot.id)
905
- assert_equal 'Mary', found_parrot.name
906
- ensure
907
- ActiveRecord::Base.connection.disable_query_cache!
908
- end
909
- end
1
+ require "cases/helper"
2
+ require 'models/aircraft'
3
+ require 'models/post'
4
+ require 'models/comment'
5
+ require 'models/author'
6
+ require 'models/topic'
7
+ require 'models/reply'
8
+ require 'models/category'
9
+ require 'models/company'
10
+ require 'models/developer'
11
+ require 'models/computer'
12
+ require 'models/project'
13
+ require 'models/minimalistic'
14
+ require 'models/warehouse_thing'
15
+ require 'models/parrot'
16
+ require 'models/minivan'
17
+ require 'models/owner'
18
+ require 'models/person'
19
+ require 'models/pet'
20
+ require 'models/ship'
21
+ require 'models/toy'
22
+ require 'models/admin'
23
+ require 'models/admin/user'
24
+ require 'rexml/document'
25
+
26
+ class PersistenceTest < ActiveRecord::TestCase
27
+ fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse_things', :authors, :author_addresses, :categorizations, :categories, :posts, :minivans, :pets, :toys
28
+
29
+ # Oracle UPDATE does not support ORDER BY
30
+ unless current_adapter?(:OracleAdapter)
31
+ def test_update_all_ignores_order_without_limit_from_association
32
+ author = authors(:david)
33
+ assert_nothing_raised do
34
+ assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all([ "body = ?", "bulk update!" ])
35
+ end
36
+ end
37
+
38
+ def test_update_all_doesnt_ignore_order
39
+ assert_equal authors(:david).id + 1, authors(:mary).id # make sure there is going to be a duplicate PK error
40
+ test_update_with_order_succeeds = lambda do |order|
41
+ begin
42
+ Author.order(order).update_all('id = id + 1')
43
+ rescue ActiveRecord::ActiveRecordError
44
+ false
45
+ end
46
+ end
47
+
48
+ if test_update_with_order_succeeds.call('id DESC')
49
+ assert !test_update_with_order_succeeds.call('id ASC') # test that this wasn't a fluke and using an incorrect order results in an exception
50
+ else
51
+ # test that we're failing because the current Arel's engine doesn't support UPDATE ORDER BY queries is using subselects instead
52
+ assert_sql(/\AUPDATE .+ \(SELECT .* ORDER BY id DESC\)\Z/i) do
53
+ test_update_with_order_succeeds.call('id DESC')
54
+ end
55
+ end
56
+ end
57
+
58
+ def test_update_all_with_order_and_limit_updates_subset_only
59
+ author = authors(:david)
60
+ assert_nothing_raised do
61
+ assert_equal 1, author.posts_sorted_by_id_limited.size
62
+ assert_equal 2, author.posts_sorted_by_id_limited.limit(2).to_a.size
63
+ assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ])
64
+ assert_equal "bulk update!", posts(:welcome).body
65
+ assert_not_equal "bulk update!", posts(:thinking).body
66
+ end
67
+ end
68
+ end
69
+
70
+ def test_update_many
71
+ topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
72
+ updated = Topic.update(topic_data.keys, topic_data.values)
73
+
74
+ assert_equal 2, updated.size
75
+ assert_equal "1 updated", Topic.find(1).content
76
+ assert_equal "2 updated", Topic.find(2).content
77
+ end
78
+
79
+ def test_delete_all
80
+ assert Topic.count > 0
81
+
82
+ assert_equal Topic.count, Topic.delete_all
83
+ end
84
+
85
+ def test_delete_all_with_joins_and_where_part_is_hash
86
+ where_args = {:toys => {:name => 'Bone'}}
87
+ count = Pet.joins(:toys).where(where_args).count
88
+
89
+ assert_equal count, 1
90
+ assert_equal count, Pet.joins(:toys).where(where_args).delete_all
91
+ end
92
+
93
+ def test_delete_all_with_joins_and_where_part_is_not_hash
94
+ where_args = ['toys.name = ?', 'Bone']
95
+ count = Pet.joins(:toys).where(where_args).count
96
+
97
+ assert_equal count, 1
98
+ assert_equal count, Pet.joins(:toys).where(where_args).delete_all
99
+ end
100
+
101
+ def test_increment_attribute
102
+ assert_equal 50, accounts(:signals37).credit_limit
103
+ accounts(:signals37).increment! :credit_limit
104
+ assert_equal 51, accounts(:signals37, :reload).credit_limit
105
+
106
+ accounts(:signals37).increment(:credit_limit).increment!(:credit_limit)
107
+ assert_equal 53, accounts(:signals37, :reload).credit_limit
108
+ end
109
+
110
+ def test_increment_nil_attribute
111
+ assert_nil topics(:first).parent_id
112
+ topics(:first).increment! :parent_id
113
+ assert_equal 1, topics(:first).parent_id
114
+ end
115
+
116
+ def test_increment_attribute_by
117
+ assert_equal 50, accounts(:signals37).credit_limit
118
+ accounts(:signals37).increment! :credit_limit, 5
119
+ assert_equal 55, accounts(:signals37, :reload).credit_limit
120
+
121
+ accounts(:signals37).increment(:credit_limit, 1).increment!(:credit_limit, 3)
122
+ assert_equal 59, accounts(:signals37, :reload).credit_limit
123
+ end
124
+
125
+ def test_increment_updates_counter_in_db_using_offset
126
+ a1 = accounts(:signals37)
127
+ initial_credit = a1.credit_limit
128
+ a2 = Account.find(accounts(:signals37).id)
129
+ a1.increment!(:credit_limit)
130
+ a2.increment!(:credit_limit)
131
+ assert_equal initial_credit + 2, a1.reload.credit_limit
132
+ end
133
+
134
+ def test_destroy_all
135
+ conditions = "author_name = 'Mary'"
136
+ topics_by_mary = Topic.all.merge!(:where => conditions, :order => 'id').to_a
137
+ assert ! topics_by_mary.empty?
138
+
139
+ assert_difference('Topic.count', -topics_by_mary.size) do
140
+ destroyed = Topic.where(conditions).destroy_all.sort_by(&:id)
141
+ assert_equal topics_by_mary, destroyed
142
+ assert destroyed.all?(&:frozen?), "destroyed topics should be frozen"
143
+ end
144
+ end
145
+
146
+ def test_destroy_many
147
+ clients = Client.all.merge!(:order => 'id').find([2, 3])
148
+
149
+ assert_difference('Client.count', -2) do
150
+ destroyed = Client.destroy([2, 3]).sort_by(&:id)
151
+ assert_equal clients, destroyed
152
+ assert destroyed.all?(&:frozen?), "destroyed clients should be frozen"
153
+ end
154
+ end
155
+
156
+ def test_becomes
157
+ assert_kind_of Reply, topics(:first).becomes(Reply)
158
+ assert_equal "The First Topic", topics(:first).becomes(Reply).title
159
+ end
160
+
161
+ def test_becomes_includes_errors
162
+ company = Company.new(:name => nil)
163
+ assert !company.valid?
164
+ original_errors = company.errors
165
+ client = company.becomes(Client)
166
+ assert_equal original_errors.keys, client.errors.keys
167
+ end
168
+
169
+ def test_becomes_errors_base
170
+ child_class = Class.new(Admin::User) do
171
+ store_accessor :settings, :foo
172
+
173
+ def self.name; 'Admin::ChildUser'; end
174
+ end
175
+
176
+ admin = Admin::User.new
177
+ admin.errors.add :token, :invalid
178
+ child = admin.becomes(child_class)
179
+
180
+ assert_equal [:token], child.errors.keys
181
+ assert_nothing_raised do
182
+ child.errors.add :foo, :invalid
183
+ end
184
+ end
185
+
186
+ def test_duped_becomes_persists_changes_from_the_original
187
+ original = topics(:first)
188
+ copy = original.dup.becomes(Reply)
189
+ copy.save!
190
+ assert_equal "The First Topic", Topic.find(copy.id).title
191
+ end
192
+
193
+ def test_becomes_includes_changed_attributes
194
+ company = Company.new(name: "37signals")
195
+ client = company.becomes(Client)
196
+ assert_equal "37signals", client.name
197
+ assert_equal %w{name}, client.changed
198
+ end
199
+
200
+ def test_delete_many
201
+ original_count = Topic.count
202
+ Topic.delete(deleting = [1, 2])
203
+ assert_equal original_count - deleting.size, Topic.count
204
+ end
205
+
206
+ def test_decrement_attribute
207
+ assert_equal 50, accounts(:signals37).credit_limit
208
+
209
+ accounts(:signals37).decrement!(:credit_limit)
210
+ assert_equal 49, accounts(:signals37, :reload).credit_limit
211
+
212
+ accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit)
213
+ assert_equal 47, accounts(:signals37, :reload).credit_limit
214
+ end
215
+
216
+ def test_decrement_attribute_by
217
+ assert_equal 50, accounts(:signals37).credit_limit
218
+ accounts(:signals37).decrement! :credit_limit, 5
219
+ assert_equal 45, accounts(:signals37, :reload).credit_limit
220
+
221
+ accounts(:signals37).decrement(:credit_limit, 1).decrement!(:credit_limit, 3)
222
+ assert_equal 41, accounts(:signals37, :reload).credit_limit
223
+ end
224
+
225
+ def test_create
226
+ topic = Topic.new
227
+ topic.title = "New Topic"
228
+ topic.save
229
+ topic_reloaded = Topic.find(topic.id)
230
+ assert_equal("New Topic", topic_reloaded.title)
231
+ end
232
+
233
+ def test_save!
234
+ topic = Topic.new(:title => "New Topic")
235
+ assert topic.save!
236
+
237
+ reply = WrongReply.new
238
+ assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
239
+ end
240
+
241
+ def test_save_null_string_attributes
242
+ topic = Topic.find(1)
243
+ topic.attributes = { "title" => "null", "author_name" => "null" }
244
+ topic.save!
245
+ topic.reload
246
+ assert_equal("null", topic.title)
247
+ assert_equal("null", topic.author_name)
248
+ end
249
+
250
+ def test_save_nil_string_attributes
251
+ topic = Topic.find(1)
252
+ topic.title = nil
253
+ topic.save!
254
+ topic.reload
255
+ assert_nil topic.title
256
+ end
257
+
258
+ def test_save_for_record_with_only_primary_key
259
+ minimalistic = Minimalistic.new
260
+ assert_nothing_raised { minimalistic.save }
261
+ end
262
+
263
+ def test_save_for_record_with_only_primary_key_that_is_provided
264
+ assert_nothing_raised { Minimalistic.create!(:id => 2) }
265
+ end
266
+
267
+ def test_save_with_duping_of_destroyed_object
268
+ developer = Developer.first
269
+ developer.destroy
270
+ new_developer = developer.dup
271
+ new_developer.save
272
+ assert new_developer.persisted?
273
+ assert_not new_developer.destroyed?
274
+ end
275
+
276
+ def test_create_many
277
+ topics = Topic.create([ { "title" => "first" }, { "title" => "second" }])
278
+ assert_equal 2, topics.size
279
+ assert_equal "first", topics.first.title
280
+ end
281
+
282
+ def test_create_columns_not_equal_attributes
283
+ topic = Topic.instantiate(
284
+ 'attributes' => {
285
+ 'title' => 'Another New Topic',
286
+ 'does_not_exist' => 'test'
287
+ }
288
+ )
289
+ assert_nothing_raised { topic.save }
290
+ end
291
+
292
+ def test_create_through_factory_with_block
293
+ topic = Topic.create("title" => "New Topic") do |t|
294
+ t.author_name = "David"
295
+ end
296
+ assert_equal("New Topic", topic.title)
297
+ assert_equal("David", topic.author_name)
298
+ end
299
+
300
+ def test_create_many_through_factory_with_block
301
+ topics = Topic.create([ { "title" => "first" }, { "title" => "second" }]) do |t|
302
+ t.author_name = "David"
303
+ end
304
+ assert_equal 2, topics.size
305
+ topic1, topic2 = Topic.find(topics[0].id), Topic.find(topics[1].id)
306
+ assert_equal "first", topic1.title
307
+ assert_equal "David", topic1.author_name
308
+ assert_equal "second", topic2.title
309
+ assert_equal "David", topic2.author_name
310
+ end
311
+
312
+ def test_update_object
313
+ topic = Topic.new
314
+ topic.title = "Another New Topic"
315
+ topic.written_on = "2003-12-12 23:23:00"
316
+ topic.save
317
+ topic_reloaded = Topic.find(topic.id)
318
+ assert_equal("Another New Topic", topic_reloaded.title)
319
+
320
+ topic_reloaded.title = "Updated topic"
321
+ topic_reloaded.save
322
+
323
+ topic_reloaded_again = Topic.find(topic.id)
324
+
325
+ assert_equal("Updated topic", topic_reloaded_again.title)
326
+ end
327
+
328
+ def test_update_columns_not_equal_attributes
329
+ topic = Topic.new
330
+ topic.title = "Still another topic"
331
+ topic.save
332
+
333
+ topic_reloaded = Topic.instantiate(topic.attributes.merge('does_not_exist' => 'test'))
334
+ topic_reloaded.title = 'A New Topic'
335
+ assert_nothing_raised { topic_reloaded.save }
336
+ end
337
+
338
+ def test_update_for_record_with_only_primary_key
339
+ minimalistic = minimalistics(:first)
340
+ assert_nothing_raised { minimalistic.save }
341
+ end
342
+
343
+ def test_update_sti_type
344
+ assert_instance_of Reply, topics(:second)
345
+
346
+ topic = topics(:second).becomes!(Topic)
347
+ assert_instance_of Topic, topic
348
+ topic.save!
349
+ assert_instance_of Topic, Topic.find(topic.id)
350
+ end
351
+
352
+ def test_preserve_original_sti_type
353
+ reply = topics(:second)
354
+ assert_equal "Reply", reply.type
355
+
356
+ topic = reply.becomes(Topic)
357
+ assert_equal "Reply", reply.type
358
+
359
+ assert_instance_of Topic, topic
360
+ assert_equal "Reply", topic.type
361
+ end
362
+
363
+ def test_update_sti_subclass_type
364
+ assert_instance_of Topic, topics(:first)
365
+
366
+ reply = topics(:first).becomes!(Reply)
367
+ assert_instance_of Reply, reply
368
+ reply.save!
369
+ assert_instance_of Reply, Reply.find(reply.id)
370
+ end
371
+
372
+ def test_update_after_create
373
+ klass = Class.new(Topic) do
374
+ def self.name; 'Topic'; end
375
+ after_create do
376
+ update_attribute("author_name", "David")
377
+ end
378
+ end
379
+ topic = klass.new
380
+ topic.title = "Another New Topic"
381
+ topic.save
382
+
383
+ topic_reloaded = Topic.find(topic.id)
384
+ assert_equal("Another New Topic", topic_reloaded.title)
385
+ assert_equal("David", topic_reloaded.author_name)
386
+ end
387
+
388
+ def test_update_attribute_does_not_run_sql_if_attribute_is_not_changed
389
+ klass = Class.new(Topic) do
390
+ def self.name; 'Topic'; end
391
+ end
392
+ topic = klass.create(title: 'Another New Topic')
393
+ assert_queries(0) do
394
+ assert topic.update_attribute(:title, "Another New Topic")
395
+ end
396
+ end
397
+
398
+ def test_update_does_not_run_sql_if_record_has_not_changed
399
+ topic = Topic.create(title: "Another New Topic")
400
+ assert_queries(0) { assert topic.update(title: "Another New Topic") }
401
+ assert_queries(0) { assert topic.update_attributes(title: "Another New Topic") }
402
+ end
403
+
404
+ def test_delete
405
+ topic = Topic.find(1)
406
+ assert_equal topic, topic.delete, 'topic.delete did not return self'
407
+ assert topic.frozen?, 'topic not frozen after delete'
408
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
409
+ end
410
+
411
+ def test_delete_doesnt_run_callbacks
412
+ Topic.find(1).delete
413
+ assert_not_nil Topic.find(2)
414
+ end
415
+
416
+ def test_destroy
417
+ topic = Topic.find(1)
418
+ assert_equal topic, topic.destroy, 'topic.destroy did not return self'
419
+ assert topic.frozen?, 'topic not frozen after destroy'
420
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
421
+ end
422
+
423
+ def test_destroy!
424
+ topic = Topic.find(1)
425
+ assert_equal topic, topic.destroy!, 'topic.destroy! did not return self'
426
+ assert topic.frozen?, 'topic not frozen after destroy!'
427
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
428
+ end
429
+
430
+ def test_record_not_found_exception
431
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(99999) }
432
+ end
433
+
434
+ def test_update_all
435
+ assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
436
+ assert_equal "bulk updated!", Topic.find(1).content
437
+ assert_equal "bulk updated!", Topic.find(2).content
438
+
439
+ assert_equal Topic.count, Topic.update_all(['content = ?', 'bulk updated again!'])
440
+ assert_equal "bulk updated again!", Topic.find(1).content
441
+ assert_equal "bulk updated again!", Topic.find(2).content
442
+
443
+ assert_equal Topic.count, Topic.update_all(['content = ?', nil])
444
+ assert_nil Topic.find(1).content
445
+ end
446
+
447
+ def test_update_all_with_hash
448
+ assert_not_nil Topic.find(1).last_read
449
+ assert_equal Topic.count, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil)
450
+ assert_equal "bulk updated with hash!", Topic.find(1).content
451
+ assert_equal "bulk updated with hash!", Topic.find(2).content
452
+ assert_nil Topic.find(1).last_read
453
+ assert_nil Topic.find(2).last_read
454
+ end
455
+
456
+ def test_update_all_with_non_standard_table_name
457
+ assert_equal 1, WarehouseThing.where(id: 1).update_all(['value = ?', 0])
458
+ assert_equal 0, WarehouseThing.find(1).value
459
+ end
460
+
461
+ def test_delete_new_record
462
+ client = Client.new
463
+ client.delete
464
+ assert client.frozen?
465
+ end
466
+
467
+ def test_delete_record_with_associations
468
+ client = Client.find(3)
469
+ client.delete
470
+ assert client.frozen?
471
+ assert_kind_of Firm, client.firm
472
+ assert_raise(RuntimeError) { client.name = "something else" }
473
+ end
474
+
475
+ def test_destroy_new_record
476
+ client = Client.new
477
+ client.destroy
478
+ assert client.frozen?
479
+ end
480
+
481
+ def test_destroy_record_with_associations
482
+ client = Client.find(3)
483
+ client.destroy
484
+ assert client.frozen?
485
+ assert_kind_of Firm, client.firm
486
+ assert_raise(RuntimeError) { client.name = "something else" }
487
+ end
488
+
489
+ def test_update_attribute
490
+ assert !Topic.find(1).approved?
491
+ Topic.find(1).update_attribute("approved", true)
492
+ assert Topic.find(1).approved?
493
+
494
+ Topic.find(1).update_attribute(:approved, false)
495
+ assert !Topic.find(1).approved?
496
+ end
497
+
498
+ def test_update_attribute_for_readonly_attribute
499
+ minivan = Minivan.find('m1')
500
+ assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_attribute(:color, 'black') }
501
+ end
502
+
503
+ def test_update_attribute_with_one_updated
504
+ t = Topic.first
505
+ t.update_attribute(:title, 'super_title')
506
+ assert_equal 'super_title', t.title
507
+ assert !t.changed?, "topic should not have changed"
508
+ assert !t.title_changed?, "title should not have changed"
509
+ assert_nil t.title_change, 'title change should be nil'
510
+
511
+ t.reload
512
+ assert_equal 'super_title', t.title
513
+ end
514
+
515
+ def test_update_attribute_for_updated_at_on
516
+ developer = Developer.find(1)
517
+ prev_month = Time.now.prev_month.change(usec: 0)
518
+
519
+ developer.update_attribute(:updated_at, prev_month)
520
+ assert_equal prev_month, developer.updated_at
521
+
522
+ developer.update_attribute(:salary, 80001)
523
+ assert_not_equal prev_month, developer.updated_at
524
+
525
+ developer.reload
526
+ assert_not_equal prev_month, developer.updated_at
527
+ end
528
+
529
+ def test_update_column
530
+ topic = Topic.find(1)
531
+ topic.update_column("approved", true)
532
+ assert topic.approved?
533
+ topic.reload
534
+ assert topic.approved?
535
+
536
+ topic.update_column(:approved, false)
537
+ assert !topic.approved?
538
+ topic.reload
539
+ assert !topic.approved?
540
+ end
541
+
542
+ def test_update_column_should_not_use_setter_method
543
+ dev = Developer.find(1)
544
+ dev.instance_eval { def salary=(value); write_attribute(:salary, value * 2); end }
545
+
546
+ dev.update_column(:salary, 80000)
547
+ assert_equal 80000, dev.salary
548
+
549
+ dev.reload
550
+ assert_equal 80000, dev.salary
551
+ end
552
+
553
+ def test_update_column_should_raise_exception_if_new_record
554
+ topic = Topic.new
555
+ assert_raises(ActiveRecord::ActiveRecordError) { topic.update_column("approved", false) }
556
+ end
557
+
558
+ def test_update_column_should_not_leave_the_object_dirty
559
+ topic = Topic.find(1)
560
+ topic.update_column("content", "--- Have a nice day\n...\n")
561
+
562
+ topic.reload
563
+ topic.update_column(:content, "--- You too\n...\n")
564
+ assert_equal [], topic.changed
565
+
566
+ topic.reload
567
+ topic.update_column("content", "--- Have a nice day\n...\n")
568
+ assert_equal [], topic.changed
569
+ end
570
+
571
+ def test_update_column_with_model_having_primary_key_other_than_id
572
+ minivan = Minivan.find('m1')
573
+ new_name = 'sebavan'
574
+
575
+ minivan.update_column(:name, new_name)
576
+ assert_equal new_name, minivan.name
577
+ end
578
+
579
+ def test_update_column_for_readonly_attribute
580
+ minivan = Minivan.find('m1')
581
+ prev_color = minivan.color
582
+ assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_column(:color, 'black') }
583
+ assert_equal prev_color, minivan.color
584
+ end
585
+
586
+ def test_update_column_should_not_modify_updated_at
587
+ developer = Developer.find(1)
588
+ prev_month = Time.now.prev_month.change(usec: 0)
589
+
590
+ developer.update_column(:updated_at, prev_month)
591
+ assert_equal prev_month, developer.updated_at
592
+
593
+ developer.update_column(:salary, 80001)
594
+ assert_equal prev_month, developer.updated_at
595
+
596
+ developer.reload
597
+ assert_equal prev_month.to_i, developer.updated_at.to_i
598
+ end
599
+
600
+ def test_update_column_with_one_changed_and_one_updated
601
+ t = Topic.order('id').limit(1).first
602
+ author_name = t.author_name
603
+ t.author_name = 'John'
604
+ t.update_column(:title, 'super_title')
605
+ assert_equal 'John', t.author_name
606
+ assert_equal 'super_title', t.title
607
+ assert t.changed?, "topic should have changed"
608
+ assert t.author_name_changed?, "author_name should have changed"
609
+
610
+ t.reload
611
+ assert_equal author_name, t.author_name
612
+ assert_equal 'super_title', t.title
613
+ end
614
+
615
+ def test_update_column_with_default_scope
616
+ developer = DeveloperCalledDavid.first
617
+ developer.name = 'John'
618
+ developer.save!
619
+
620
+ assert developer.update_column(:name, 'Will'), 'did not update record due to default scope'
621
+ end
622
+
623
+ def test_update_columns
624
+ topic = Topic.find(1)
625
+ topic.update_columns({ "approved" => true, title: "Sebastian Topic" })
626
+ assert topic.approved?
627
+ assert_equal "Sebastian Topic", topic.title
628
+ topic.reload
629
+ assert topic.approved?
630
+ assert_equal "Sebastian Topic", topic.title
631
+ end
632
+
633
+ def test_update_columns_should_not_use_setter_method
634
+ dev = Developer.find(1)
635
+ dev.instance_eval { def salary=(value); write_attribute(:salary, value * 2); end }
636
+
637
+ dev.update_columns(salary: 80000)
638
+ assert_equal 80000, dev.salary
639
+
640
+ dev.reload
641
+ assert_equal 80000, dev.salary
642
+ end
643
+
644
+ def test_update_columns_should_raise_exception_if_new_record
645
+ topic = Topic.new
646
+ assert_raises(ActiveRecord::ActiveRecordError) { topic.update_columns({ approved: false }) }
647
+ end
648
+
649
+ def test_update_columns_should_not_leave_the_object_dirty
650
+ topic = Topic.find(1)
651
+ topic.update({ "content" => "--- Have a nice day\n...\n", :author_name => "Jose" })
652
+
653
+ topic.reload
654
+ topic.update_columns({ content: "--- You too\n...\n", "author_name" => "Sebastian" })
655
+ assert_equal [], topic.changed
656
+
657
+ topic.reload
658
+ topic.update_columns({ content: "--- Have a nice day\n...\n", author_name: "Jose" })
659
+ assert_equal [], topic.changed
660
+ end
661
+
662
+ def test_update_columns_with_model_having_primary_key_other_than_id
663
+ minivan = Minivan.find('m1')
664
+ new_name = 'sebavan'
665
+
666
+ minivan.update_columns(name: new_name)
667
+ assert_equal new_name, minivan.name
668
+ end
669
+
670
+ def test_update_columns_with_one_readonly_attribute
671
+ minivan = Minivan.find('m1')
672
+ prev_color = minivan.color
673
+ prev_name = minivan.name
674
+ assert_raises(ActiveRecord::ActiveRecordError) { minivan.update_columns({ name: "My old minivan", color: 'black' }) }
675
+ assert_equal prev_color, minivan.color
676
+ assert_equal prev_name, minivan.name
677
+
678
+ minivan.reload
679
+ assert_equal prev_color, minivan.color
680
+ assert_equal prev_name, minivan.name
681
+ end
682
+
683
+ def test_update_columns_should_not_modify_updated_at
684
+ developer = Developer.find(1)
685
+ prev_month = Time.now.prev_month.change(usec: 0)
686
+
687
+ developer.update_columns(updated_at: prev_month)
688
+ assert_equal prev_month, developer.updated_at
689
+
690
+ developer.update_columns(salary: 80000)
691
+ assert_equal prev_month, developer.updated_at
692
+ assert_equal 80000, developer.salary
693
+
694
+ developer.reload
695
+ assert_equal prev_month.to_i, developer.updated_at.to_i
696
+ assert_equal 80000, developer.salary
697
+ end
698
+
699
+ def test_update_columns_with_one_changed_and_one_updated
700
+ t = Topic.order('id').limit(1).first
701
+ author_name = t.author_name
702
+ t.author_name = 'John'
703
+ t.update_columns(title: 'super_title')
704
+ assert_equal 'John', t.author_name
705
+ assert_equal 'super_title', t.title
706
+ assert t.changed?, "topic should have changed"
707
+ assert t.author_name_changed?, "author_name should have changed"
708
+
709
+ t.reload
710
+ assert_equal author_name, t.author_name
711
+ assert_equal 'super_title', t.title
712
+ end
713
+
714
+ def test_update_columns_changing_id
715
+ topic = Topic.find(1)
716
+ topic.update_columns(id: 123)
717
+ assert_equal 123, topic.id
718
+ topic.reload
719
+ assert_equal 123, topic.id
720
+ end
721
+
722
+ def test_update_columns_returns_boolean
723
+ topic = Topic.find(1)
724
+ assert_equal true, topic.update_columns(title: "New title")
725
+ end
726
+
727
+ def test_update_columns_with_default_scope
728
+ developer = DeveloperCalledDavid.first
729
+ developer.name = 'John'
730
+ developer.save!
731
+
732
+ assert developer.update_columns(name: 'Will'), 'did not update record due to default scope'
733
+ end
734
+
735
+ def test_update
736
+ topic = Topic.find(1)
737
+ assert !topic.approved?
738
+ assert_equal "The First Topic", topic.title
739
+
740
+ topic.update("approved" => true, "title" => "The First Topic Updated")
741
+ topic.reload
742
+ assert topic.approved?
743
+ assert_equal "The First Topic Updated", topic.title
744
+
745
+ topic.update(approved: false, title: "The First Topic")
746
+ topic.reload
747
+ assert !topic.approved?
748
+ assert_equal "The First Topic", topic.title
749
+ end
750
+
751
+ def test_update_attributes
752
+ topic = Topic.find(1)
753
+ assert !topic.approved?
754
+ assert_equal "The First Topic", topic.title
755
+
756
+ topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
757
+ topic.reload
758
+ assert topic.approved?
759
+ assert_equal "The First Topic Updated", topic.title
760
+
761
+ topic.update_attributes(approved: false, title: "The First Topic")
762
+ topic.reload
763
+ assert !topic.approved?
764
+ assert_equal "The First Topic", topic.title
765
+
766
+ error = assert_raise(ActiveRecord::RecordNotUnique, ActiveRecord::StatementInvalid) do
767
+ topic.update_attributes(id: 3, title: "Hm is it possible?")
768
+ end
769
+ assert_not_nil error.cause
770
+ assert_not_equal "Hm is it possible?", Topic.find(3).title
771
+
772
+ topic.update_attributes(id: 1234)
773
+ assert_nothing_raised { topic.reload }
774
+ assert_equal topic.title, Topic.find(1234).title
775
+ end
776
+
777
+ def test_update_attributes_parameters
778
+ topic = Topic.find(1)
779
+ assert_nothing_raised do
780
+ topic.update_attributes({})
781
+ end
782
+
783
+ assert_raises(ArgumentError) do
784
+ topic.update_attributes(nil)
785
+ end
786
+ end
787
+
788
+ def test_update!
789
+ Reply.validates_presence_of(:title)
790
+ reply = Reply.find(2)
791
+ assert_equal "The Second Topic of the day", reply.title
792
+ assert_equal "Have a nice day", reply.content
793
+
794
+ reply.update!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
795
+ reply.reload
796
+ assert_equal "The Second Topic of the day updated", reply.title
797
+ assert_equal "Have a nice evening", reply.content
798
+
799
+ reply.update!(title: "The Second Topic of the day", content: "Have a nice day")
800
+ reply.reload
801
+ assert_equal "The Second Topic of the day", reply.title
802
+ assert_equal "Have a nice day", reply.content
803
+
804
+ assert_raise(ActiveRecord::RecordInvalid) { reply.update!(title: nil, content: "Have a nice evening") }
805
+ ensure
806
+ Reply.clear_validators!
807
+ end
808
+
809
+ def test_update_attributes!
810
+ Reply.validates_presence_of(:title)
811
+ reply = Reply.find(2)
812
+ assert_equal "The Second Topic of the day", reply.title
813
+ assert_equal "Have a nice day", reply.content
814
+
815
+ reply.update_attributes!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
816
+ reply.reload
817
+ assert_equal "The Second Topic of the day updated", reply.title
818
+ assert_equal "Have a nice evening", reply.content
819
+
820
+ reply.update_attributes!(title: "The Second Topic of the day", content: "Have a nice day")
821
+ reply.reload
822
+ assert_equal "The Second Topic of the day", reply.title
823
+ assert_equal "Have a nice day", reply.content
824
+
825
+ assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(title: nil, content: "Have a nice evening") }
826
+ ensure
827
+ Reply.clear_validators!
828
+ end
829
+
830
+ def test_destroyed_returns_boolean
831
+ developer = Developer.first
832
+ assert_equal false, developer.destroyed?
833
+ developer.destroy
834
+ assert_equal true, developer.destroyed?
835
+
836
+ developer = Developer.last
837
+ assert_equal false, developer.destroyed?
838
+ developer.delete
839
+ assert_equal true, developer.destroyed?
840
+ end
841
+
842
+ def test_persisted_returns_boolean
843
+ developer = Developer.new(:name => "Jose")
844
+ assert_equal false, developer.persisted?
845
+ developer.save!
846
+ assert_equal true, developer.persisted?
847
+
848
+ developer = Developer.first
849
+ assert_equal true, developer.persisted?
850
+ developer.destroy
851
+ assert_equal false, developer.persisted?
852
+
853
+ developer = Developer.last
854
+ assert_equal true, developer.persisted?
855
+ developer.delete
856
+ assert_equal false, developer.persisted?
857
+ end
858
+
859
+ def test_class_level_destroy
860
+ should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
861
+ Topic.find(1).replies << should_be_destroyed_reply
862
+
863
+ Topic.destroy(1)
864
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
865
+ assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
866
+ end
867
+
868
+ def test_class_level_delete
869
+ should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
870
+ Topic.find(1).replies << should_be_destroyed_reply
871
+
872
+ Topic.delete(1)
873
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
874
+ assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
875
+ end
876
+
877
+ def test_create_with_custom_timestamps
878
+ custom_datetime = 1.hour.ago.beginning_of_day
879
+
880
+ %w(created_at created_on updated_at updated_on).each do |attribute|
881
+ parrot = LiveParrot.create(:name => "colombian", attribute => custom_datetime)
882
+ assert_equal custom_datetime, parrot[attribute]
883
+ end
884
+ end
885
+
886
+ def test_persist_inherited_class_with_different_table_name
887
+ minimalistic_aircrafts = Class.new(Minimalistic) do
888
+ self.table_name = "aircraft"
889
+ end
890
+
891
+ assert_difference "Aircraft.count", 1 do
892
+ aircraft = minimalistic_aircrafts.create(name: "Wright Flyer")
893
+ aircraft.name = "Wright Glider"
894
+ aircraft.save
895
+ end
896
+
897
+ assert_equal "Wright Glider", Aircraft.last.name
898
+ end
899
+
900
+ def test_instantiate_creates_a_new_instance
901
+ post = Post.instantiate("title" => "appropriate documentation", "type" => "SpecialPost")
902
+ assert_equal "appropriate documentation", post.title
903
+ assert_instance_of SpecialPost, post
904
+
905
+ # body was not initialized
906
+ assert_raises ActiveModel::MissingAttributeError do
907
+ post.body
908
+ end
909
+ end
910
+
911
+ def test_reload_removes_custom_selects
912
+ post = Post.select('posts.*, 1 as wibble').last!
913
+
914
+ assert_equal 1, post[:wibble]
915
+ assert_nil post.reload[:wibble]
916
+ end
917
+
918
+ def test_find_via_reload
919
+ post = Post.new
920
+
921
+ assert post.new_record?
922
+
923
+ post.id = 1
924
+ post.reload
925
+
926
+ assert_equal "Welcome to the weblog", post.title
927
+ assert_not post.new_record?
928
+ end
929
+
930
+ def test_reload_via_querycache
931
+ ActiveRecord::Base.connection.enable_query_cache!
932
+ ActiveRecord::Base.connection.clear_query_cache
933
+ assert ActiveRecord::Base.connection.query_cache_enabled, 'cache should be on'
934
+ parrot = Parrot.create(:name => 'Shane')
935
+
936
+ # populate the cache with the SELECT result
937
+ found_parrot = Parrot.find(parrot.id)
938
+ assert_equal parrot.id, found_parrot.id
939
+
940
+ # Manually update the 'name' attribute in the DB directly
941
+ assert_equal 1, ActiveRecord::Base.connection.query_cache.length
942
+ ActiveRecord::Base.uncached do
943
+ found_parrot.name = 'Mary'
944
+ found_parrot.save
945
+ end
946
+
947
+ # Now reload, and verify that it gets the DB version, and not the querycache version
948
+ found_parrot.reload
949
+ assert_equal 'Mary', found_parrot.name
950
+
951
+ found_parrot = Parrot.find(parrot.id)
952
+ assert_equal 'Mary', found_parrot.name
953
+ ensure
954
+ ActiveRecord::Base.connection.disable_query_cache!
955
+ end
956
+
957
+ class SaveTest < ActiveRecord::TestCase
958
+ self.use_transactional_tests = false
959
+
960
+ def test_save_touch_false
961
+ widget = Class.new(ActiveRecord::Base) do
962
+ connection.create_table :widgets, force: true do |t|
963
+ t.string :name
964
+ t.timestamps null: false
965
+ end
966
+
967
+ self.table_name = :widgets
968
+ end
969
+
970
+ instance = widget.create!({
971
+ name: 'Bob',
972
+ created_at: 1.day.ago,
973
+ updated_at: 1.day.ago
974
+ })
975
+
976
+ created_at = instance.created_at
977
+ updated_at = instance.updated_at
978
+
979
+ instance.name = 'Barb'
980
+ instance.save!(touch: false)
981
+ assert_equal instance.created_at, created_at
982
+ assert_equal instance.updated_at, updated_at
983
+ ensure
984
+ ActiveRecord::Base.connection.drop_table widget.table_name
985
+ widget.reset_column_information
986
+ end
987
+ end
988
+
989
+ def test_reset_column_information_resets_children
990
+ child = Class.new(Topic)
991
+ child.new # force schema to load
992
+
993
+ ActiveRecord::Base.connection.add_column(:topics, :foo, :string)
994
+ Topic.reset_column_information
995
+
996
+ assert_equal "bar", child.new(foo: :bar).foo
997
+ ensure
998
+ ActiveRecord::Base.connection.remove_column(:topics, :foo)
999
+ Topic.reset_column_information
1000
+ end
1001
+ end