ibm_db 3.0.4-x86-mingw32 → 5.0.4-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 (593) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +8 -1
  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 +269 -0
  8. data/ext/Makefile.nt32 +181 -181
  9. data/ext/Makefile.nt32.191 +212 -212
  10. data/ext/extconf.rb +322 -291
  11. data/ext/gil_release_version +3 -0
  12. data/ext/ibm_db-i386-mingw32.def +2 -0
  13. data/ext/ibm_db.c +11879 -11884
  14. data/ext/ibm_db.o +0 -0
  15. data/ext/ibm_db.so +0 -0
  16. data/ext/mkmf.log +110 -0
  17. data/ext/ruby_ibm_db.h +241 -241
  18. data/ext/ruby_ibm_db_cli.c +866 -866
  19. data/ext/ruby_ibm_db_cli.h +500 -500
  20. data/ext/ruby_ibm_db_cli.o +0 -0
  21. data/ext/unicode_support_version +3 -0
  22. data/init.rb +41 -41
  23. data/lib/IBM_DB.rb +27 -27
  24. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3561 -3177
  25. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -2
  26. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  27. data/lib/mswin32/ibm_db.rb +91 -123
  28. data/lib/mswin32/rb2x/i386/ibm_db.so +0 -0
  29. data/test/active_record/connection_adapters/fake_adapter.rb +49 -46
  30. data/test/assets/example.log +1 -1
  31. data/test/assets/test.txt +1 -1
  32. data/test/cases/adapter_test.rb +351 -261
  33. data/test/cases/adapters/mysql2/active_schema_test.rb +193 -0
  34. data/test/cases/adapters/mysql2/bind_parameter_test.rb +50 -0
  35. data/test/cases/adapters/mysql2/boolean_test.rb +100 -0
  36. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +63 -0
  37. data/test/cases/adapters/mysql2/charset_collation_test.rb +54 -0
  38. data/test/cases/adapters/mysql2/connection_test.rb +210 -0
  39. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +45 -0
  40. data/test/cases/adapters/mysql2/enum_test.rb +26 -0
  41. data/test/cases/adapters/mysql2/explain_test.rb +21 -0
  42. data/test/cases/adapters/mysql2/json_test.rb +195 -0
  43. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +83 -0
  44. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  45. data/test/cases/adapters/mysql2/schema_migrations_test.rb +59 -0
  46. data/test/cases/adapters/mysql2/schema_test.rb +126 -0
  47. data/test/cases/adapters/mysql2/sp_test.rb +36 -0
  48. data/test/cases/adapters/mysql2/sql_types_test.rb +14 -0
  49. data/test/cases/adapters/mysql2/table_options_test.rb +42 -0
  50. data/test/cases/adapters/mysql2/unsigned_type_test.rb +66 -0
  51. data/test/cases/adapters/postgresql/active_schema_test.rb +98 -0
  52. data/test/cases/adapters/postgresql/array_test.rb +339 -0
  53. data/test/cases/adapters/postgresql/bit_string_test.rb +82 -0
  54. data/test/cases/adapters/postgresql/bytea_test.rb +134 -0
  55. data/test/cases/adapters/postgresql/case_insensitive_test.rb +26 -0
  56. data/test/cases/adapters/postgresql/change_schema_test.rb +38 -0
  57. data/test/cases/adapters/postgresql/cidr_test.rb +25 -0
  58. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  59. data/test/cases/adapters/postgresql/collation_test.rb +53 -0
  60. data/test/cases/adapters/postgresql/composite_test.rb +132 -0
  61. data/test/cases/adapters/postgresql/connection_test.rb +257 -0
  62. data/test/cases/adapters/postgresql/datatype_test.rb +92 -0
  63. data/test/cases/adapters/postgresql/domain_test.rb +47 -0
  64. data/test/cases/adapters/postgresql/enum_test.rb +91 -0
  65. data/test/cases/adapters/postgresql/explain_test.rb +20 -0
  66. data/test/cases/adapters/postgresql/extension_migration_test.rb +63 -0
  67. data/test/cases/adapters/postgresql/full_text_test.rb +44 -0
  68. data/test/cases/adapters/postgresql/geometric_test.rb +378 -0
  69. data/test/cases/adapters/postgresql/hstore_test.rb +382 -0
  70. data/test/cases/adapters/postgresql/infinity_test.rb +69 -0
  71. data/test/cases/adapters/postgresql/integer_test.rb +25 -0
  72. data/test/cases/adapters/postgresql/json_test.rb +237 -0
  73. data/test/cases/adapters/postgresql/ltree_test.rb +53 -0
  74. data/test/cases/adapters/postgresql/money_test.rb +96 -0
  75. data/test/cases/adapters/postgresql/network_test.rb +94 -0
  76. data/test/cases/adapters/postgresql/numbers_test.rb +49 -0
  77. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +405 -0
  78. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  79. data/test/cases/adapters/postgresql/quoting_test.rb +44 -0
  80. data/test/cases/adapters/postgresql/range_test.rb +343 -0
  81. data/test/cases/adapters/postgresql/referential_integrity_test.rb +111 -0
  82. data/test/cases/adapters/postgresql/rename_table_test.rb +34 -0
  83. data/test/cases/adapters/postgresql/schema_authorization_test.rb +119 -0
  84. data/test/cases/adapters/postgresql/schema_test.rb +597 -0
  85. data/test/cases/adapters/postgresql/serial_test.rb +154 -0
  86. data/test/cases/adapters/postgresql/statement_pool_test.rb +41 -0
  87. data/test/cases/adapters/postgresql/timestamp_test.rb +90 -0
  88. data/test/cases/adapters/postgresql/type_lookup_test.rb +33 -0
  89. data/test/cases/adapters/postgresql/utils_test.rb +62 -0
  90. data/test/cases/adapters/postgresql/uuid_test.rb +294 -0
  91. data/test/cases/adapters/postgresql/xml_test.rb +54 -0
  92. data/test/cases/adapters/sqlite3/collation_test.rb +53 -0
  93. data/test/cases/adapters/sqlite3/copy_table_test.rb +98 -0
  94. data/test/cases/adapters/sqlite3/explain_test.rb +21 -0
  95. data/test/cases/adapters/sqlite3/quoting_test.rb +101 -0
  96. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +441 -0
  97. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  98. data/test/cases/adapters/sqlite3/statement_pool_test.rb +20 -0
  99. data/test/cases/aggregations_test.rb +168 -158
  100. data/test/cases/ar_schema_test.rb +146 -161
  101. data/test/cases/associations/association_scope_test.rb +16 -21
  102. data/test/cases/associations/belongs_to_associations_test.rb +1141 -1029
  103. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +41 -0
  104. data/test/cases/associations/callbacks_test.rb +190 -192
  105. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
  106. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
  107. data/test/cases/associations/eager_load_nested_include_test.rb +126 -128
  108. data/test/cases/associations/eager_singularization_test.rb +148 -148
  109. data/test/cases/associations/eager_test.rb +1514 -1411
  110. data/test/cases/associations/extension_test.rb +87 -82
  111. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1004 -932
  112. data/test/cases/associations/has_many_associations_test.rb +2501 -2162
  113. data/test/cases/associations/has_many_through_associations_test.rb +1271 -1204
  114. data/test/cases/associations/has_one_associations_test.rb +707 -610
  115. data/test/cases/associations/has_one_through_associations_test.rb +383 -380
  116. data/test/cases/associations/inner_join_association_test.rb +139 -139
  117. data/test/cases/associations/inverse_associations_test.rb +733 -693
  118. data/test/cases/associations/join_model_test.rb +777 -754
  119. data/test/cases/associations/left_outer_join_association_test.rb +88 -0
  120. data/test/cases/associations/nested_through_associations_test.rb +579 -579
  121. data/test/cases/associations/required_test.rb +102 -82
  122. data/test/cases/associations_test.rb +385 -380
  123. data/test/cases/attribute_decorators_test.rb +126 -125
  124. data/test/cases/attribute_methods/read_test.rb +60 -60
  125. data/test/cases/attribute_methods_test.rb +1009 -952
  126. data/test/cases/attribute_set_test.rb +270 -200
  127. data/test/cases/attribute_test.rb +246 -180
  128. data/test/cases/attributes_test.rb +253 -136
  129. data/test/cases/autosave_association_test.rb +1708 -1595
  130. data/test/cases/base_test.rb +1713 -1638
  131. data/test/cases/batches_test.rb +489 -212
  132. data/test/cases/binary_test.rb +44 -52
  133. data/test/cases/bind_parameter_test.rb +110 -100
  134. data/test/cases/cache_key_test.rb +26 -0
  135. data/test/cases/calculations_test.rb +798 -646
  136. data/test/cases/callbacks_test.rb +636 -543
  137. data/test/cases/clone_test.rb +40 -40
  138. data/test/cases/coders/json_test.rb +15 -0
  139. data/test/cases/coders/yaml_column_test.rb +63 -63
  140. data/test/cases/collection_cache_key_test.rb +115 -0
  141. data/test/cases/column_alias_test.rb +17 -17
  142. data/test/cases/column_definition_test.rb +92 -123
  143. data/test/cases/comment_test.rb +145 -0
  144. data/test/cases/connection_adapters/adapter_leasing_test.rb +56 -54
  145. data/test/cases/connection_adapters/connection_handler_test.rb +160 -53
  146. data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
  147. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +255 -293
  148. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +69 -65
  149. data/test/cases/connection_adapters/quoting_test.rb +13 -13
  150. data/test/cases/connection_adapters/schema_cache_test.rb +61 -56
  151. data/test/cases/connection_adapters/type_lookup_test.rb +118 -110
  152. data/test/cases/connection_management_test.rb +112 -122
  153. data/test/cases/connection_pool_test.rb +521 -346
  154. data/test/cases/connection_specification/resolver_test.rb +131 -116
  155. data/test/cases/core_test.rb +112 -112
  156. data/test/cases/counter_cache_test.rb +214 -209
  157. data/test/cases/custom_locking_test.rb +17 -17
  158. data/test/cases/database_statements_test.rb +34 -19
  159. data/test/cases/{invalid_date_test.rb → date_test.rb} +44 -32
  160. data/test/cases/date_time_precision_test.rb +107 -0
  161. data/test/cases/date_time_test.rb +61 -61
  162. data/test/cases/defaults_test.rb +219 -223
  163. data/test/cases/dirty_test.rb +763 -775
  164. data/test/cases/disconnected_test.rb +30 -28
  165. data/test/cases/dup_test.rb +157 -157
  166. data/test/cases/enum_test.rb +444 -290
  167. data/test/cases/errors_test.rb +16 -0
  168. data/test/cases/explain_subscriber_test.rb +64 -64
  169. data/test/cases/explain_test.rb +87 -76
  170. data/test/cases/finder_respond_to_test.rb +60 -60
  171. data/test/cases/finder_test.rb +1294 -1166
  172. data/test/cases/fixture_set/file_test.rb +156 -138
  173. data/test/cases/fixtures_test.rb +988 -897
  174. data/test/cases/forbidden_attributes_protection_test.rb +165 -99
  175. data/test/cases/habtm_destroy_order_test.rb +61 -61
  176. data/test/cases/helper.rb +204 -210
  177. data/test/cases/hot_compatibility_test.rb +142 -54
  178. data/test/cases/i18n_test.rb +45 -45
  179. data/test/cases/inheritance_test.rb +606 -375
  180. data/test/cases/integration_test.rb +155 -139
  181. data/test/cases/invalid_connection_test.rb +24 -22
  182. data/test/cases/invertible_migration_test.rb +387 -295
  183. data/test/cases/json_serialization_test.rb +311 -302
  184. data/test/cases/locking_test.rb +493 -477
  185. data/test/cases/log_subscriber_test.rb +225 -136
  186. data/test/cases/migration/change_schema_test.rb +458 -472
  187. data/test/cases/migration/change_table_test.rb +256 -224
  188. data/test/cases/migration/column_attributes_test.rb +176 -192
  189. data/test/cases/migration/column_positioning_test.rb +56 -56
  190. data/test/cases/migration/columns_test.rb +310 -304
  191. data/test/cases/migration/command_recorder_test.rb +350 -305
  192. data/test/cases/migration/compatibility_test.rb +118 -0
  193. data/test/cases/migration/create_join_table_test.rb +157 -148
  194. data/test/cases/migration/foreign_key_test.rb +362 -360
  195. data/test/cases/migration/helper.rb +39 -39
  196. data/test/cases/migration/index_test.rb +218 -216
  197. data/test/cases/migration/logger_test.rb +36 -36
  198. data/test/cases/migration/pending_migrations_test.rb +52 -53
  199. data/test/cases/migration/references_foreign_key_test.rb +221 -214
  200. data/test/cases/migration/references_index_test.rb +101 -101
  201. data/test/cases/migration/references_statements_test.rb +136 -116
  202. data/test/cases/migration/rename_table_test.rb +93 -93
  203. data/test/cases/migration_test.rb +1157 -959
  204. data/test/cases/migrator_test.rb +471 -388
  205. data/test/cases/mixin_test.rb +68 -70
  206. data/test/cases/modules_test.rb +172 -173
  207. data/test/cases/multiparameter_attributes_test.rb +372 -350
  208. data/test/cases/multiple_db_test.rb +122 -115
  209. data/test/cases/nested_attributes_test.rb +1098 -1057
  210. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
  211. data/test/cases/persistence_test.rb +1001 -909
  212. data/test/cases/pooled_connections_test.rb +81 -81
  213. data/test/cases/primary_keys_test.rb +376 -237
  214. data/test/cases/query_cache_test.rb +446 -326
  215. data/test/cases/quoting_test.rb +202 -156
  216. data/test/cases/readonly_test.rb +119 -118
  217. data/test/cases/reaper_test.rb +85 -85
  218. data/test/cases/reflection_test.rb +509 -454
  219. data/test/cases/relation/delegation_test.rb +63 -68
  220. data/test/cases/relation/merging_test.rb +157 -161
  221. data/test/cases/relation/mutation_test.rb +183 -165
  222. data/test/cases/relation/or_test.rb +92 -0
  223. data/test/cases/relation/predicate_builder_test.rb +16 -14
  224. data/test/cases/relation/record_fetch_warning_test.rb +40 -0
  225. data/test/cases/relation/where_chain_test.rb +105 -181
  226. data/test/cases/relation/where_clause_test.rb +182 -0
  227. data/test/cases/relation/where_test.rb +322 -300
  228. data/test/cases/relation_test.rb +328 -297
  229. data/test/cases/relations_test.rb +2026 -1815
  230. data/test/cases/reload_models_test.rb +22 -22
  231. data/test/cases/result_test.rb +90 -80
  232. data/test/cases/sanitize_test.rb +176 -83
  233. data/test/cases/schema_dumper_test.rb +457 -463
  234. data/test/cases/schema_loading_test.rb +52 -0
  235. data/test/cases/scoping/default_scoping_test.rb +528 -454
  236. data/test/cases/scoping/named_scoping_test.rb +561 -524
  237. data/test/cases/scoping/relation_scoping_test.rb +400 -357
  238. data/test/cases/secure_token_test.rb +32 -0
  239. data/test/cases/serialization_test.rb +104 -104
  240. data/test/cases/serialized_attribute_test.rb +364 -277
  241. data/test/cases/statement_cache_test.rb +136 -98
  242. data/test/cases/store_test.rb +195 -194
  243. data/test/cases/suppressor_test.rb +63 -0
  244. data/test/cases/tasks/database_tasks_test.rb +462 -396
  245. data/test/cases/tasks/mysql_rake_test.rb +345 -311
  246. data/test/cases/tasks/postgresql_rake_test.rb +304 -245
  247. data/test/cases/tasks/sqlite_rake_test.rb +220 -193
  248. data/test/cases/test_case.rb +131 -123
  249. data/test/cases/test_fixtures_test.rb +36 -0
  250. data/test/cases/time_precision_test.rb +103 -0
  251. data/test/cases/timestamp_test.rb +501 -468
  252. data/test/cases/touch_later_test.rb +121 -0
  253. data/test/cases/transaction_callbacks_test.rb +518 -452
  254. data/test/cases/transaction_isolation_test.rb +106 -106
  255. data/test/cases/transactions_test.rb +835 -817
  256. data/test/cases/type/adapter_specific_registry_test.rb +133 -0
  257. data/test/cases/type/date_time_test.rb +14 -0
  258. data/test/cases/type/integer_test.rb +27 -121
  259. data/test/cases/type/string_test.rb +22 -36
  260. data/test/cases/type/type_map_test.rb +177 -177
  261. data/test/cases/type_test.rb +39 -0
  262. data/test/cases/types_test.rb +24 -141
  263. data/test/cases/unconnected_test.rb +33 -33
  264. data/test/cases/validations/absence_validation_test.rb +73 -0
  265. data/test/cases/validations/association_validation_test.rb +97 -86
  266. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
  267. data/test/cases/validations/i18n_validation_test.rb +86 -90
  268. data/test/cases/validations/length_validation_test.rb +79 -47
  269. data/test/cases/validations/presence_validation_test.rb +103 -68
  270. data/test/cases/validations/uniqueness_validation_test.rb +548 -434
  271. data/test/cases/validations_repair_helper.rb +19 -23
  272. data/test/cases/validations_test.rb +194 -165
  273. data/test/cases/view_test.rb +216 -113
  274. data/test/cases/yaml_serialization_test.rb +121 -86
  275. data/test/config.example.yml +97 -0
  276. data/test/config.rb +5 -5
  277. data/test/config.yml +154 -154
  278. data/test/connections/native_ibm_db/connection.rb +43 -43
  279. data/test/fixtures/accounts.yml +29 -29
  280. data/test/fixtures/admin/accounts.yml +2 -2
  281. data/test/fixtures/admin/randomly_named_a9.yml +7 -7
  282. data/test/fixtures/admin/randomly_named_b0.yml +7 -7
  283. data/test/fixtures/admin/users.yml +10 -10
  284. data/test/fixtures/author_addresses.yml +17 -17
  285. data/test/fixtures/author_favorites.yml +3 -3
  286. data/test/fixtures/authors.yml +23 -23
  287. data/test/fixtures/bad_posts.yml +9 -0
  288. data/test/fixtures/binaries.yml +133 -133
  289. data/test/fixtures/books.yml +31 -11
  290. data/test/fixtures/bulbs.yml +5 -5
  291. data/test/fixtures/cars.yml +9 -9
  292. data/test/fixtures/categories.yml +19 -19
  293. data/test/fixtures/categories/special_categories.yml +9 -9
  294. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
  295. data/test/fixtures/categories_ordered.yml +7 -7
  296. data/test/fixtures/categories_posts.yml +31 -31
  297. data/test/fixtures/categorizations.yml +23 -23
  298. data/test/fixtures/clubs.yml +8 -8
  299. data/test/fixtures/collections.yml +3 -3
  300. data/test/fixtures/colleges.yml +3 -3
  301. data/test/fixtures/comments.yml +65 -65
  302. data/test/fixtures/companies.yml +67 -67
  303. data/test/fixtures/computers.yml +10 -10
  304. data/test/fixtures/content.yml +3 -0
  305. data/test/fixtures/content_positions.yml +3 -0
  306. data/test/fixtures/courses.yml +8 -8
  307. data/test/fixtures/customers.yml +25 -25
  308. data/test/fixtures/dashboards.yml +6 -6
  309. data/test/fixtures/dead_parrots.yml +5 -0
  310. data/test/fixtures/developers.yml +21 -21
  311. data/test/fixtures/developers_projects.yml +16 -16
  312. data/test/fixtures/dog_lovers.yml +7 -7
  313. data/test/fixtures/dogs.yml +4 -4
  314. data/test/fixtures/doubloons.yml +3 -3
  315. data/test/fixtures/edges.yml +5 -5
  316. data/test/fixtures/entrants.yml +14 -14
  317. data/test/fixtures/essays.yml +6 -6
  318. data/test/fixtures/faces.yml +11 -11
  319. data/test/fixtures/fk_test_has_fk.yml +3 -3
  320. data/test/fixtures/fk_test_has_pk.yml +1 -1
  321. data/test/fixtures/friendships.yml +4 -4
  322. data/test/fixtures/funny_jokes.yml +10 -10
  323. data/test/fixtures/interests.yml +33 -33
  324. data/test/fixtures/items.yml +3 -3
  325. data/test/fixtures/jobs.yml +7 -7
  326. data/test/fixtures/legacy_things.yml +3 -3
  327. data/test/fixtures/live_parrots.yml +4 -0
  328. data/test/fixtures/mateys.yml +4 -4
  329. data/test/fixtures/member_details.yml +8 -8
  330. data/test/fixtures/member_types.yml +6 -6
  331. data/test/fixtures/members.yml +11 -11
  332. data/test/fixtures/memberships.yml +34 -34
  333. data/test/fixtures/men.yml +5 -5
  334. data/test/fixtures/minimalistics.yml +2 -2
  335. data/test/fixtures/minivans.yml +5 -5
  336. data/test/fixtures/mixed_case_monkeys.yml +6 -6
  337. data/test/fixtures/mixins.yml +29 -29
  338. data/test/fixtures/movies.yml +7 -7
  339. data/test/fixtures/naked/yml/accounts.yml +1 -1
  340. data/test/fixtures/naked/yml/companies.yml +1 -1
  341. data/test/fixtures/naked/yml/courses.yml +1 -1
  342. data/test/fixtures/naked/yml/parrots.yml +2 -0
  343. data/test/fixtures/naked/yml/trees.yml +3 -0
  344. data/test/fixtures/nodes.yml +29 -0
  345. data/test/fixtures/organizations.yml +5 -5
  346. data/test/fixtures/other_comments.yml +6 -0
  347. data/test/fixtures/other_dogs.yml +2 -0
  348. data/test/fixtures/other_posts.yml +7 -0
  349. data/test/fixtures/other_topics.yml +42 -42
  350. data/test/fixtures/owners.yml +9 -9
  351. data/test/fixtures/parrots.yml +27 -27
  352. data/test/fixtures/parrots_pirates.yml +7 -7
  353. data/test/fixtures/people.yml +24 -24
  354. data/test/fixtures/peoples_treasures.yml +3 -3
  355. data/test/fixtures/pets.yml +19 -19
  356. data/test/fixtures/pirates.yml +12 -12
  357. data/test/fixtures/posts.yml +80 -80
  358. data/test/fixtures/price_estimates.yml +16 -7
  359. data/test/fixtures/products.yml +4 -4
  360. data/test/fixtures/projects.yml +7 -7
  361. data/test/fixtures/randomly_named_a9.yml +7 -7
  362. data/test/fixtures/ratings.yml +14 -14
  363. data/test/fixtures/readers.yml +11 -11
  364. data/test/fixtures/references.yml +17 -17
  365. data/test/fixtures/reserved_words/distinct.yml +5 -5
  366. data/test/fixtures/reserved_words/distinct_select.yml +11 -11
  367. data/test/fixtures/reserved_words/group.yml +14 -14
  368. data/test/fixtures/reserved_words/select.yml +8 -8
  369. data/test/fixtures/reserved_words/values.yml +7 -7
  370. data/test/fixtures/ships.yml +6 -6
  371. data/test/fixtures/speedometers.yml +8 -8
  372. data/test/fixtures/sponsors.yml +12 -12
  373. data/test/fixtures/string_key_objects.yml +7 -7
  374. data/test/fixtures/subscribers.yml +10 -10
  375. data/test/fixtures/subscriptions.yml +12 -12
  376. data/test/fixtures/taggings.yml +78 -78
  377. data/test/fixtures/tags.yml +11 -11
  378. data/test/fixtures/tasks.yml +7 -7
  379. data/test/fixtures/teapots.yml +3 -3
  380. data/test/fixtures/to_be_linked/accounts.yml +2 -2
  381. data/test/fixtures/to_be_linked/users.yml +10 -10
  382. data/test/fixtures/topics.yml +49 -49
  383. data/test/fixtures/toys.yml +14 -14
  384. data/test/fixtures/traffic_lights.yml +9 -9
  385. data/test/fixtures/treasures.yml +10 -10
  386. data/test/fixtures/trees.yml +3 -0
  387. data/test/fixtures/uuid_children.yml +3 -3
  388. data/test/fixtures/uuid_parents.yml +2 -2
  389. data/test/fixtures/variants.yml +4 -4
  390. data/test/fixtures/vegetables.yml +19 -19
  391. data/test/fixtures/vertices.yml +3 -3
  392. data/test/fixtures/warehouse_things.yml +2 -2
  393. data/test/fixtures/zines.yml +5 -5
  394. data/test/ibm_db_test.rb +24 -24
  395. data/test/migrations/10_urban/9_add_expressions.rb +11 -11
  396. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
  397. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
  398. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -9
  399. data/test/migrations/missing/1_people_have_last_names.rb +9 -9
  400. data/test/migrations/missing/3_we_need_reminders.rb +12 -12
  401. data/test/migrations/missing/4_innocent_jointable.rb +12 -12
  402. data/test/migrations/rename/1_we_need_things.rb +11 -11
  403. data/test/migrations/rename/2_rename_things.rb +9 -9
  404. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
  405. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
  406. data/test/migrations/to_copy2/1_create_articles.rb +7 -7
  407. data/test/migrations/to_copy2/2_create_comments.rb +7 -7
  408. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
  409. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
  410. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
  411. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
  412. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
  413. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
  414. data/test/migrations/valid/2_we_need_reminders.rb +12 -12
  415. data/test/migrations/valid/3_innocent_jointable.rb +12 -12
  416. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
  417. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -12
  418. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -12
  419. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
  420. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
  421. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
  422. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
  423. data/test/models/admin.rb +4 -4
  424. data/test/models/admin/account.rb +2 -2
  425. data/test/models/admin/randomly_named_c1.rb +7 -3
  426. data/test/models/admin/user.rb +40 -40
  427. data/test/models/aircraft.rb +5 -4
  428. data/test/models/arunit2_model.rb +3 -3
  429. data/test/models/author.rb +209 -212
  430. data/test/models/auto_id.rb +4 -4
  431. data/test/models/autoloadable/extra_firm.rb +2 -2
  432. data/test/models/binary.rb +1 -1
  433. data/test/models/bird.rb +12 -12
  434. data/test/models/book.rb +23 -18
  435. data/test/models/boolean.rb +2 -2
  436. data/test/models/bulb.rb +52 -51
  437. data/test/models/cake_designer.rb +3 -3
  438. data/test/models/car.rb +29 -26
  439. data/test/models/carrier.rb +2 -2
  440. data/test/models/cat.rb +10 -0
  441. data/test/models/categorization.rb +19 -19
  442. data/test/models/category.rb +35 -35
  443. data/test/models/chef.rb +8 -3
  444. data/test/models/citation.rb +3 -3
  445. data/test/models/club.rb +25 -23
  446. data/test/models/college.rb +10 -10
  447. data/test/models/column.rb +3 -3
  448. data/test/models/column_name.rb +3 -3
  449. data/test/models/comment.rb +76 -64
  450. data/test/models/company.rb +230 -225
  451. data/test/models/company_in_module.rb +98 -98
  452. data/test/models/computer.rb +3 -3
  453. data/test/models/contact.rb +41 -41
  454. data/test/models/content.rb +40 -0
  455. data/test/models/contract.rb +20 -20
  456. data/test/models/country.rb +7 -7
  457. data/test/models/course.rb +6 -6
  458. data/test/models/customer.rb +83 -77
  459. data/test/models/customer_carrier.rb +14 -14
  460. data/test/models/dashboard.rb +3 -3
  461. data/test/models/default.rb +2 -2
  462. data/test/models/department.rb +4 -4
  463. data/test/models/developer.rb +274 -252
  464. data/test/models/dog.rb +5 -5
  465. data/test/models/dog_lover.rb +5 -5
  466. data/test/models/doubloon.rb +12 -12
  467. data/test/models/drink_designer.rb +3 -3
  468. data/test/models/edge.rb +5 -5
  469. data/test/models/electron.rb +5 -5
  470. data/test/models/engine.rb +4 -4
  471. data/test/models/entrant.rb +3 -3
  472. data/test/models/essay.rb +5 -5
  473. data/test/models/event.rb +2 -2
  474. data/test/models/eye.rb +37 -37
  475. data/test/models/face.rb +9 -9
  476. data/test/models/friendship.rb +6 -6
  477. data/test/models/guid.rb +1 -1
  478. data/test/models/guitar.rb +4 -0
  479. data/test/models/hotel.rb +11 -6
  480. data/test/models/image.rb +3 -3
  481. data/test/models/interest.rb +5 -5
  482. data/test/models/invoice.rb +4 -4
  483. data/test/models/item.rb +7 -7
  484. data/test/models/job.rb +7 -7
  485. data/test/models/joke.rb +7 -7
  486. data/test/models/keyboard.rb +3 -3
  487. data/test/models/legacy_thing.rb +3 -3
  488. data/test/models/lesson.rb +11 -11
  489. data/test/models/line_item.rb +3 -3
  490. data/test/models/liquid.rb +4 -4
  491. data/test/models/man.rb +11 -11
  492. data/test/models/matey.rb +4 -4
  493. data/test/models/member.rb +42 -41
  494. data/test/models/member_detail.rb +8 -7
  495. data/test/models/member_type.rb +3 -3
  496. data/test/models/membership.rb +35 -35
  497. data/test/models/mentor.rb +3 -0
  498. data/test/models/minimalistic.rb +2 -2
  499. data/test/models/minivan.rb +9 -9
  500. data/test/models/mixed_case_monkey.rb +3 -3
  501. data/test/models/mocktail_designer.rb +2 -0
  502. data/test/models/molecule.rb +6 -6
  503. data/test/models/movie.rb +5 -5
  504. data/test/models/node.rb +5 -0
  505. data/test/models/non_primary_key.rb +2 -0
  506. data/test/models/notification.rb +3 -0
  507. data/test/models/order.rb +4 -4
  508. data/test/models/organization.rb +14 -14
  509. data/test/models/other_dog.rb +5 -0
  510. data/test/models/owner.rb +37 -34
  511. data/test/models/parrot.rb +28 -29
  512. data/test/models/person.rb +142 -143
  513. data/test/models/personal_legacy_thing.rb +4 -4
  514. data/test/models/pet.rb +18 -15
  515. data/test/models/pet_treasure.rb +6 -0
  516. data/test/models/pirate.rb +92 -92
  517. data/test/models/possession.rb +3 -3
  518. data/test/models/post.rb +273 -264
  519. data/test/models/price_estimate.rb +4 -4
  520. data/test/models/professor.rb +5 -5
  521. data/test/models/project.rb +40 -29
  522. data/test/models/publisher.rb +2 -2
  523. data/test/models/publisher/article.rb +4 -4
  524. data/test/models/publisher/magazine.rb +3 -3
  525. data/test/models/randomly_named_c1.rb +3 -3
  526. data/test/models/rating.rb +4 -4
  527. data/test/models/reader.rb +23 -23
  528. data/test/models/recipe.rb +3 -0
  529. data/test/models/record.rb +2 -2
  530. data/test/models/reference.rb +22 -22
  531. data/test/models/reply.rb +61 -61
  532. data/test/models/ship.rb +39 -33
  533. data/test/models/ship_part.rb +7 -7
  534. data/test/models/shop.rb +17 -17
  535. data/test/models/shop_account.rb +6 -6
  536. data/test/models/speedometer.rb +6 -6
  537. data/test/models/sponsor.rb +7 -7
  538. data/test/models/string_key_object.rb +3 -3
  539. data/test/models/student.rb +4 -4
  540. data/test/models/subject.rb +16 -16
  541. data/test/models/subscriber.rb +8 -8
  542. data/test/models/subscription.rb +4 -4
  543. data/test/models/tag.rb +13 -7
  544. data/test/models/tagging.rb +13 -13
  545. data/test/models/task.rb +5 -5
  546. data/test/models/topic.rb +118 -124
  547. data/test/models/toy.rb +6 -6
  548. data/test/models/traffic_light.rb +4 -4
  549. data/test/models/treasure.rb +14 -14
  550. data/test/models/treaty.rb +7 -7
  551. data/test/models/tree.rb +3 -0
  552. data/test/models/tuning_peg.rb +4 -0
  553. data/test/models/tyre.rb +11 -11
  554. data/test/models/user.rb +14 -0
  555. data/test/models/uuid_child.rb +3 -3
  556. data/test/models/uuid_item.rb +6 -0
  557. data/test/models/uuid_parent.rb +3 -3
  558. data/test/models/vegetables.rb +24 -24
  559. data/test/models/vehicle.rb +6 -6
  560. data/test/models/vertex.rb +9 -9
  561. data/test/models/warehouse_thing.rb +5 -5
  562. data/test/models/wheel.rb +3 -3
  563. data/test/models/without_table.rb +3 -3
  564. data/test/models/zine.rb +3 -3
  565. data/test/schema/mysql2_specific_schema.rb +68 -58
  566. data/test/schema/oracle_specific_schema.rb +40 -43
  567. data/test/schema/postgresql_specific_schema.rb +114 -202
  568. data/test/schema/schema.rb +1057 -938
  569. data/test/schema/schema.rb.original +1057 -0
  570. data/test/schema/sqlite_specific_schema.rb +18 -22
  571. data/test/support/config.rb +43 -43
  572. data/test/support/connection.rb +23 -22
  573. data/test/support/connection_helper.rb +14 -14
  574. data/test/support/ddl_helper.rb +8 -8
  575. data/test/support/schema_dumping_helper.rb +20 -20
  576. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  577. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  578. metadata +146 -30
  579. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  580. data/lib/mswin32/rb21x/i386/ibm_db.so +0 -0
  581. data/lib/mswin32/rb22x/i386/ibm_db.so +0 -0
  582. data/lib/mswin32/rb23x/i386/ibm_db.so +0 -0
  583. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +0 -26
  584. data/test/cases/attribute_methods/serialization_test.rb +0 -29
  585. data/test/cases/migration/change_schema_test - Copy.rb +0 -448
  586. data/test/cases/migration/foreign_key_test - Changed.rb +0 -325
  587. data/test/cases/migration/table_and_index_test.rb +0 -24
  588. data/test/cases/relation/where_test2.rb +0 -36
  589. data/test/cases/type/decimal_test.rb +0 -51
  590. data/test/cases/type/unsigned_integer_test.rb +0 -18
  591. data/test/cases/xml_serialization_test.rb +0 -457
  592. data/test/fixtures/naked/csv/accounts.csv +0 -1
  593. data/test/schema/mysql_specific_schema.rb +0 -70
@@ -1,1638 +1,1713 @@
1
- # encoding: utf-8
2
-
3
- require "cases/helper"
4
- require 'active_support/concurrency/latch'
5
- require 'models/post'
6
- require 'models/author'
7
- require 'models/topic'
8
- require 'models/reply'
9
- require 'models/category'
10
- require 'models/company'
11
- require 'models/customer'
12
- require 'models/developer'
13
- require 'models/computer'
14
- require 'models/project'
15
- require 'models/default'
16
- require 'models/auto_id'
17
- require 'models/boolean'
18
- require 'models/column_name'
19
- require 'models/subscriber'
20
- require 'models/keyboard'
21
- require 'models/comment'
22
- require 'models/minimalistic'
23
- require 'models/warehouse_thing'
24
- require 'models/parrot'
25
- require 'models/person'
26
- require 'models/edge'
27
- require 'models/joke'
28
- require 'models/bird'
29
- require 'models/car'
30
- require 'models/bulb'
31
- require 'rexml/document'
32
-
33
- class FirstAbstractClass < ActiveRecord::Base
34
- self.abstract_class = true
35
- end
36
- class SecondAbstractClass < FirstAbstractClass
37
- self.abstract_class = true
38
- end
39
- class Photo < SecondAbstractClass; end
40
- class Category < ActiveRecord::Base; end
41
- class Categorization < ActiveRecord::Base; end
42
- class Smarts < ActiveRecord::Base; end
43
- class CreditCard < ActiveRecord::Base
44
- class PinNumber < ActiveRecord::Base
45
- class CvvCode < ActiveRecord::Base; end
46
- class SubCvvCode < CvvCode; end
47
- end
48
- class SubPinNumber < PinNumber; end
49
- class Brand < Category; end
50
- end
51
- class MasterCreditCard < ActiveRecord::Base; end
52
- class Post < ActiveRecord::Base; end
53
- class Computer < ActiveRecord::Base; end
54
- class NonExistentTable < ActiveRecord::Base; end
55
- class TestOracleDefault < ActiveRecord::Base; end
56
-
57
- class ReadonlyTitlePost < Post
58
- attr_readonly :title
59
- end
60
-
61
- class Weird < ActiveRecord::Base; end
62
-
63
- class Boolean < ActiveRecord::Base
64
- def has_fun
65
- super
66
- end
67
- end
68
-
69
- class LintTest < ActiveRecord::TestCase
70
- include ActiveModel::Lint::Tests
71
-
72
- class LintModel < ActiveRecord::Base; end
73
-
74
- def setup
75
- @model = LintModel.new
76
- end
77
- end
78
-
79
- class BasicsTest < ActiveRecord::TestCase
80
- fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse_things', :authors, :categorizations, :categories, :posts, :author_addresses
81
-
82
- def test_column_names_are_escaped
83
- conn = ActiveRecord::Base.connection
84
- classname = conn.class.name[/[^:]*$/]
85
- badchar = {
86
- 'SQLite3Adapter' => '"',
87
- 'MysqlAdapter' => '`',
88
- 'Mysql2Adapter' => '`',
89
- 'PostgreSQLAdapter' => '"',
90
- 'OracleAdapter' => '"',
91
- 'IBM_DBAdapter' => '"',
92
- }.fetch(classname) {
93
- raise "need a bad char for #{classname}"
94
- }
95
-
96
- quoted = conn.quote_column_name "foo#{badchar}bar"
97
- if current_adapter?(:OracleAdapter)
98
- # Oracle does not allow double quotes in table and column names at all
99
- # therefore quoting removes them
100
- assert_equal("#{badchar}foobar#{badchar}", quoted)
101
- elsif current_adapter?(:IBM_DBAdapter)
102
- assert_equal("foo#{badchar}bar", quoted)
103
- else
104
- assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted)
105
- end
106
- end
107
-
108
- def test_columns_should_obey_set_primary_key
109
- pk = Subscriber.columns_hash[Subscriber.primary_key]
110
- assert_equal 'nick', pk.name, 'nick should be primary key'
111
- end
112
-
113
- def test_primary_key_with_no_id
114
- assert_nil Edge.primary_key
115
- end
116
-
117
- unless current_adapter?(:PostgreSQLAdapter, :OracleAdapter, :SQLServerAdapter, :IBM_DBAdapter)
118
- def test_limit_with_comma
119
- assert Topic.limit("1,2").to_a
120
- end
121
- end
122
-
123
- def test_limit_without_comma
124
- assert_equal 1, Topic.limit("1").to_a.length
125
- assert_equal 1, Topic.limit(1).to_a.length
126
- end
127
-
128
- def test_limit_should_take_value_from_latest_limit
129
- assert_equal 1, Topic.limit(2).limit(1).to_a.length
130
- end
131
-
132
- def test_invalid_limit
133
- assert_raises(ArgumentError) do
134
- Topic.limit("asdfadf").to_a
135
- end
136
- end
137
-
138
- def test_limit_should_sanitize_sql_injection_for_limit_without_commas
139
- assert_raises(ArgumentError) do
140
- Topic.limit("1 select * from schema").to_a
141
- end
142
- end
143
-
144
- def test_limit_should_sanitize_sql_injection_for_limit_with_commas
145
- assert_raises(ArgumentError) do
146
- Topic.limit("1, 7 procedure help()").to_a
147
- end
148
- end
149
-
150
- unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :IBM_DBAdapter)
151
- def test_limit_should_allow_sql_literal
152
- assert_equal 1, Topic.limit(Arel.sql('2-1')).to_a.length
153
- end
154
- end
155
-
156
- def test_select_symbol
157
- topic_ids = Topic.select(:id).map(&:id).sort
158
- assert_equal Topic.pluck(:id).sort, topic_ids
159
- end
160
-
161
- def test_table_exists
162
- assert !NonExistentTable.table_exists?
163
- assert Topic.table_exists?
164
- end
165
-
166
- def test_preserving_date_objects
167
- # Oracle enhanced adapter allows to define Date attributes in model class (see topic.rb)
168
- assert_kind_of(
169
- Date, Topic.find(1).last_read,
170
- "The last_read attribute should be of the Date class"
171
- )
172
- end
173
-
174
- def test_previously_changed
175
- topic = Topic.first
176
- topic.title = '<3<3<3'
177
- assert_equal({}, topic.previous_changes)
178
-
179
- topic.save!
180
- expected = ["The First Topic", "<3<3<3"]
181
- assert_equal(expected, topic.previous_changes['title'])
182
- end
183
-
184
- def test_previously_changed_dup
185
- topic = Topic.first
186
- topic.title = '<3<3<3'
187
- topic.save!
188
-
189
- t2 = topic.dup
190
-
191
- assert_equal(topic.previous_changes, t2.previous_changes)
192
-
193
- topic.title = "lolwut"
194
- topic.save!
195
-
196
- assert_not_equal(topic.previous_changes, t2.previous_changes)
197
- end
198
-
199
- def test_preserving_time_objects
200
- assert_kind_of(
201
- Time, Topic.find(1).bonus_time,
202
- "The bonus_time attribute should be of the Time class"
203
- )
204
-
205
- assert_kind_of(
206
- Time, Topic.find(1).written_on,
207
- "The written_on attribute should be of the Time class"
208
- )
209
-
210
- # For adapters which support microsecond resolution.
211
- if current_adapter?(:PostgreSQLAdapter, :SQLite3Adapter) || mysql_56?
212
- assert_equal 11, Topic.find(1).written_on.sec
213
- assert_equal 223300, Topic.find(1).written_on.usec
214
- assert_equal 9900, Topic.find(2).written_on.usec
215
- assert_equal 129346, Topic.find(3).written_on.usec
216
- end
217
- end
218
-
219
- def test_preserving_time_objects_with_local_time_conversion_to_default_timezone_utc
220
- with_env_tz 'America/New_York' do
221
- with_timezone_config default: :utc do
222
- time = Time.local(2000)
223
- topic = Topic.create('written_on' => time)
224
- saved_time = Topic.find(topic.id).reload.written_on
225
- assert_equal time, saved_time
226
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "EST"], time.to_a
227
- assert_equal [0, 0, 5, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
228
- end
229
- end
230
- end
231
-
232
- def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_utc
233
- with_env_tz 'America/New_York' do
234
- with_timezone_config default: :utc do
235
- Time.use_zone 'Central Time (US & Canada)' do
236
- time = Time.zone.local(2000)
237
- topic = Topic.create('written_on' => time)
238
- saved_time = Topic.find(topic.id).reload.written_on
239
- assert_equal time, saved_time
240
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
241
- assert_equal [0, 0, 6, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
242
- end
243
- end
244
- end
245
- end
246
-
247
- def test_preserving_time_objects_with_utc_time_conversion_to_default_timezone_local
248
- with_env_tz 'America/New_York' do
249
- with_timezone_config default: :local do
250
- time = Time.utc(2000)
251
- topic = Topic.create('written_on' => time)
252
- saved_time = Topic.find(topic.id).reload.written_on
253
- assert_equal time, saved_time
254
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], time.to_a
255
- assert_equal [0, 0, 19, 31, 12, 1999, 5, 365, false, "EST"], saved_time.to_a
256
- end
257
- end
258
- end
259
-
260
- def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_local
261
- with_env_tz 'America/New_York' do
262
- with_timezone_config default: :local do
263
- Time.use_zone 'Central Time (US & Canada)' do
264
- time = Time.zone.local(2000)
265
- topic = Topic.create('written_on' => time)
266
- saved_time = Topic.find(topic.id).reload.written_on
267
- assert_equal time, saved_time
268
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
269
- assert_equal [0, 0, 1, 1, 1, 2000, 6, 1, false, "EST"], saved_time.to_a
270
- end
271
- end
272
- end
273
- end
274
-
275
- def test_custom_mutator
276
- topic = Topic.find(1)
277
- # This mutator is protected in the class definition
278
- topic.send(:approved=, true)
279
- assert topic.instance_variable_get("@custom_approved")
280
- end
281
-
282
- def test_initialize_with_attributes
283
- topic = Topic.new({
284
- "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23"
285
- })
286
-
287
- assert_equal("initialized from attributes", topic.title)
288
- end
289
-
290
- def test_initialize_with_invalid_attribute
291
- Topic.new({ "title" => "test",
292
- "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
293
- rescue ActiveRecord::MultiparameterAssignmentErrors => ex
294
- assert_equal(1, ex.errors.size)
295
- assert_equal("last_read", ex.errors[0].attribute)
296
- end
297
-
298
- def test_create_after_initialize_without_block
299
- cb = CustomBulb.create(:name => 'Dude')
300
- assert_equal('Dude', cb.name)
301
- assert_equal(true, cb.frickinawesome)
302
- end
303
-
304
- def test_create_after_initialize_with_block
305
- cb = CustomBulb.create {|c| c.name = 'Dude' }
306
- assert_equal('Dude', cb.name)
307
- assert_equal(true, cb.frickinawesome)
308
- end
309
-
310
- def test_create_after_initialize_with_array_param
311
- cbs = CustomBulb.create([{ name: 'Dude' }, { name: 'Bob' }])
312
- assert_equal 'Dude', cbs[0].name
313
- assert_equal 'Bob', cbs[1].name
314
- assert cbs[0].frickinawesome
315
- assert !cbs[1].frickinawesome
316
- end
317
-
318
- def test_load
319
- topics = Topic.all.merge!(:order => 'id').to_a
320
- assert_equal(5, topics.size)
321
- assert_equal(topics(:first).title, topics.first.title)
322
- end
323
-
324
- def test_load_with_condition
325
- topics = Topic.all.merge!(:where => "author_name = 'Mary'").to_a
326
-
327
- assert_equal(1, topics.size)
328
- assert_equal(topics(:second).title, topics.first.title)
329
- end
330
-
331
- GUESSED_CLASSES = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]
332
-
333
- def test_table_name_guesses
334
- assert_equal "topics", Topic.table_name
335
-
336
- assert_equal "categories", Category.table_name
337
- assert_equal "smarts", Smarts.table_name
338
- assert_equal "credit_cards", CreditCard.table_name
339
- assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
340
- assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
341
- assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
342
- assert_equal "categories", CreditCard::Brand.table_name
343
- assert_equal "master_credit_cards", MasterCreditCard.table_name
344
- ensure
345
- GUESSED_CLASSES.each(&:reset_table_name)
346
- end
347
-
348
- def test_singular_table_name_guesses
349
- ActiveRecord::Base.pluralize_table_names = false
350
- GUESSED_CLASSES.each(&:reset_table_name)
351
-
352
- assert_equal "category", Category.table_name
353
- assert_equal "smarts", Smarts.table_name
354
- assert_equal "credit_card", CreditCard.table_name
355
- assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
356
- assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
357
- assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
358
- assert_equal "category", CreditCard::Brand.table_name
359
- assert_equal "master_credit_card", MasterCreditCard.table_name
360
- ensure
361
- ActiveRecord::Base.pluralize_table_names = true
362
- GUESSED_CLASSES.each(&:reset_table_name)
363
- end
364
-
365
- def test_table_name_guesses_with_prefixes_and_suffixes
366
- ActiveRecord::Base.table_name_prefix = "test_"
367
- Category.reset_table_name
368
- assert_equal "test_categories", Category.table_name
369
- ActiveRecord::Base.table_name_suffix = "_test"
370
- Category.reset_table_name
371
- assert_equal "test_categories_test", Category.table_name
372
- ActiveRecord::Base.table_name_prefix = ""
373
- Category.reset_table_name
374
- assert_equal "categories_test", Category.table_name
375
- ActiveRecord::Base.table_name_suffix = ""
376
- Category.reset_table_name
377
- assert_equal "categories", Category.table_name
378
- ensure
379
- ActiveRecord::Base.table_name_prefix = ""
380
- ActiveRecord::Base.table_name_suffix = ""
381
- GUESSED_CLASSES.each(&:reset_table_name)
382
- end
383
-
384
- def test_singular_table_name_guesses_with_prefixes_and_suffixes
385
- ActiveRecord::Base.pluralize_table_names = false
386
-
387
- ActiveRecord::Base.table_name_prefix = "test_"
388
- Category.reset_table_name
389
- assert_equal "test_category", Category.table_name
390
- ActiveRecord::Base.table_name_suffix = "_test"
391
- Category.reset_table_name
392
- assert_equal "test_category_test", Category.table_name
393
- ActiveRecord::Base.table_name_prefix = ""
394
- Category.reset_table_name
395
- assert_equal "category_test", Category.table_name
396
- ActiveRecord::Base.table_name_suffix = ""
397
- Category.reset_table_name
398
- assert_equal "category", Category.table_name
399
- ensure
400
- ActiveRecord::Base.pluralize_table_names = true
401
- ActiveRecord::Base.table_name_prefix = ""
402
- ActiveRecord::Base.table_name_suffix = ""
403
- GUESSED_CLASSES.each(&:reset_table_name)
404
- end
405
-
406
- def test_table_name_guesses_with_inherited_prefixes_and_suffixes
407
- GUESSED_CLASSES.each(&:reset_table_name)
408
-
409
- CreditCard.table_name_prefix = "test_"
410
- CreditCard.reset_table_name
411
- Category.reset_table_name
412
- assert_equal "test_credit_cards", CreditCard.table_name
413
- assert_equal "categories", Category.table_name
414
- CreditCard.table_name_suffix = "_test"
415
- CreditCard.reset_table_name
416
- Category.reset_table_name
417
- assert_equal "test_credit_cards_test", CreditCard.table_name
418
- assert_equal "categories", Category.table_name
419
- CreditCard.table_name_prefix = ""
420
- CreditCard.reset_table_name
421
- Category.reset_table_name
422
- assert_equal "credit_cards_test", CreditCard.table_name
423
- assert_equal "categories", Category.table_name
424
- CreditCard.table_name_suffix = ""
425
- CreditCard.reset_table_name
426
- Category.reset_table_name
427
- assert_equal "credit_cards", CreditCard.table_name
428
- assert_equal "categories", Category.table_name
429
- ensure
430
- CreditCard.table_name_prefix = ""
431
- CreditCard.table_name_suffix = ""
432
- GUESSED_CLASSES.each(&:reset_table_name)
433
- end
434
-
435
- def test_singular_table_name_guesses_for_individual_table
436
- Post.pluralize_table_names = false
437
- Post.reset_table_name
438
- assert_equal "post", Post.table_name
439
- assert_equal "categories", Category.table_name
440
- ensure
441
- Post.pluralize_table_names = true
442
- Post.reset_table_name
443
- end
444
-
445
- if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
446
- def test_update_all_with_order_and_limit
447
- assert_equal 1, Topic.limit(1).order('id DESC').update_all(:content => 'bulk updated!')
448
- end
449
- end
450
-
451
- def test_null_fields
452
- assert_nil Topic.find(1).parent_id
453
- assert_nil Topic.create("title" => "Hey you").parent_id
454
- end
455
-
456
- def test_default_values
457
- topic = Topic.new
458
- assert topic.approved?
459
- assert_nil topic.written_on
460
- assert_nil topic.bonus_time
461
- assert_nil topic.last_read
462
-
463
- topic.save
464
-
465
- topic = Topic.find(topic.id)
466
- assert topic.approved?
467
- assert_nil topic.last_read
468
-
469
- # Oracle has some funky default handling, so it requires a bit of
470
- # extra testing. See ticket #2788.
471
- if current_adapter?(:OracleAdapter)
472
- test = TestOracleDefault.new
473
- assert_equal "X", test.test_char
474
- assert_equal "hello", test.test_string
475
- assert_equal 3, test.test_int
476
- end
477
- end
478
-
479
- # Oracle does not have a TIME datatype.
480
- unless current_adapter?(:OracleAdapter)
481
- def test_utc_as_time_zone
482
- with_timezone_config default: :utc do
483
- attributes = { "bonus_time" => "5:42:00AM" }
484
- topic = Topic.find(1)
485
- topic.attributes = attributes
486
- assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
487
- end
488
- end
489
-
490
- def test_utc_as_time_zone_and_new
491
- with_timezone_config default: :utc do
492
- attributes = { "bonus_time(1i)"=>"2000",
493
- "bonus_time(2i)"=>"1",
494
- "bonus_time(3i)"=>"1",
495
- "bonus_time(4i)"=>"10",
496
- "bonus_time(5i)"=>"35",
497
- "bonus_time(6i)"=>"50" }
498
- topic = Topic.new(attributes)
499
- assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
500
- end
501
- end
502
- end
503
-
504
- def test_default_values_on_empty_strings
505
- topic = Topic.new
506
- topic.approved = nil
507
- topic.last_read = nil
508
-
509
- topic.save
510
-
511
- topic = Topic.find(topic.id)
512
- assert_nil topic.last_read
513
-
514
- assert_nil topic.approved
515
- end
516
-
517
- def test_equality
518
- assert_equal Topic.find(1), Topic.find(2).topic
519
- end
520
-
521
- def test_find_by_slug
522
- assert_equal Topic.find('1-meowmeow'), Topic.find(1)
523
- end
524
-
525
- def test_find_by_slug_with_array
526
- assert_equal Topic.find(['1-meowmeow', '2-hello']), Topic.find([1, 2])
527
- end
528
-
529
- def test_find_by_slug_with_range
530
- assert_equal Topic.where(id: '1-meowmeow'..'2-hello'), Topic.where(id: 1..2)
531
- end
532
-
533
- def test_equality_of_new_records
534
- assert_not_equal Topic.new, Topic.new
535
- assert_equal false, Topic.new == Topic.new
536
- end
537
-
538
- def test_equality_of_destroyed_records
539
- topic_1 = Topic.new(:title => 'test_1')
540
- topic_1.save
541
- topic_2 = Topic.find(topic_1.id)
542
- topic_1.destroy
543
- assert_equal topic_1, topic_2
544
- assert_equal topic_2, topic_1
545
- end
546
-
547
- def test_equality_with_blank_ids
548
- one = Subscriber.new(:id => '')
549
- two = Subscriber.new(:id => '')
550
- assert_equal one, two
551
- end
552
-
553
- def test_equality_of_relation_and_collection_proxy
554
- car = Car.create!
555
- car.bulbs.build
556
- car.save
557
-
558
- assert car.bulbs == Bulb.where(car_id: car.id), 'CollectionProxy should be comparable with Relation'
559
- assert Bulb.where(car_id: car.id) == car.bulbs, 'Relation should be comparable with CollectionProxy'
560
- end
561
-
562
- def test_equality_of_relation_and_array
563
- car = Car.create!
564
- car.bulbs.build
565
- car.save
566
-
567
- assert Bulb.where(car_id: car.id) == car.bulbs.to_a, 'Relation should be comparable with Array'
568
- end
569
-
570
- def test_equality_of_relation_and_association_relation
571
- car = Car.create!
572
- car.bulbs.build
573
- car.save
574
-
575
- assert_equal Bulb.where(car_id: car.id), car.bulbs.includes(:car), 'Relation should be comparable with AssociationRelation'
576
- assert_equal car.bulbs.includes(:car), Bulb.where(car_id: car.id), 'AssociationRelation should be comparable with Relation'
577
- end
578
-
579
- def test_equality_of_collection_proxy_and_association_relation
580
- car = Car.create!
581
- car.bulbs.build
582
- car.save
583
-
584
- assert_equal car.bulbs, car.bulbs.includes(:car), 'CollectionProxy should be comparable with AssociationRelation'
585
- assert_equal car.bulbs.includes(:car), car.bulbs, 'AssociationRelation should be comparable with CollectionProxy'
586
- end
587
-
588
- def test_hashing
589
- assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
590
- end
591
-
592
- def test_successful_comparison_of_like_class_records
593
- topic_1 = Topic.create!
594
- topic_2 = Topic.create!
595
-
596
- assert_equal [topic_2, topic_1].sort, [topic_1, topic_2]
597
- end
598
-
599
- def test_failed_comparison_of_unlike_class_records
600
- assert_raises ArgumentError do
601
- [ topics(:first), posts(:welcome) ].sort
602
- end
603
- end
604
-
605
- def test_create_without_prepared_statement
606
- topic = Topic.connection.unprepared_statement do
607
- Topic.create(:title => 'foo')
608
- end
609
-
610
- assert_equal topic, Topic.find(topic.id)
611
- end
612
-
613
- def test_destroy_without_prepared_statement
614
- topic = Topic.create(title: 'foo')
615
- Topic.connection.unprepared_statement do
616
- Topic.find(topic.id).destroy
617
- end
618
-
619
- assert_equal nil, Topic.find_by_id(topic.id)
620
- end
621
-
622
- def test_comparison_with_different_objects
623
- topic = Topic.create
624
- category = Category.create(:name => "comparison")
625
- assert_nil topic <=> category
626
- end
627
-
628
- def test_comparison_with_different_objects_in_array
629
- topic = Topic.create
630
- assert_raises(ArgumentError) do
631
- [1, topic].sort
632
- end
633
- end
634
-
635
- def test_readonly_attributes
636
- assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes
637
-
638
- post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable")
639
- post.reload
640
- assert_equal "cannot change this", post.title
641
-
642
- post.update(title: "try to change", body: "changed")
643
- post.reload
644
- assert_equal "cannot change this", post.title
645
- assert_equal "changed", post.body
646
- end
647
-
648
- def test_unicode_column_name
649
- Weird.reset_column_information
650
- weird = Weird.create(:なまえ => 'たこ焼き仮面')
651
- assert_equal 'たこ焼き仮面', weird.なまえ
652
- end
653
-
654
- unless current_adapter?(:PostgreSQLAdapter)
655
- def test_respect_internal_encoding
656
- old_default_internal = Encoding.default_internal
657
- silence_warnings { Encoding.default_internal = "EUC-JP" }
658
-
659
- Weird.reset_column_information
660
-
661
- assert_equal ["EUC-JP"], Weird.columns.map {|c| c.name.encoding.name }.uniq
662
- ensure
663
- silence_warnings { Encoding.default_internal = old_default_internal }
664
- Weird.reset_column_information
665
- end
666
- end
667
-
668
- def test_non_valid_identifier_column_name
669
- weird = Weird.create('a$b' => 'value')
670
- weird.reload
671
- assert_equal 'value', weird.send('a$b')
672
- assert_equal 'value', weird.read_attribute('a$b')
673
-
674
- weird.update_columns('a$b' => 'value2')
675
- weird.reload
676
- assert_equal 'value2', weird.send('a$b')
677
- assert_equal 'value2', weird.read_attribute('a$b')
678
- end
679
-
680
- def test_group_weirds_by_from
681
- Weird.create('a$b' => 'value', :from => 'aaron')
682
- count = Weird.group(Weird.arel_table[:from]).count
683
- assert_equal 1, count['aaron']
684
- end
685
-
686
- def test_attributes_on_dummy_time
687
- # Oracle does not have a TIME datatype.
688
- return true if current_adapter?(:OracleAdapter)
689
-
690
- with_timezone_config default: :local do
691
- attributes = {
692
- "bonus_time" => "5:42:00AM"
693
- }
694
- topic = Topic.find(1)
695
- topic.attributes = attributes
696
- assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
697
- end
698
- end
699
-
700
- def test_attributes_on_dummy_time_with_invalid_time
701
- # Oracle does not have a TIME datatype.
702
- return true if current_adapter?(:OracleAdapter)
703
-
704
- attributes = {
705
- "bonus_time" => "not a time"
706
- }
707
- topic = Topic.find(1)
708
- topic.attributes = attributes
709
- assert_nil topic.bonus_time
710
- end
711
-
712
- def test_boolean
713
- b_nil = Boolean.create({ "value" => nil })
714
- nil_id = b_nil.id
715
- b_false = Boolean.create({ "value" => false })
716
- false_id = b_false.id
717
- b_true = Boolean.create({ "value" => true })
718
- true_id = b_true.id
719
-
720
- b_nil = Boolean.find(nil_id)
721
- assert_nil b_nil.value
722
- b_false = Boolean.find(false_id)
723
- assert !b_false.value?
724
- b_true = Boolean.find(true_id)
725
- assert b_true.value?
726
- end
727
-
728
- def test_boolean_without_questionmark
729
- b_true = Boolean.create({ "value" => true })
730
- true_id = b_true.id
731
-
732
- subclass = Class.new(Boolean).find true_id
733
- superclass = Boolean.find true_id
734
-
735
- assert_equal superclass.read_attribute(:has_fun), subclass.read_attribute(:has_fun)
736
- end
737
-
738
- def test_boolean_cast_from_string
739
- b_blank = Boolean.create({ "value" => "" })
740
- blank_id = b_blank.id
741
- b_false = Boolean.create({ "value" => "0" })
742
- false_id = b_false.id
743
- b_true = Boolean.create({ "value" => "1" })
744
- true_id = b_true.id
745
-
746
- b_blank = Boolean.find(blank_id)
747
- assert_nil b_blank.value
748
- b_false = Boolean.find(false_id)
749
- assert !b_false.value?
750
- b_true = Boolean.find(true_id)
751
- assert b_true.value?
752
- end
753
-
754
- def test_new_record_returns_boolean
755
- assert_equal false, Topic.new.persisted?
756
- assert_equal true, Topic.find(1).persisted?
757
- end
758
-
759
- def test_dup
760
- topic = Topic.find(1)
761
- duped_topic = nil
762
- assert_nothing_raised { duped_topic = topic.dup }
763
- assert_equal topic.title, duped_topic.title
764
- assert !duped_topic.persisted?
765
-
766
- # test if the attributes have been duped
767
- topic.title = "a"
768
- duped_topic.title = "b"
769
- assert_equal "a", topic.title
770
- assert_equal "b", duped_topic.title
771
-
772
- # test if the attribute values have been duped
773
- duped_topic = topic.dup
774
- duped_topic.title.replace "c"
775
- assert_equal "a", topic.title
776
-
777
- # test if attributes set as part of after_initialize are duped correctly
778
- assert_equal topic.author_email_address, duped_topic.author_email_address
779
-
780
- # test if saved clone object differs from original
781
- duped_topic.save
782
- assert duped_topic.persisted?
783
- assert_not_equal duped_topic.id, topic.id
784
-
785
- duped_topic.reload
786
- assert_equal("c", duped_topic.title)
787
- end
788
-
789
- DeveloperSalary = Struct.new(:amount)
790
- def test_dup_with_aggregate_of_same_name_as_attribute
791
- developer_with_aggregate = Class.new(ActiveRecord::Base) do
792
- self.table_name = 'developers'
793
- composed_of :salary, :class_name => 'BasicsTest::DeveloperSalary', :mapping => [%w(salary amount)]
794
- end
795
-
796
- dev = developer_with_aggregate.find(1)
797
- assert_kind_of DeveloperSalary, dev.salary
798
-
799
- dup = nil
800
- assert_nothing_raised { dup = dev.dup }
801
- assert_kind_of DeveloperSalary, dup.salary
802
- assert_equal dev.salary.amount, dup.salary.amount
803
- assert !dup.persisted?
804
-
805
- # test if the attributes have been dupd
806
- original_amount = dup.salary.amount
807
- dev.salary.amount = 1
808
- assert_equal original_amount, dup.salary.amount
809
-
810
- assert dup.save
811
- assert dup.persisted?
812
- assert_not_equal dup.id, dev.id
813
- end
814
-
815
- def test_dup_does_not_copy_associations
816
- author = authors(:david)
817
- assert_not_equal [], author.posts
818
- author.send(:clear_association_cache)
819
-
820
- author_dup = author.dup
821
- assert_equal [], author_dup.posts
822
- end
823
-
824
- def test_clone_preserves_subtype
825
- clone = nil
826
- assert_nothing_raised { clone = Company.find(3).clone }
827
- assert_kind_of Client, clone
828
- end
829
-
830
- def test_clone_of_new_object_with_defaults
831
- developer = Developer.new
832
- assert !developer.name_changed?
833
- assert !developer.salary_changed?
834
-
835
- cloned_developer = developer.clone
836
- assert !cloned_developer.name_changed?
837
- assert !cloned_developer.salary_changed?
838
- end
839
-
840
- def test_clone_of_new_object_marks_attributes_as_dirty
841
- developer = Developer.new :name => 'Bjorn', :salary => 100000
842
- assert developer.name_changed?
843
- assert developer.salary_changed?
844
-
845
- cloned_developer = developer.clone
846
- assert cloned_developer.name_changed?
847
- assert cloned_developer.salary_changed?
848
- end
849
-
850
- def test_clone_of_new_object_marks_as_dirty_only_changed_attributes
851
- developer = Developer.new :name => 'Bjorn'
852
- assert developer.name_changed? # obviously
853
- assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed
854
-
855
- cloned_developer = developer.clone
856
- assert cloned_developer.name_changed?
857
- assert !cloned_developer.salary_changed? # ... and cloned instance should behave same
858
- end
859
-
860
- def test_dup_of_saved_object_marks_attributes_as_dirty
861
- developer = Developer.create! :name => 'Bjorn', :salary => 100000
862
- assert !developer.name_changed?
863
- assert !developer.salary_changed?
864
-
865
- cloned_developer = developer.dup
866
- assert cloned_developer.name_changed? # both attributes differ from defaults
867
- assert cloned_developer.salary_changed?
868
- end
869
-
870
- def test_dup_of_saved_object_marks_as_dirty_only_changed_attributes
871
- developer = Developer.create! :name => 'Bjorn'
872
- assert !developer.name_changed? # both attributes of saved object should be treated as not changed
873
- assert !developer.salary_changed?
874
-
875
- cloned_developer = developer.dup
876
- assert cloned_developer.name_changed? # ... but on cloned object should be
877
- assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be treated as not changed on cloned instance
878
- end
879
-
880
- def test_bignum
881
- company = Company.find(1)
882
- company.rating = 2147483647
883
- company.save
884
- company = Company.find(1)
885
- assert_equal 2147483647, company.rating
886
- end
887
-
888
- # TODO: extend defaults tests to other databases!
889
- if current_adapter?(:PostgreSQLAdapter)
890
- def test_default
891
- with_timezone_config default: :local do
892
- default = Default.new
893
-
894
- # fixed dates / times
895
- assert_equal Date.new(2004, 1, 1), default.fixed_date
896
- assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
897
-
898
- # char types
899
- assert_equal 'Y', default.char1
900
- assert_equal 'a varchar field', default.char2
901
- assert_equal 'a text field', default.char3
902
- end
903
- end
904
-
905
- class Geometric < ActiveRecord::Base; end
906
- def test_geometric_content
907
-
908
- # accepted format notes:
909
- # ()'s aren't required
910
- # values can be a mix of float or integer
911
-
912
- g = Geometric.new(
913
- :a_point => '(5.0, 6.1)',
914
- #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
915
- :a_line_segment => '(2.0, 3), (5.5, 7.0)',
916
- :a_box => '2.0, 3, 5.5, 7.0',
917
- :a_path => '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]', # [ ] is an open path
918
- :a_polygon => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))',
919
- :a_circle => '<(5.3, 10.4), 2>'
920
- )
921
-
922
- assert g.save
923
-
924
- # Reload and check that we have all the geometric attributes.
925
- h = Geometric.find(g.id)
926
-
927
- assert_equal [5.0, 6.1], h.a_point
928
- assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
929
- assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
930
- assert_equal '[(2,3),(5.5,7),(8.5,11)]', h.a_path
931
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
932
- assert_equal '<(5.3,10.4),2>', h.a_circle
933
-
934
- # use a geometric function to test for an open path
935
- objs = Geometric.find_by_sql ["select isopen(a_path) from geometrics where id = ?", g.id]
936
-
937
- assert_equal true, objs[0].isopen
938
-
939
- # test alternate formats when defining the geometric types
940
-
941
- g = Geometric.new(
942
- :a_point => '5.0, 6.1',
943
- #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
944
- :a_line_segment => '((2.0, 3), (5.5, 7.0))',
945
- :a_box => '(2.0, 3), (5.5, 7.0)',
946
- :a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', # ( ) is a closed path
947
- :a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
948
- :a_circle => '((5.3, 10.4), 2)'
949
- )
950
-
951
- assert g.save
952
-
953
- # Reload and check that we have all the geometric attributes.
954
- h = Geometric.find(g.id)
955
-
956
- assert_equal [5.0, 6.1], h.a_point
957
- assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
958
- assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
959
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
960
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
961
- assert_equal '<(5.3,10.4),2>', h.a_circle
962
-
963
- # use a geometric function to test for an closed path
964
- objs = Geometric.find_by_sql ["select isclosed(a_path) from geometrics where id = ?", g.id]
965
-
966
- assert_equal true, objs[0].isclosed
967
-
968
- # test native ruby formats when defining the geometric types
969
- g = Geometric.new(
970
- :a_point => [5.0, 6.1],
971
- #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
972
- :a_line_segment => '((2.0, 3), (5.5, 7.0))',
973
- :a_box => '(2.0, 3), (5.5, 7.0)',
974
- :a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', # ( ) is a closed path
975
- :a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
976
- :a_circle => '((5.3, 10.4), 2)'
977
- )
978
-
979
- assert g.save
980
-
981
- # Reload and check that we have all the geometric attributes.
982
- h = Geometric.find(g.id)
983
-
984
- assert_equal [5.0, 6.1], h.a_point
985
- assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
986
- assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
987
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
988
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
989
- assert_equal '<(5.3,10.4),2>', h.a_circle
990
- end
991
- end
992
-
993
- class NumericData < ActiveRecord::Base
994
- self.table_name = 'numeric_data'
995
-
996
- attribute :my_house_population, Type::Integer.new
997
- attribute :atoms_in_universe, Type::Integer.new
998
- end
999
-
1000
- def test_big_decimal_conditions
1001
- m = NumericData.new(
1002
- :bank_balance => 1586.43,
1003
- :big_bank_balance => BigDecimal("1000234000567.95"),
1004
- :world_population => 6000000000,
1005
- :my_house_population => 3
1006
- )
1007
- assert m.save
1008
- assert_equal 0, NumericData.where("bank_balance > ?", 2000.0).count
1009
- end
1010
-
1011
- def test_numeric_fields
1012
- m = NumericData.new(
1013
- :bank_balance => 1586.43,
1014
- :big_bank_balance => BigDecimal("1000234000567.95"),
1015
- :world_population => 6000000000,
1016
- :my_house_population => 3
1017
- )
1018
- assert m.save
1019
-
1020
- m1 = NumericData.find(m.id)
1021
- assert_not_nil m1
1022
-
1023
- # As with migration_test.rb, we should make world_population >= 2**62
1024
- # to cover 64-bit platforms and test it is a Bignum, but the main thing
1025
- # is that it's an Integer.
1026
- unless current_adapter?(:IBM_DBAdapter)
1027
- assert_kind_of Integer, m1.world_population
1028
- else
1029
- assert_kind_of BigDecimal, m1.world_population
1030
- end
1031
- assert_equal 6000000000, m1.world_population
1032
-
1033
- unless current_adapter?(:IBM_DBAdapter)
1034
- assert_kind_of Fixnum, m1.my_house_population
1035
- else
1036
- assert_kind_of BigDecimal, m1.my_house_population
1037
- end
1038
- assert_equal 3, m1.my_house_population
1039
-
1040
- assert_kind_of BigDecimal, m1.bank_balance
1041
- assert_equal BigDecimal("1586.43"), m1.bank_balance
1042
-
1043
- assert_kind_of BigDecimal, m1.big_bank_balance
1044
- assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
1045
- end
1046
-
1047
- def test_auto_id
1048
- auto = AutoId.new
1049
- auto.save
1050
- assert(auto.id > 0)
1051
- end
1052
-
1053
- def test_sql_injection_via_find
1054
- assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
1055
- Topic.find("123456 OR id > 0")
1056
- end
1057
- end
1058
-
1059
- def test_column_name_properly_quoted
1060
- col_record = ColumnName.new
1061
- col_record.references = 40
1062
- assert col_record.save
1063
- col_record.references = 41
1064
- assert col_record.save
1065
- assert_not_nil c2 = ColumnName.find(col_record.id)
1066
- assert_equal(41, c2.references)
1067
- end
1068
-
1069
- def test_quoting_arrays
1070
- replies = Reply.all.merge!(:where => [ "id IN (?)", topics(:first).replies.collect(&:id) ]).to_a
1071
- assert_equal topics(:first).replies.size, replies.size
1072
-
1073
- replies = Reply.all.merge!(:where => [ "id IN (?)", [] ]).to_a
1074
- assert_equal 0, replies.size
1075
- end
1076
-
1077
- def test_quote
1078
- author_name = "\\ \001 ' \n \\n \""
1079
- topic = Topic.create('author_name' => author_name)
1080
- assert_equal author_name, Topic.find(topic.id).author_name
1081
- end
1082
-
1083
- def test_toggle_attribute
1084
- assert !topics(:first).approved?
1085
- topics(:first).toggle!(:approved)
1086
- assert topics(:first).approved?
1087
- topic = topics(:first)
1088
- topic.toggle(:approved)
1089
- assert !topic.approved?
1090
- topic.reload
1091
- assert topic.approved?
1092
- end
1093
-
1094
- def test_reload
1095
- t1 = Topic.find(1)
1096
- t2 = Topic.find(1)
1097
- t1.title = "something else"
1098
- t1.save
1099
- t2.reload
1100
- assert_equal t1.title, t2.title
1101
- end
1102
-
1103
- def test_reload_with_exclusive_scope
1104
- dev = DeveloperCalledDavid.first
1105
- dev.update!(name: "NotDavid" )
1106
- assert_equal dev, dev.reload
1107
- end
1108
-
1109
- def test_switching_between_table_name
1110
- assert_difference("GoodJoke.count") do
1111
- Joke.table_name = "cold_jokes"
1112
- Joke.create
1113
-
1114
- Joke.table_name = "funny_jokes"
1115
- Joke.create
1116
- end
1117
- end
1118
-
1119
- def test_clear_cash_when_setting_table_name
1120
- Joke.table_name = "cold_jokes"
1121
- before_columns = Joke.columns
1122
- before_seq = Joke.sequence_name
1123
-
1124
- Joke.table_name = "funny_jokes"
1125
- after_columns = Joke.columns
1126
- after_seq = Joke.sequence_name
1127
-
1128
- assert_not_equal before_columns, after_columns
1129
- assert_not_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
1130
- end
1131
-
1132
- def test_dont_clear_sequence_name_when_setting_explicitly
1133
- Joke.sequence_name = "black_jokes_seq"
1134
- Joke.table_name = "cold_jokes"
1135
- before_seq = Joke.sequence_name
1136
-
1137
- Joke.table_name = "funny_jokes"
1138
- after_seq = Joke.sequence_name
1139
-
1140
- assert_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
1141
- ensure
1142
- Joke.reset_sequence_name
1143
- end
1144
-
1145
- def test_dont_clear_inheritance_column_when_setting_explicitly
1146
- Joke.inheritance_column = "my_type"
1147
- before_inherit = Joke.inheritance_column
1148
-
1149
- Joke.reset_column_information
1150
- after_inherit = Joke.inheritance_column
1151
-
1152
- assert_equal before_inherit, after_inherit unless before_inherit.blank? && after_inherit.blank?
1153
- end
1154
-
1155
- def test_set_table_name_symbol_converted_to_string
1156
- Joke.table_name = :cold_jokes
1157
- assert_equal 'cold_jokes', Joke.table_name
1158
- end
1159
-
1160
- def test_quoted_table_name_after_set_table_name
1161
- klass = Class.new(ActiveRecord::Base)
1162
-
1163
- klass.table_name = "foo"
1164
- assert_equal "foo", klass.table_name
1165
- assert_equal klass.connection.quote_table_name("foo"), klass.quoted_table_name
1166
-
1167
- klass.table_name = "bar"
1168
- assert_equal "bar", klass.table_name
1169
- assert_equal klass.connection.quote_table_name("bar"), klass.quoted_table_name
1170
- end
1171
-
1172
- def test_set_table_name_with_inheritance
1173
- k = Class.new( ActiveRecord::Base )
1174
- def k.name; "Foo"; end
1175
- def k.table_name; super + "ks"; end
1176
- assert_equal "foosks", k.table_name
1177
- end
1178
-
1179
- def test_sequence_name_with_abstract_class
1180
- ak = Class.new(ActiveRecord::Base)
1181
- ak.abstract_class = true
1182
- k = Class.new(ak)
1183
- k.table_name = "projects"
1184
- orig_name = k.sequence_name
1185
- skip "sequences not supported by db" unless orig_name
1186
- assert_equal k.reset_sequence_name, orig_name
1187
- end
1188
-
1189
- def test_count_with_join
1190
- res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
1191
-
1192
- res2 = Post.where("posts.#{QUOTED_TYPE} = 'Post'").joins("LEFT JOIN comments ON posts.id=comments.post_id").count
1193
- assert_equal res, res2
1194
-
1195
- res3 = nil
1196
- assert_nothing_raised do
1197
- res3 = Post.where("posts.#{QUOTED_TYPE} = 'Post'").joins("LEFT JOIN comments ON posts.id=comments.post_id").count
1198
- end
1199
- assert_equal res, res3
1200
-
1201
- res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
1202
- res5 = nil
1203
- assert_nothing_raised do
1204
- res5 = Post.where("p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id").joins("p, comments co").select("p.id").count
1205
- end
1206
-
1207
- assert_equal res4, res5
1208
-
1209
- res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
1210
- res7 = nil
1211
- assert_nothing_raised do
1212
- res7 = Post.where("p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id").joins("p, comments co").select("p.id").distinct.count
1213
- end
1214
- assert_equal res6, res7
1215
- end
1216
-
1217
- def test_no_limit_offset
1218
- assert_nothing_raised do
1219
- Developer.all.merge!(:offset => 2).to_a
1220
- end
1221
- end
1222
-
1223
- def test_find_last
1224
- last = Developer.last
1225
- assert_equal last, Developer.all.merge!(:order => 'id desc').first
1226
- end
1227
-
1228
- def test_last
1229
- assert_equal Developer.all.merge!(:order => 'id desc').first, Developer.last
1230
- end
1231
-
1232
- def test_all
1233
- developers = Developer.all
1234
- assert_kind_of ActiveRecord::Relation, developers
1235
- assert_equal Developer.all, developers
1236
- end
1237
-
1238
- def test_all_with_conditions
1239
- assert_equal Developer.all.merge!(:order => 'id desc').to_a, Developer.order('id desc').to_a
1240
- end
1241
-
1242
- def test_find_ordered_last
1243
- last = Developer.all.merge!(:order => 'developers.salary ASC').last
1244
- assert_equal last, Developer.all.merge!(:order => 'developers.salary ASC').to_a.last
1245
- end
1246
-
1247
- def test_find_reverse_ordered_last
1248
- last = Developer.all.merge!(:order => 'developers.salary DESC').last
1249
- assert_equal last, Developer.all.merge!(:order => 'developers.salary DESC').to_a.last
1250
- end
1251
-
1252
- def test_find_multiple_ordered_last
1253
- last = Developer.all.merge!(:order => 'developers.name, developers.salary DESC').last
1254
- assert_equal last, Developer.all.merge!(:order => 'developers.name, developers.salary DESC').to_a.last
1255
- end
1256
-
1257
- def test_find_keeps_multiple_order_values
1258
- combined = Developer.all.merge!(:order => 'developers.name, developers.salary').to_a
1259
- assert_equal combined, Developer.all.merge!(:order => ['developers.name', 'developers.salary']).to_a
1260
- end
1261
-
1262
- def test_find_keeps_multiple_group_values
1263
- combined = Developer.all.merge!(:group => 'developers.name, developers.salary, developers.id, developers.created_at, developers.updated_at, developers.created_on, developers.updated_on').to_a
1264
- assert_equal combined, Developer.all.merge!(:group => ['developers.name', 'developers.salary', 'developers.id', 'developers.created_at', 'developers.updated_at', 'developers.created_on', 'developers.updated_on']).to_a
1265
- end
1266
-
1267
- def test_find_symbol_ordered_last
1268
- last = Developer.all.merge!(:order => :salary).last
1269
- assert_equal last, Developer.all.merge!(:order => :salary).to_a.last
1270
- end
1271
-
1272
- def test_abstract_class
1273
- assert !ActiveRecord::Base.abstract_class?
1274
- assert LoosePerson.abstract_class?
1275
- assert !LooseDescendant.abstract_class?
1276
- end
1277
-
1278
- def test_abstract_class_table_name
1279
- assert_nil AbstractCompany.table_name
1280
- end
1281
-
1282
- def test_descends_from_active_record
1283
- assert !ActiveRecord::Base.descends_from_active_record?
1284
-
1285
- # Abstract subclass of AR::Base.
1286
- assert LoosePerson.descends_from_active_record?
1287
-
1288
- # Concrete subclass of an abstract class.
1289
- assert LooseDescendant.descends_from_active_record?
1290
-
1291
- # Concrete subclass of AR::Base.
1292
- assert TightPerson.descends_from_active_record?
1293
-
1294
- # Concrete subclass of a concrete class but has no type column.
1295
- assert TightDescendant.descends_from_active_record?
1296
-
1297
- # Concrete subclass of AR::Base.
1298
- assert Post.descends_from_active_record?
1299
-
1300
- # Abstract subclass of a concrete class which has a type column.
1301
- # This is pathological, as you'll never have Sub < Abstract < Concrete.
1302
- assert !StiPost.descends_from_active_record?
1303
-
1304
- # Concrete subclasses an abstract class which has a type column.
1305
- assert !SubStiPost.descends_from_active_record?
1306
- end
1307
-
1308
- def test_find_on_abstract_base_class_doesnt_use_type_condition
1309
- old_class = LooseDescendant
1310
- Object.send :remove_const, :LooseDescendant
1311
-
1312
- descendant = old_class.create! :first_name => 'bob'
1313
- assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
1314
- ensure
1315
- unless Object.const_defined?(:LooseDescendant)
1316
- Object.const_set :LooseDescendant, old_class
1317
- end
1318
- end
1319
-
1320
- def test_assert_queries
1321
- query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
1322
- assert_queries(2) { 2.times { query.call } }
1323
- assert_queries 1, &query
1324
- assert_no_queries { assert true }
1325
- end
1326
-
1327
- def test_benchmark_with_log_level
1328
- original_logger = ActiveRecord::Base.logger
1329
- log = StringIO.new
1330
- ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
1331
- ActiveRecord::Base.logger.level = Logger::WARN
1332
- ActiveRecord::Base.benchmark("Debug Topic Count", :level => :debug) { Topic.count }
1333
- ActiveRecord::Base.benchmark("Warn Topic Count", :level => :warn) { Topic.count }
1334
- ActiveRecord::Base.benchmark("Error Topic Count", :level => :error) { Topic.count }
1335
- assert_no_match(/Debug Topic Count/, log.string)
1336
- assert_match(/Warn Topic Count/, log.string)
1337
- assert_match(/Error Topic Count/, log.string)
1338
- ensure
1339
- ActiveRecord::Base.logger = original_logger
1340
- end
1341
-
1342
- def test_benchmark_with_use_silence
1343
- original_logger = ActiveRecord::Base.logger
1344
- log = StringIO.new
1345
- ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
1346
- ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" }
1347
- assert_match(/Quiet/, log.string)
1348
- ensure
1349
- ActiveRecord::Base.logger = original_logger
1350
- end
1351
-
1352
- def test_compute_type_success
1353
- assert_equal Author, ActiveRecord::Base.send(:compute_type, 'Author')
1354
- end
1355
-
1356
- def test_compute_type_nonexistent_constant
1357
- e = assert_raises NameError do
1358
- ActiveRecord::Base.send :compute_type, 'NonexistentModel'
1359
- end
1360
- assert_equal 'uninitialized constant ActiveRecord::Base::NonexistentModel', e.message
1361
- assert_equal 'ActiveRecord::Base::NonexistentModel', e.name
1362
- end
1363
-
1364
- def test_compute_type_no_method_error
1365
- ActiveSupport::Dependencies.stubs(:safe_constantize).raises(NoMethodError)
1366
- assert_raises NoMethodError do
1367
- ActiveRecord::Base.send :compute_type, 'InvalidModel'
1368
- end
1369
- end
1370
-
1371
- def test_compute_type_on_undefined_method
1372
- error = nil
1373
- begin
1374
- Class.new(Author) do
1375
- alias_method :foo, :bar
1376
- end
1377
- rescue => e
1378
- error = e
1379
- end
1380
-
1381
- ActiveSupport::Dependencies.stubs(:safe_constantize).raises(e)
1382
-
1383
- exception = assert_raises NameError do
1384
- ActiveRecord::Base.send :compute_type, 'InvalidModel'
1385
- end
1386
- assert_equal error.message, exception.message
1387
- end
1388
-
1389
- def test_compute_type_argument_error
1390
- ActiveSupport::Dependencies.stubs(:safe_constantize).raises(ArgumentError)
1391
- assert_raises ArgumentError do
1392
- ActiveRecord::Base.send :compute_type, 'InvalidModel'
1393
- end
1394
- end
1395
-
1396
- def test_clear_cache!
1397
- # preheat cache
1398
- c1 = Post.connection.schema_cache.columns('posts')
1399
- ActiveRecord::Base.clear_cache!
1400
- c2 = Post.connection.schema_cache.columns('posts')
1401
- c1.each_with_index do |v, i|
1402
- assert_not_same v, c2[i]
1403
- end
1404
- assert_equal c1, c2
1405
- end
1406
-
1407
- def test_current_scope_is_reset
1408
- Object.const_set :UnloadablePost, Class.new(ActiveRecord::Base)
1409
- UnloadablePost.send(:current_scope=, UnloadablePost.all)
1410
-
1411
- UnloadablePost.unloadable
1412
- assert_not_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, "UnloadablePost")
1413
- ActiveSupport::Dependencies.remove_unloadable_constants!
1414
- assert_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, "UnloadablePost")
1415
- ensure
1416
- Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
1417
- end
1418
-
1419
- def test_marshal_round_trip
1420
- expected = posts(:welcome)
1421
- marshalled = Marshal.dump(expected)
1422
- actual = Marshal.load(marshalled)
1423
-
1424
- assert_equal expected.attributes, actual.attributes
1425
- end
1426
-
1427
- def test_marshal_new_record_round_trip
1428
- marshalled = Marshal.dump(Post.new)
1429
- post = Marshal.load(marshalled)
1430
-
1431
- assert post.new_record?, "should be a new record"
1432
- end
1433
-
1434
- def test_marshalling_with_associations
1435
- post = Post.new
1436
- post.comments.build
1437
-
1438
- marshalled = Marshal.dump(post)
1439
- post = Marshal.load(marshalled)
1440
-
1441
- assert_equal 1, post.comments.length
1442
- end
1443
-
1444
- if Process.respond_to?(:fork) && !in_memory_db?
1445
- def test_marshal_between_processes
1446
- # Define a new model to ensure there are no caches
1447
- if self.class.const_defined?("Post", false)
1448
- flunk "there should be no post constant"
1449
- end
1450
-
1451
- self.class.const_set("Post", Class.new(ActiveRecord::Base) {
1452
- has_many :comments
1453
- })
1454
-
1455
- rd, wr = IO.pipe
1456
- rd.binmode
1457
- wr.binmode
1458
-
1459
- ActiveRecord::Base.connection_handler.clear_all_connections!
1460
-
1461
- fork do
1462
- rd.close
1463
- post = Post.new
1464
- post.comments.build
1465
- wr.write Marshal.dump(post)
1466
- wr.close
1467
- end
1468
-
1469
- wr.close
1470
- assert Marshal.load rd.read
1471
- rd.close
1472
- end
1473
- end
1474
-
1475
- def test_marshalling_new_record_round_trip_with_associations
1476
- post = Post.new
1477
- post.comments.build
1478
-
1479
- post = Marshal.load(Marshal.dump(post))
1480
-
1481
- assert post.new_record?, "should be a new record"
1482
- end
1483
-
1484
- def test_attribute_names
1485
- assert_equal ["id", "type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id", "description"],
1486
- Company.attribute_names
1487
- end
1488
-
1489
- def test_attribute_names_on_table_not_exists
1490
- assert_equal [], NonExistentTable.attribute_names
1491
- end
1492
-
1493
- def test_attribute_names_on_abstract_class
1494
- assert_equal [], AbstractCompany.attribute_names
1495
- end
1496
-
1497
- def test_touch_should_raise_error_on_a_new_object
1498
- company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals")
1499
- assert_raises(ActiveRecord::ActiveRecordError) do
1500
- company.touch :updated_at
1501
- end
1502
- end
1503
-
1504
- def test_uniq_delegates_to_scoped
1505
- scope = stub
1506
- Bird.stubs(:all).returns(mock(:uniq => scope))
1507
- assert_equal scope, Bird.uniq
1508
- end
1509
-
1510
- def test_distinct_delegates_to_scoped
1511
- scope = stub
1512
- Bird.stubs(:all).returns(mock(:distinct => scope))
1513
- assert_equal scope, Bird.distinct
1514
- end
1515
-
1516
- def test_table_name_with_2_abstract_subclasses
1517
- assert_equal "photos", Photo.table_name
1518
- end
1519
-
1520
- def test_column_types_typecast
1521
- topic = Topic.first
1522
- assert_not_equal 't.lo', topic.author_name
1523
-
1524
- attrs = topic.attributes.dup
1525
- attrs.delete 'id'
1526
-
1527
- typecast = Class.new(ActiveRecord::Type::Value) {
1528
- def type_cast value
1529
- "t.lo"
1530
- end
1531
- }
1532
-
1533
- types = { 'author_name' => typecast.new }
1534
- topic = Topic.instantiate(attrs, types)
1535
-
1536
- assert_equal 't.lo', topic.author_name
1537
- end
1538
-
1539
- def test_typecasting_aliases
1540
- assert_equal 10, Topic.select('10 as tenderlove').first.tenderlove
1541
- end
1542
-
1543
- def test_slice
1544
- company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals")
1545
- hash = company.slice(:name, :rating, "arbitrary_method")
1546
- assert_equal hash[:name], company.name
1547
- assert_equal hash['name'], company.name
1548
- assert_equal hash[:rating], company.rating
1549
- assert_equal hash['arbitrary_method'], company.arbitrary_method
1550
- assert_equal hash[:arbitrary_method], company.arbitrary_method
1551
- assert_nil hash[:firm_name]
1552
- assert_nil hash['firm_name']
1553
- end
1554
-
1555
- def test_default_values_are_deeply_dupped
1556
- company = Company.new
1557
- company.description << "foo"
1558
- assert_equal "", Company.new.description
1559
- end
1560
-
1561
- test "scoped can take a values hash" do
1562
- klass = Class.new(ActiveRecord::Base)
1563
- assert_equal ['foo'], klass.all.merge!(select: 'foo').select_values
1564
- end
1565
-
1566
- test "connection_handler can be overridden" do
1567
- klass = Class.new(ActiveRecord::Base)
1568
- orig_handler = klass.connection_handler
1569
- new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
1570
- thread_connection_handler = nil
1571
-
1572
- t = Thread.new do
1573
- klass.connection_handler = new_handler
1574
- thread_connection_handler = klass.connection_handler
1575
- end
1576
- t.join
1577
-
1578
- assert_equal klass.connection_handler, orig_handler
1579
- assert_equal thread_connection_handler, new_handler
1580
- end
1581
-
1582
- test "new threads get default the default connection handler" do
1583
- klass = Class.new(ActiveRecord::Base)
1584
- orig_handler = klass.connection_handler
1585
- handler = nil
1586
-
1587
- t = Thread.new do
1588
- handler = klass.connection_handler
1589
- end
1590
- t.join
1591
-
1592
- assert_equal handler, orig_handler
1593
- assert_equal klass.connection_handler, orig_handler
1594
- assert_equal klass.default_connection_handler, orig_handler
1595
- end
1596
-
1597
- test "changing a connection handler in a main thread does not poison the other threads" do
1598
- klass = Class.new(ActiveRecord::Base)
1599
- orig_handler = klass.connection_handler
1600
- new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
1601
- after_handler = nil
1602
- latch1 = ActiveSupport::Concurrency::Latch.new
1603
- latch2 = ActiveSupport::Concurrency::Latch.new
1604
-
1605
- t = Thread.new do
1606
- klass.connection_handler = new_handler
1607
- latch1.release
1608
- latch2.await
1609
- after_handler = klass.connection_handler
1610
- end
1611
-
1612
- latch1.await
1613
-
1614
- klass.connection_handler = orig_handler
1615
- latch2.release
1616
- t.join
1617
-
1618
- assert_equal after_handler, new_handler
1619
- assert_equal orig_handler, klass.connection_handler
1620
- end
1621
-
1622
- # Note: This is a performance optimization for Array#uniq and Hash#[] with
1623
- # AR::Base objects. If the future has made this irrelevant, feel free to
1624
- # delete this.
1625
- test "records without an id have unique hashes" do
1626
- assert_not_equal Post.new.hash, Post.new.hash
1627
- end
1628
-
1629
- test "resetting column information doesn't remove attribute methods" do
1630
- topic = topics(:first)
1631
-
1632
- assert_not topic.id_changed?
1633
-
1634
- Topic.reset_column_information
1635
-
1636
- assert_not topic.id_changed?
1637
- end
1638
- end
1
+ require "cases/helper"
2
+ require 'models/post'
3
+ require 'models/author'
4
+ require 'models/topic'
5
+ require 'models/reply'
6
+ require 'models/category'
7
+ require 'models/company'
8
+ require 'models/customer'
9
+ require 'models/developer'
10
+ require 'models/computer'
11
+ require 'models/project'
12
+ require 'models/default'
13
+ require 'models/auto_id'
14
+ require 'models/boolean'
15
+ require 'models/column_name'
16
+ require 'models/subscriber'
17
+ require 'models/keyboard'
18
+ require 'models/comment'
19
+ require 'models/minimalistic'
20
+ require 'models/warehouse_thing'
21
+ require 'models/parrot'
22
+ require 'models/person'
23
+ require 'models/edge'
24
+ require 'models/joke'
25
+ require 'models/bird'
26
+ require 'models/car'
27
+ require 'models/bulb'
28
+ require 'rexml/document'
29
+ require 'concurrent/atomic/count_down_latch'
30
+
31
+ class FirstAbstractClass < ActiveRecord::Base
32
+ self.abstract_class = true
33
+ end
34
+ class SecondAbstractClass < FirstAbstractClass
35
+ self.abstract_class = true
36
+ end
37
+ class Photo < SecondAbstractClass; end
38
+ class Category < ActiveRecord::Base; end
39
+ class Categorization < ActiveRecord::Base; end
40
+ class Smarts < ActiveRecord::Base; end
41
+ class CreditCard < ActiveRecord::Base
42
+ class PinNumber < ActiveRecord::Base
43
+ class CvvCode < ActiveRecord::Base; end
44
+ class SubCvvCode < CvvCode; end
45
+ end
46
+ class SubPinNumber < PinNumber; end
47
+ class Brand < Category; end
48
+ end
49
+ class MasterCreditCard < ActiveRecord::Base; end
50
+ class Post < ActiveRecord::Base; end
51
+ class Computer < ActiveRecord::Base; end
52
+ class NonExistentTable < ActiveRecord::Base; end
53
+ class TestOracleDefault < ActiveRecord::Base; end
54
+
55
+ class ReadonlyTitlePost < Post
56
+ attr_readonly :title
57
+ end
58
+
59
+ class Weird < ActiveRecord::Base; end
60
+
61
+ class Boolean < ActiveRecord::Base
62
+ def has_fun
63
+ super
64
+ end
65
+ end
66
+
67
+ class LintTest < ActiveRecord::TestCase
68
+ include ActiveModel::Lint::Tests
69
+
70
+ class LintModel < ActiveRecord::Base; end
71
+
72
+ def setup
73
+ @model = LintModel.new
74
+ end
75
+ end
76
+
77
+ class BasicsTest < ActiveRecord::TestCase
78
+ #fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse_things', :authors, :categorizations, :categories, :posts
79
+ fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse_things', :categorizations, :categories, :posts
80
+
81
+ def test_column_names_are_escaped
82
+ puts "In base_test test_column_names_are_escaped"
83
+ conn = ActiveRecord::Base.connection
84
+ classname = conn.class.name[/[^:]*$/]
85
+ badchar = {
86
+ 'SQLite3Adapter' => '"',
87
+ 'Mysql2Adapter' => '`',
88
+ 'PostgreSQLAdapter' => '"',
89
+ 'OracleAdapter' => '"',
90
+ 'IBM_DBAdapter' => '"',
91
+ 'FbAdapter' => '"'
92
+ }.fetch(classname) {
93
+ raise "need a bad char for #{classname}"
94
+ }
95
+
96
+ quoted = conn.quote_column_name "foo#{badchar}bar"
97
+ if current_adapter?(:OracleAdapter)
98
+ # Oracle does not allow double quotes in table and column names at all
99
+ # therefore quoting removes them
100
+ assert_equal("#{badchar}foobar#{badchar}", quoted)
101
+ elsif current_adapter?(:IBM_DBAdapter)
102
+ assert_equal("foo#{badchar}bar", quoted)
103
+ else
104
+ assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted)
105
+ end
106
+ end
107
+
108
+ def test_columns_should_obey_set_primary_key
109
+ puts "In base_test test_columns_should_obey_set_primary_key"
110
+ pk = Subscriber.columns_hash[Subscriber.primary_key]
111
+ assert_equal 'nick', pk.name, 'nick should be primary key'
112
+ end
113
+
114
+ def test_primary_key_with_no_id
115
+ puts "In base_test test_primary_key_with_no_id"
116
+ assert_nil Edge.primary_key
117
+ end
118
+
119
+ unless current_adapter?(:PostgreSQLAdapter, :OracleAdapter, :SQLServerAdapter, :IBM_DBAdapter, :FbAdapter)
120
+ def test_limit_with_comma
121
+ puts "In base_test test_limit_with_comma"
122
+ assert_deprecated do
123
+ assert Topic.limit("1,2").to_a
124
+ end
125
+ end
126
+ end
127
+
128
+ def test_many_mutations
129
+ puts "In base_test test_many_mutations"
130
+ car = Car.new name: "<3<3<3"
131
+ car.engines_count = 0
132
+ 20_000.times { car.engines_count += 1 }
133
+ assert car.save
134
+ end
135
+
136
+ def test_limit_without_comma
137
+ puts "In base_test test_limit_without_comma"
138
+ assert_equal 1, Topic.limit("1").to_a.length
139
+ assert_equal 1, Topic.limit(1).to_a.length
140
+ end
141
+
142
+ def test_limit_should_take_value_from_latest_limit
143
+ puts "In base_test test_limit_should_take_value_from_latest_limit"
144
+ assert_equal 1, Topic.limit(2).limit(1).to_a.length
145
+ end
146
+
147
+ def test_invalid_limit
148
+ puts "In base_test test_invalid_limit"
149
+ assert_raises(ArgumentError) do
150
+ Topic.limit("asdfadf").to_a
151
+ end
152
+ end
153
+
154
+ def test_limit_should_sanitize_sql_injection_for_limit_without_commas
155
+ puts "In base_test test_limit_should_sanitize_sql_injection_for_limit_without_commas"
156
+ assert_raises(ArgumentError) do
157
+ Topic.limit("1 select * from schema").to_a
158
+ end
159
+ end
160
+
161
+ def test_limit_should_sanitize_sql_injection_for_limit_with_commas
162
+ puts "In base_test test_limit_should_sanitize_sql_injection_for_limit_with_commas"
163
+ assert_deprecated do
164
+ assert_raises(ArgumentError) do
165
+ Topic.limit("1, 7 procedure help()").to_a
166
+ end
167
+ end
168
+ end
169
+
170
+ def test_select_symbol
171
+ puts "In base_test test_select_symbol"
172
+ topic_ids = Topic.select(:id).map(&:id).sort
173
+ assert_equal Topic.pluck(:id).sort, topic_ids
174
+ end
175
+
176
+ def test_table_exists
177
+ puts "In base_test test_table_exists"
178
+ assert !NonExistentTable.table_exists?
179
+ assert Topic.table_exists?
180
+ end
181
+
182
+ def test_preserving_date_objects
183
+ puts "In base_test test_preserving_date_objects"
184
+ # Oracle enhanced adapter allows to define Date attributes in model class (see topic.rb)
185
+ assert_kind_of(
186
+ Date, Topic.find(1).last_read,
187
+ "The last_read attribute should be of the Date class"
188
+ )
189
+ end
190
+
191
+ def test_previously_changed
192
+ puts "In base_test test_previously_changed"
193
+ topic = Topic.first
194
+ topic.title = '<3<3<3'
195
+ assert_equal({}, topic.previous_changes)
196
+
197
+ topic.save!
198
+ expected = ["The First Topic", "<3<3<3"]
199
+ assert_equal(expected, topic.previous_changes['title'])
200
+ end
201
+
202
+ def test_previously_changed_dup
203
+ puts "In base_test test_previously_changed_dup"
204
+ topic = Topic.first
205
+ topic.title = '<3<3<3'
206
+ topic.save!
207
+
208
+ t2 = topic.dup
209
+
210
+ assert_equal(topic.previous_changes, t2.previous_changes)
211
+
212
+ topic.title = "lolwut"
213
+ topic.save!
214
+
215
+ assert_not_equal(topic.previous_changes, t2.previous_changes)
216
+ end
217
+
218
+ def test_preserving_time_objects
219
+ puts "In base_test test_preserving_time_objects"
220
+ assert_kind_of(
221
+ Time, Topic.find(1).bonus_time,
222
+ "The bonus_time attribute should be of the Time class"
223
+ )
224
+
225
+ assert_kind_of(
226
+ Time, Topic.find(1).written_on,
227
+ "The written_on attribute should be of the Time class"
228
+ )
229
+
230
+ # For adapters which support microsecond resolution.
231
+ if subsecond_precision_supported?
232
+ assert_equal 11, Topic.find(1).written_on.sec
233
+ assert_equal 223300, Topic.find(1).written_on.usec
234
+ assert_equal 9900, Topic.find(2).written_on.usec
235
+ assert_equal 129346, Topic.find(3).written_on.usec
236
+ end
237
+ end
238
+
239
+ def test_preserving_time_objects_with_local_time_conversion_to_default_timezone_utc
240
+ puts "In base_test test_preserving_time_objects_with_local_time_conversion_to_default_timezone_utc"
241
+ with_env_tz eastern_time_zone do
242
+ with_timezone_config default: :utc do
243
+ time = Time.local(2000)
244
+ topic = Topic.create('written_on' => time)
245
+ saved_time = Topic.find(topic.id).reload.written_on
246
+ assert_equal time, saved_time
247
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "EST"], time.to_a
248
+ assert_equal [0, 0, 5, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
249
+ end
250
+ end
251
+ end
252
+
253
+ def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_utc
254
+ puts "In base_test test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_utc"
255
+ with_env_tz eastern_time_zone do
256
+ with_timezone_config default: :utc do
257
+ Time.use_zone 'Central Time (US & Canada)' do
258
+ time = Time.zone.local(2000)
259
+ topic = Topic.create('written_on' => time)
260
+ saved_time = Topic.find(topic.id).reload.written_on
261
+ assert_equal time, saved_time
262
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
263
+ assert_equal [0, 0, 6, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
264
+ end
265
+ end
266
+ end
267
+ end
268
+
269
+ def test_preserving_time_objects_with_utc_time_conversion_to_default_timezone_local
270
+ puts "In base_test test_preserving_time_objects_with_utc_time_conversion_to_default_timezone_local"
271
+ with_env_tz eastern_time_zone do
272
+ with_timezone_config default: :local do
273
+ time = Time.utc(2000)
274
+ topic = Topic.create('written_on' => time)
275
+ saved_time = Topic.find(topic.id).reload.written_on
276
+ assert_equal time, saved_time
277
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], time.to_a
278
+ assert_equal [0, 0, 19, 31, 12, 1999, 5, 365, false, "EST"], saved_time.to_a
279
+ end
280
+ end
281
+ end
282
+
283
+ def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_local
284
+ puts "In base_test test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_local"
285
+ with_env_tz eastern_time_zone do
286
+ with_timezone_config default: :local do
287
+ Time.use_zone 'Central Time (US & Canada)' do
288
+ time = Time.zone.local(2000)
289
+ topic = Topic.create('written_on' => time)
290
+ saved_time = Topic.find(topic.id).reload.written_on
291
+ assert_equal time, saved_time
292
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
293
+ assert_equal [0, 0, 1, 1, 1, 2000, 6, 1, false, "EST"], saved_time.to_a
294
+ end
295
+ end
296
+ end
297
+ end
298
+
299
+ def eastern_time_zone
300
+ if Gem.win_platform?
301
+ "EST5EDT"
302
+ else
303
+ "America/New_York"
304
+ end
305
+ end
306
+
307
+ def test_custom_mutator
308
+ puts "In base_test test_custom_mutator"
309
+ topic = Topic.find(1)
310
+ # This mutator is protected in the class definition
311
+ topic.send(:approved=, true)
312
+ assert topic.instance_variable_get("@custom_approved")
313
+ end
314
+
315
+ def test_initialize_with_attributes
316
+ puts "In base_test test_initialize_with_attributes"
317
+ topic = Topic.new({
318
+ "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23"
319
+ })
320
+
321
+ assert_equal("initialized from attributes", topic.title)
322
+ end
323
+
324
+ def test_initialize_with_invalid_attribute
325
+ puts "In base_test test_initialize_with_invalid_attribute"
326
+ Topic.new({ "title" => "test",
327
+ "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
328
+ rescue ActiveRecord::MultiparameterAssignmentErrors => ex
329
+ assert_equal(1, ex.errors.size)
330
+ assert_equal("last_read", ex.errors[0].attribute)
331
+ end
332
+
333
+ def test_create_after_initialize_without_block
334
+ puts "In base_test test_create_after_initialize_without_block"
335
+ cb = CustomBulb.create(:name => 'Dude')
336
+ assert_equal('Dude', cb.name)
337
+ assert_equal(true, cb.frickinawesome)
338
+ end
339
+
340
+ def test_create_after_initialize_with_block
341
+ puts "In base_test test_create_after_initialize_with_block"
342
+ cb = CustomBulb.create {|c| c.name = 'Dude' }
343
+ assert_equal('Dude', cb.name)
344
+ assert_equal(true, cb.frickinawesome)
345
+ end
346
+
347
+ def test_create_after_initialize_with_array_param
348
+ puts "In base_test test_create_after_initialize_with_array_param"
349
+ cbs = CustomBulb.create([{ name: 'Dude' }, { name: 'Bob' }])
350
+ assert_equal 'Dude', cbs[0].name
351
+ assert_equal 'Bob', cbs[1].name
352
+ assert cbs[0].frickinawesome
353
+ assert !cbs[1].frickinawesome
354
+ end
355
+
356
+ def test_load
357
+ puts "In base_test test_load"
358
+ topics = Topic.all.merge!(:order => 'id').to_a
359
+ assert_equal(5, topics.size)
360
+ assert_equal(topics(:first).title, topics.first.title)
361
+ end
362
+
363
+ def test_load_with_condition
364
+ puts "In base_test test_load_with_condition"
365
+ topics = Topic.all.merge!(:where => "author_name = 'Mary'").to_a
366
+
367
+ assert_equal(1, topics.size)
368
+ assert_equal(topics(:second).title, topics.first.title)
369
+ end
370
+
371
+ GUESSED_CLASSES = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]
372
+
373
+ def test_table_name_guesses
374
+ puts "In base_test test_table_name_guesses"
375
+ assert_equal "topics", Topic.table_name
376
+
377
+ assert_equal "categories", Category.table_name
378
+ assert_equal "smarts", Smarts.table_name
379
+ assert_equal "credit_cards", CreditCard.table_name
380
+ assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
381
+ assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
382
+ assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
383
+ assert_equal "categories", CreditCard::Brand.table_name
384
+ assert_equal "master_credit_cards", MasterCreditCard.table_name
385
+ ensure
386
+ GUESSED_CLASSES.each(&:reset_table_name)
387
+ end
388
+
389
+ def test_singular_table_name_guesses
390
+ puts "In base_test test_singular_table_name_guesses"
391
+ ActiveRecord::Base.pluralize_table_names = false
392
+ GUESSED_CLASSES.each(&:reset_table_name)
393
+
394
+ assert_equal "category", Category.table_name
395
+ assert_equal "smarts", Smarts.table_name
396
+ assert_equal "credit_card", CreditCard.table_name
397
+ assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
398
+ assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
399
+ assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
400
+ assert_equal "category", CreditCard::Brand.table_name
401
+ assert_equal "master_credit_card", MasterCreditCard.table_name
402
+ ensure
403
+ ActiveRecord::Base.pluralize_table_names = true
404
+ GUESSED_CLASSES.each(&:reset_table_name)
405
+ end
406
+
407
+ def test_table_name_guesses_with_prefixes_and_suffixes
408
+ puts "In base_test test_table_name_guesses_with_prefixes_and_suffixes"
409
+ ActiveRecord::Base.table_name_prefix = "test_"
410
+ Category.reset_table_name
411
+ assert_equal "test_categories", Category.table_name
412
+ ActiveRecord::Base.table_name_suffix = "_test"
413
+ Category.reset_table_name
414
+ assert_equal "test_categories_test", Category.table_name
415
+ ActiveRecord::Base.table_name_prefix = ""
416
+ Category.reset_table_name
417
+ assert_equal "categories_test", Category.table_name
418
+ ActiveRecord::Base.table_name_suffix = ""
419
+ Category.reset_table_name
420
+ assert_equal "categories", Category.table_name
421
+ ensure
422
+ ActiveRecord::Base.table_name_prefix = ""
423
+ ActiveRecord::Base.table_name_suffix = ""
424
+ GUESSED_CLASSES.each(&:reset_table_name)
425
+ end
426
+
427
+ def test_singular_table_name_guesses_with_prefixes_and_suffixes
428
+ puts "In base_test test_singular_table_name_guesses_with_prefixes_and_suffixes"
429
+ ActiveRecord::Base.pluralize_table_names = false
430
+
431
+ ActiveRecord::Base.table_name_prefix = "test_"
432
+ Category.reset_table_name
433
+ assert_equal "test_category", Category.table_name
434
+ ActiveRecord::Base.table_name_suffix = "_test"
435
+ Category.reset_table_name
436
+ assert_equal "test_category_test", Category.table_name
437
+ ActiveRecord::Base.table_name_prefix = ""
438
+ Category.reset_table_name
439
+ assert_equal "category_test", Category.table_name
440
+ ActiveRecord::Base.table_name_suffix = ""
441
+ Category.reset_table_name
442
+ assert_equal "category", Category.table_name
443
+ ensure
444
+ ActiveRecord::Base.pluralize_table_names = true
445
+ ActiveRecord::Base.table_name_prefix = ""
446
+ ActiveRecord::Base.table_name_suffix = ""
447
+ GUESSED_CLASSES.each(&:reset_table_name)
448
+ end
449
+
450
+ def test_table_name_guesses_with_inherited_prefixes_and_suffixes
451
+ puts "In base_test test_table_name_guesses_with_inherited_prefixes_and_suffixes"
452
+ GUESSED_CLASSES.each(&:reset_table_name)
453
+
454
+ CreditCard.table_name_prefix = "test_"
455
+ CreditCard.reset_table_name
456
+ Category.reset_table_name
457
+ assert_equal "test_credit_cards", CreditCard.table_name
458
+ assert_equal "categories", Category.table_name
459
+ CreditCard.table_name_suffix = "_test"
460
+ CreditCard.reset_table_name
461
+ Category.reset_table_name
462
+ assert_equal "test_credit_cards_test", CreditCard.table_name
463
+ assert_equal "categories", Category.table_name
464
+ CreditCard.table_name_prefix = ""
465
+ CreditCard.reset_table_name
466
+ Category.reset_table_name
467
+ assert_equal "credit_cards_test", CreditCard.table_name
468
+ assert_equal "categories", Category.table_name
469
+ CreditCard.table_name_suffix = ""
470
+ CreditCard.reset_table_name
471
+ Category.reset_table_name
472
+ assert_equal "credit_cards", CreditCard.table_name
473
+ assert_equal "categories", Category.table_name
474
+ ensure
475
+ CreditCard.table_name_prefix = ""
476
+ CreditCard.table_name_suffix = ""
477
+ GUESSED_CLASSES.each(&:reset_table_name)
478
+ end
479
+
480
+ def test_singular_table_name_guesses_for_individual_table
481
+ puts "In base_test test_singular_table_name_guesses_for_individual_table"
482
+ Post.pluralize_table_names = false
483
+ Post.reset_table_name
484
+ assert_equal "post", Post.table_name
485
+ assert_equal "categories", Category.table_name
486
+ ensure
487
+ Post.pluralize_table_names = true
488
+ Post.reset_table_name
489
+ end
490
+
491
+ if current_adapter?(:Mysql2Adapter)
492
+ puts "In base_test test_update_all_with_order_and_limit"
493
+ def test_update_all_with_order_and_limit
494
+ assert_equal 1, Topic.limit(1).order('id DESC').update_all(:content => 'bulk updated!')
495
+ end
496
+ end
497
+
498
+ def test_null_fields
499
+ puts "In base_test test_null_fields"
500
+ assert_nil Topic.find(1).parent_id
501
+ assert_nil Topic.create("title" => "Hey you").parent_id
502
+ end
503
+
504
+ def test_default_values
505
+ puts "In base_test test_default_values"
506
+ topic = Topic.new
507
+ assert topic.approved?
508
+ assert_nil topic.written_on
509
+ assert_nil topic.bonus_time
510
+ assert_nil topic.last_read
511
+
512
+ topic.save
513
+
514
+ topic = Topic.find(topic.id)
515
+ assert topic.approved?
516
+ assert_nil topic.last_read
517
+
518
+ # Oracle has some funky default handling, so it requires a bit of
519
+ # extra testing. See ticket #2788.
520
+ if current_adapter?(:OracleAdapter)
521
+ test = TestOracleDefault.new
522
+ assert_equal "X", test.test_char
523
+ assert_equal "hello", test.test_string
524
+ assert_equal 3, test.test_int
525
+ end
526
+ end
527
+
528
+ # Oracle does not have a TIME datatype.
529
+ unless current_adapter?(:OracleAdapter,:IBM_DBAdapter)
530
+ def test_utc_as_time_zone
531
+ puts "In base_test test_utc_as_time_zone"
532
+ with_timezone_config default: :utc do
533
+ attributes = { "bonus_time" => "5:42:00AM" }
534
+ topic = Topic.find(1)
535
+ topic.attributes = attributes
536
+ assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
537
+ end
538
+ end
539
+ end
540
+
541
+ def test_utc_as_time_zone_and_new
542
+ puts "In base_test test_utc_as_time_zone_and_new"
543
+ with_timezone_config default: :utc do
544
+ attributes = { "bonus_time(1i)"=>"2000",
545
+ "bonus_time(2i)"=>"1",
546
+ "bonus_time(3i)"=>"1",
547
+ "bonus_time(4i)"=>"10",
548
+ "bonus_time(5i)"=>"35",
549
+ "bonus_time(6i)"=>"50" }
550
+ topic = Topic.new(attributes)
551
+ assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
552
+ end
553
+ end
554
+ end
555
+
556
+ def test_default_values_on_empty_strings
557
+ puts "In base_test test_default_values_on_empty_strings"
558
+ topic = Topic.new
559
+ topic.approved = nil
560
+ topic.last_read = nil
561
+
562
+ topic.save
563
+
564
+ topic = Topic.find(topic.id)
565
+ assert_nil topic.last_read
566
+
567
+ assert_nil topic.approved
568
+ end
569
+
570
+ def test_equality
571
+ puts "In base_test test_equality"
572
+ assert_equal Topic.find(1), Topic.find(2).topic
573
+ end
574
+
575
+ def test_find_by_slug
576
+ puts "In base_test test_find_by_slug"
577
+ assert_equal Topic.find('1-meowmeow'), Topic.find(1)
578
+ end
579
+
580
+ def test_find_by_slug_with_array
581
+ puts "In base_test test_find_by_slug_with_array"
582
+ assert_equal Topic.find([1, 2]), Topic.find(['1-meowmeow', '2-hello'])
583
+ assert_equal 'The Second Topic of the day', Topic.find(['2-hello', '1-meowmeow']).first.title
584
+ end
585
+
586
+ def test_find_by_slug_with_range
587
+ puts "In base_test test_find_by_slug_with_range"
588
+ assert_equal Topic.where(id: '1-meowmeow'..'2-hello'), Topic.where(id: 1..2)
589
+ end
590
+
591
+ def test_equality_of_new_records
592
+ puts "In base_test test_equality_of_new_records"
593
+ assert_not_equal Topic.new, Topic.new
594
+ assert_equal false, Topic.new == Topic.new
595
+ end
596
+
597
+ def test_equality_of_destroyed_records
598
+ puts "In base_test test_equality_of_destroyed_records"
599
+ topic_1 = Topic.new(:title => 'test_1')
600
+ topic_1.save
601
+ topic_2 = Topic.find(topic_1.id)
602
+ topic_1.destroy
603
+ assert_equal topic_1, topic_2
604
+ assert_equal topic_2, topic_1
605
+ end
606
+
607
+ def test_equality_with_blank_ids
608
+ puts "In base_test test_equality_with_blank_ids"
609
+ one = Subscriber.new(:id => '')
610
+ two = Subscriber.new(:id => '')
611
+ assert_equal one, two
612
+ end
613
+
614
+ def test_equality_of_relation_and_collection_proxy
615
+ puts "In base_test test_equality_of_relation_and_collection_proxy"
616
+ car = Car.create!
617
+ car.bulbs.build
618
+ car.save
619
+
620
+ assert car.bulbs == Bulb.where(car_id: car.id), 'CollectionProxy should be comparable with Relation'
621
+ assert Bulb.where(car_id: car.id) == car.bulbs, 'Relation should be comparable with CollectionProxy'
622
+ end
623
+
624
+ def test_equality_of_relation_and_array
625
+ puts "In base_test test_equality_of_relation_and_array"
626
+ car = Car.create!
627
+ car.bulbs.build
628
+ car.save
629
+
630
+ assert Bulb.where(car_id: car.id) == car.bulbs.to_a, 'Relation should be comparable with Array'
631
+ end
632
+
633
+ def test_equality_of_relation_and_association_relation
634
+ puts "In base_test test_equality_of_relation_and_association_relation"
635
+ car = Car.create!
636
+ car.bulbs.build
637
+ car.save
638
+
639
+ assert_equal Bulb.where(car_id: car.id), car.bulbs.includes(:car), 'Relation should be comparable with AssociationRelation'
640
+ assert_equal car.bulbs.includes(:car), Bulb.where(car_id: car.id), 'AssociationRelation should be comparable with Relation'
641
+ end
642
+
643
+ def test_equality_of_collection_proxy_and_association_relation
644
+ puts "In base_test test_equality_of_collection_proxy_and_association_relation"
645
+ car = Car.create!
646
+ car.bulbs.build
647
+ car.save
648
+
649
+ assert_equal car.bulbs, car.bulbs.includes(:car), 'CollectionProxy should be comparable with AssociationRelation'
650
+ assert_equal car.bulbs.includes(:car), car.bulbs, 'AssociationRelation should be comparable with CollectionProxy'
651
+ end
652
+
653
+ def test_hashing
654
+ puts "In base_test test_hashing"
655
+ assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
656
+ end
657
+
658
+ def test_successful_comparison_of_like_class_records
659
+ puts "In base_test test_successful_comparison_of_like_class_records"
660
+ topic_1 = Topic.create!
661
+ topic_2 = Topic.create!
662
+
663
+ assert_equal [topic_2, topic_1].sort, [topic_1, topic_2]
664
+ end
665
+
666
+ def test_failed_comparison_of_unlike_class_records
667
+ puts "In base_test test_failed_comparison_of_unlike_class_records"
668
+ assert_raises ArgumentError do
669
+ [ topics(:first), posts(:welcome) ].sort
670
+ end
671
+ end
672
+
673
+ def test_create_without_prepared_statement
674
+ puts "In base_test test_create_without_prepared_statement"
675
+ topic = Topic.connection.unprepared_statement do
676
+ Topic.create(:title => 'foo')
677
+ end
678
+
679
+ assert_equal topic, Topic.find(topic.id)
680
+ end
681
+
682
+ def test_destroy_without_prepared_statement
683
+ puts "In base_test test_destroy_without_prepared_statement"
684
+ topic = Topic.create(title: 'foo')
685
+ Topic.connection.unprepared_statement do
686
+ Topic.find(topic.id).destroy
687
+ end
688
+
689
+ assert_equal nil, Topic.find_by_id(topic.id)
690
+ end
691
+
692
+ def test_comparison_with_different_objects
693
+ puts "In base_test test_comparison_with_different_objects"
694
+ topic = Topic.create
695
+ category = Category.create(:name => "comparison")
696
+ assert_nil topic <=> category
697
+ end
698
+
699
+ def test_comparison_with_different_objects_in_array
700
+ puts "In base_test test_comparison_with_different_objects_in_array"
701
+ topic = Topic.create
702
+ assert_raises(ArgumentError) do
703
+ [1, topic].sort
704
+ end
705
+ end
706
+
707
+ def test_readonly_attributes
708
+ puts "In base_test test_readonly_attributes"
709
+ assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes
710
+
711
+ post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable")
712
+ post.reload
713
+ assert_equal "cannot change this", post.title
714
+
715
+ post.update(title: "try to change", body: "changed")
716
+ post.reload
717
+ assert_equal "cannot change this", post.title
718
+ assert_equal "changed", post.body
719
+ end
720
+
721
+ def test_unicode_column_name
722
+ puts "In base_test test_unicode_column_name"
723
+ Weird.reset_column_information
724
+ weird = Weird.create(:なまえ => 'たこ焼き仮面')
725
+ assert_equal 'たこ焼き仮面', weird.なまえ
726
+ end
727
+
728
+ unless current_adapter?(:PostgreSQLAdapter)
729
+ def test_respect_internal_encoding
730
+ puts "In base_test test_respect_internal_encoding"
731
+ old_default_internal = Encoding.default_internal
732
+ silence_warnings { Encoding.default_internal = "EUC-JP" }
733
+
734
+ Weird.reset_column_information
735
+
736
+ assert_equal ["EUC-JP"], Weird.columns.map {|c| c.name.encoding.name }.uniq
737
+ ensure
738
+ silence_warnings { Encoding.default_internal = old_default_internal }
739
+ Weird.reset_column_information
740
+ end
741
+ end
742
+
743
+ def test_non_valid_identifier_column_name
744
+ puts "In base_test test_non_valid_identifier_column_name"
745
+ weird = Weird.create('a$b' => 'value')
746
+ weird.reload
747
+ assert_equal 'value', weird.send('a$b')
748
+ assert_equal 'value', weird.read_attribute('a$b')
749
+
750
+ weird.update_columns('a$b' => 'value2')
751
+ weird.reload
752
+ assert_equal 'value2', weird.send('a$b')
753
+ assert_equal 'value2', weird.read_attribute('a$b')
754
+ end
755
+
756
+ def test_group_weirds_by_from
757
+ puts "In base_test test_group_weirds_by_from"
758
+ Weird.create('a$b' => 'value', :from => 'aaron')
759
+ count = Weird.group(Weird.arel_table[:from]).count
760
+ assert_equal 1, count['aaron']
761
+ end
762
+
763
+ def test_attributes_on_dummy_time
764
+ puts "In base_test test_attributes_on_dummy_time"
765
+ # Oracle does not have a TIME datatype.
766
+ return true if current_adapter?(:OracleAdapter)
767
+
768
+ with_timezone_config default: :local do
769
+ attributes = {
770
+ "bonus_time" => "5:42:00AM"
771
+ }
772
+ topic = Topic.find(1)
773
+ topic.attributes = attributes
774
+ assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
775
+ end
776
+ end
777
+
778
+ def test_attributes_on_dummy_time_with_invalid_time
779
+ puts "In base_test test_attributes_on_dummy_time_with_invalid_time"
780
+ # Oracle does not have a TIME datatype.
781
+ return true if current_adapter?(:OracleAdapter)
782
+
783
+ attributes = {
784
+ "bonus_time" => "not a time"
785
+ }
786
+ topic = Topic.find(1)
787
+ topic.attributes = attributes
788
+ assert_nil topic.bonus_time
789
+ end
790
+
791
+ def test_boolean
792
+ puts "In base_test test_boolean"
793
+ b_nil = Boolean.create({ "value" => nil })
794
+ nil_id = b_nil.id
795
+ b_false = Boolean.create({ "value" => false })
796
+ false_id = b_false.id
797
+ b_true = Boolean.create({ "value" => true })
798
+ true_id = b_true.id
799
+
800
+ b_nil = Boolean.find(nil_id)
801
+ assert_nil b_nil.value
802
+ b_false = Boolean.find(false_id)
803
+ assert !b_false.value?
804
+ b_true = Boolean.find(true_id)
805
+ assert b_true.value?
806
+ end
807
+
808
+ def test_boolean_without_questionmark
809
+ puts "In base_test test_boolean_without_questionmark"
810
+ b_true = Boolean.create({ "value" => true })
811
+ true_id = b_true.id
812
+
813
+ subclass = Class.new(Boolean).find true_id
814
+ superclass = Boolean.find true_id
815
+
816
+ assert_equal superclass.read_attribute(:has_fun), subclass.read_attribute(:has_fun)
817
+ end
818
+
819
+ def test_boolean_cast_from_string
820
+ puts "In base_test test_boolean_cast_from_string"
821
+ b_blank = Boolean.create({ "value" => "" })
822
+ blank_id = b_blank.id
823
+ b_false = Boolean.create({ "value" => "0" })
824
+ false_id = b_false.id
825
+ b_true = Boolean.create({ "value" => "1" })
826
+ true_id = b_true.id
827
+
828
+ b_blank = Boolean.find(blank_id)
829
+ assert_nil b_blank.value
830
+ b_false = Boolean.find(false_id)
831
+ assert !b_false.value?
832
+ b_true = Boolean.find(true_id)
833
+ assert b_true.value?
834
+ end
835
+
836
+ def test_new_record_returns_boolean
837
+ puts "In base_test test_new_record_returns_boolean"
838
+ assert_equal false, Topic.new.persisted?
839
+ assert_equal true, Topic.find(1).persisted?
840
+ end
841
+
842
+ def test_dup
843
+ puts "In base_test test_dup"
844
+ topic = Topic.find(1)
845
+ duped_topic = nil
846
+ assert_nothing_raised { duped_topic = topic.dup }
847
+ assert_equal topic.title, duped_topic.title
848
+ assert !duped_topic.persisted?
849
+
850
+ # test if the attributes have been duped
851
+ topic.title = "a"
852
+ duped_topic.title = "b"
853
+ assert_equal "a", topic.title
854
+ assert_equal "b", duped_topic.title
855
+
856
+ # test if the attribute values have been duped
857
+ duped_topic = topic.dup
858
+ duped_topic.title.replace "c"
859
+ assert_equal "a", topic.title
860
+
861
+ # test if attributes set as part of after_initialize are duped correctly
862
+ assert_equal topic.author_email_address, duped_topic.author_email_address
863
+
864
+ # test if saved clone object differs from original
865
+ duped_topic.save
866
+ assert duped_topic.persisted?
867
+ assert_not_equal duped_topic.id, topic.id
868
+
869
+ duped_topic.reload
870
+ assert_equal("c", duped_topic.title)
871
+ end
872
+
873
+ DeveloperSalary = Struct.new(:amount)
874
+ def test_dup_with_aggregate_of_same_name_as_attribute
875
+ puts "In base_test test_dup_with_aggregate_of_same_name_as_attribute"
876
+ developer_with_aggregate = Class.new(ActiveRecord::Base) do
877
+ self.table_name = 'developers'
878
+ composed_of :salary, :class_name => 'BasicsTest::DeveloperSalary', :mapping => [%w(salary amount)]
879
+ end
880
+
881
+ dev = developer_with_aggregate.find(1)
882
+ assert_kind_of DeveloperSalary, dev.salary
883
+
884
+ dup = nil
885
+ assert_nothing_raised { dup = dev.dup }
886
+ assert_kind_of DeveloperSalary, dup.salary
887
+ assert_equal dev.salary.amount, dup.salary.amount
888
+ assert !dup.persisted?
889
+
890
+ # test if the attributes have been duped
891
+ original_amount = dup.salary.amount
892
+ dev.salary.amount = 1
893
+ assert_equal original_amount, dup.salary.amount
894
+
895
+ assert dup.save
896
+ assert dup.persisted?
897
+ assert_not_equal dup.id, dev.id
898
+ end
899
+
900
+ def test_dup_does_not_copy_associations
901
+ puts "In base_test test_dup_does_not_copy_associations"
902
+ author = authors(:david)
903
+ assert_not_equal [], author.posts
904
+
905
+ author_dup = author.dup
906
+ assert_equal [], author_dup.posts
907
+ end
908
+
909
+ def test_clone_preserves_subtype
910
+ puts "In base_test test_clone_preserves_subtype"
911
+ clone = nil
912
+ assert_nothing_raised { clone = Company.find(3).clone }
913
+ assert_kind_of Client, clone
914
+ end
915
+
916
+ def test_clone_of_new_object_with_defaults
917
+ puts "In base_test test_clone_of_new_object_with_defaults"
918
+ developer = Developer.new
919
+ assert !developer.name_changed?
920
+ assert !developer.salary_changed?
921
+
922
+ cloned_developer = developer.clone
923
+ assert !cloned_developer.name_changed?
924
+ assert !cloned_developer.salary_changed?
925
+ end
926
+
927
+ def test_clone_of_new_object_marks_attributes_as_dirty
928
+ puts "In base_test test_clone_of_new_object_marks_attributes_as_dirty"
929
+ developer = Developer.new :name => 'Bjorn', :salary => 100000
930
+ assert developer.name_changed?
931
+ assert developer.salary_changed?
932
+
933
+ cloned_developer = developer.clone
934
+ assert cloned_developer.name_changed?
935
+ assert cloned_developer.salary_changed?
936
+ end
937
+
938
+ def test_clone_of_new_object_marks_as_dirty_only_changed_attributes
939
+ puts "In base_test test_clone_of_new_object_marks_as_dirty_only_changed_attributes"
940
+ developer = Developer.new :name => 'Bjorn'
941
+ assert developer.name_changed? # obviously
942
+ assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed
943
+
944
+ cloned_developer = developer.clone
945
+ assert cloned_developer.name_changed?
946
+ assert !cloned_developer.salary_changed? # ... and cloned instance should behave same
947
+ end
948
+
949
+ def test_dup_of_saved_object_marks_attributes_as_dirty
950
+ puts "In base_test test_dup_of_saved_object_marks_attributes_as_dirty"
951
+ developer = Developer.create! :name => 'Bjorn', :salary => 100000
952
+ assert !developer.name_changed?
953
+ assert !developer.salary_changed?
954
+
955
+ cloned_developer = developer.dup
956
+ assert cloned_developer.name_changed? # both attributes differ from defaults
957
+ assert cloned_developer.salary_changed?
958
+ end
959
+
960
+ def test_dup_of_saved_object_marks_as_dirty_only_changed_attributes
961
+ puts "In base_test test_dup_of_saved_object_marks_as_dirty_only_changed_attributes"
962
+ developer = Developer.create! :name => 'Bjorn'
963
+ assert !developer.name_changed? # both attributes of saved object should be treated as not changed
964
+ assert !developer.salary_changed?
965
+
966
+ cloned_developer = developer.dup
967
+ assert cloned_developer.name_changed? # ... but on cloned object should be
968
+ assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be treated as not changed on cloned instance
969
+ end
970
+
971
+ def test_bignum
972
+ puts "In base_test test_bignum"
973
+ company = Company.find(1)
974
+ company.rating = 2147483647
975
+ company.save
976
+ company = Company.find(1)
977
+ assert_equal 2147483647, company.rating
978
+ end
979
+
980
+ # TODO: extend defaults tests to other databases!
981
+ if current_adapter?(:PostgreSQLAdapter)
982
+ def test_default
983
+ puts "In base_test test_default"
984
+ with_timezone_config default: :local do
985
+ default = Default.new
986
+
987
+ # fixed dates / times
988
+ assert_equal Date.new(2004, 1, 1), default.fixed_date
989
+ assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
990
+
991
+ # char types
992
+ assert_equal 'Y', default.char1
993
+ assert_equal 'a varchar field', default.char2
994
+ assert_equal 'a text field', default.char3
995
+ end
996
+ end
997
+ end
998
+
999
+ class NumericData < ActiveRecord::Base
1000
+ self.table_name = 'numeric_data'
1001
+
1002
+ attribute :my_house_population, :integer
1003
+ attribute :atoms_in_universe, :integer
1004
+ end
1005
+
1006
+ def test_big_decimal_conditions
1007
+ puts "In base_test test_big_decimal_conditions"
1008
+ m = NumericData.new(
1009
+ :bank_balance => 1586.43,
1010
+ :big_bank_balance => BigDecimal("1000234000567.95"),
1011
+ :world_population => 6000000000,
1012
+ :my_house_population => 3
1013
+ )
1014
+ assert m.save
1015
+ assert_equal 0, NumericData.where("bank_balance > ?", 2000.0).count
1016
+ end
1017
+
1018
+ def test_numeric_fields
1019
+ puts "In base_test test_numeric_fields"
1020
+ m = NumericData.new(
1021
+ :bank_balance => 1586.43,
1022
+ :big_bank_balance => BigDecimal("1000234000567.95"),
1023
+ :world_population => 6000000000,
1024
+ :my_house_population => 3
1025
+ )
1026
+ assert m.save
1027
+
1028
+ m1 = NumericData.find(m.id)
1029
+ assert_not_nil m1
1030
+
1031
+ # As with migration_test.rb, we should make world_population >= 2**62
1032
+ # to cover 64-bit platforms and test it is a Bignum, but the main thing
1033
+ # is that it's an Integer.
1034
+ unless current_adapter?(:IBM_DBAdapter)
1035
+ assert_kind_of Integer, m1.world_population
1036
+ else
1037
+ assert_equal 6000000000, m1.world_population
1038
+
1039
+ assert_kind_of Integer, m1.my_house_population
1040
+ assert_equal 3, m1.my_house_population
1041
+
1042
+ assert_kind_of BigDecimal, m1.bank_balance
1043
+ assert_equal BigDecimal("1586.43"), m1.bank_balance
1044
+
1045
+ assert_kind_of BigDecimal, m1.big_bank_balance
1046
+ assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
1047
+ end
1048
+
1049
+ def test_numeric_fields_with_scale
1050
+ puts "In base_test test_numeric_fields_with_scale"
1051
+ m = NumericData.new(
1052
+ :bank_balance => 1586.43122334,
1053
+ :big_bank_balance => BigDecimal("234000567.952344"),
1054
+ :world_population => 6000000000,
1055
+ :my_house_population => 3
1056
+ )
1057
+ assert m.save
1058
+
1059
+ m1 = NumericData.find(m.id)
1060
+ assert_not_nil m1
1061
+
1062
+ # As with migration_test.rb, we should make world_population >= 2**62
1063
+ # to cover 64-bit platforms and test it is a Bignum, but the main thing
1064
+ # is that it's an Integer.
1065
+ assert_kind_of Integer, m1.world_population
1066
+ assert_equal 6000000000, m1.world_population
1067
+
1068
+ assert_kind_of Integer, m1.my_house_population
1069
+ assert_equal 3, m1.my_house_population
1070
+
1071
+ assert_kind_of BigDecimal, m1.bank_balance
1072
+ assert_equal BigDecimal("1586.43"), m1.bank_balance
1073
+
1074
+ assert_kind_of BigDecimal, m1.big_bank_balance
1075
+ assert_equal BigDecimal("234000567.95"), m1.big_bank_balance
1076
+ end
1077
+
1078
+ def test_auto_id
1079
+ puts "In base_test test_auto_id"
1080
+ auto = AutoId.new
1081
+ auto.save
1082
+ assert(auto.id > 0)
1083
+ end
1084
+
1085
+ def test_sql_injection_via_find
1086
+ puts "In base_test test_sql_injection_via_find"
1087
+ assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
1088
+ Topic.find("123456 OR id > 0")
1089
+ end
1090
+ end
1091
+
1092
+ def test_column_name_properly_quoted
1093
+ puts "In base_test test_column_name_properly_quoted"
1094
+ col_record = ColumnName.new
1095
+ col_record.references = 40
1096
+ assert col_record.save
1097
+ col_record.references = 41
1098
+ assert col_record.save
1099
+ assert_not_nil c2 = ColumnName.find(col_record.id)
1100
+ assert_equal(41, c2.references)
1101
+ end
1102
+
1103
+ def test_quoting_arrays
1104
+ puts "In base_test test_quoting_arrays"
1105
+ replies = Reply.all.merge!(:where => [ "id IN (?)", topics(:first).replies.collect(&:id) ]).to_a
1106
+ assert_equal topics(:first).replies.size, replies.size
1107
+
1108
+ replies = Reply.all.merge!(:where => [ "id IN (?)", [] ]).to_a
1109
+ assert_equal 0, replies.size
1110
+ end
1111
+
1112
+ def test_quote
1113
+ puts "In base_test test_quote"
1114
+ author_name = "\\ \001 ' \n \\n \""
1115
+ topic = Topic.create('author_name' => author_name)
1116
+ assert_equal author_name, Topic.find(topic.id).author_name
1117
+ end
1118
+
1119
+ def test_toggle_attribute
1120
+ puts "In base_test test_toggle_attribute"
1121
+ assert !topics(:first).approved?
1122
+ topics(:first).toggle!(:approved)
1123
+ assert topics(:first).approved?
1124
+ topic = topics(:first)
1125
+ topic.toggle(:approved)
1126
+ assert !topic.approved?
1127
+ topic.reload
1128
+ assert topic.approved?
1129
+ end
1130
+
1131
+ def test_reload
1132
+ puts "In base_test test_reload"
1133
+ t1 = Topic.find(1)
1134
+ t2 = Topic.find(1)
1135
+ t1.title = "something else"
1136
+ t1.save
1137
+ t2.reload
1138
+ assert_equal t1.title, t2.title
1139
+ end
1140
+
1141
+ def test_reload_with_exclusive_scope
1142
+ puts "In base_test test_reload_with_exclusive_scope"
1143
+ dev = DeveloperCalledDavid.first
1144
+ dev.update!(name: "NotDavid" )
1145
+ assert_equal dev, dev.reload
1146
+ end
1147
+
1148
+ def test_switching_between_table_name
1149
+ puts "In base_test test_switching_between_table_name"
1150
+ k = Class.new(Joke)
1151
+
1152
+ assert_difference("GoodJoke.count") do
1153
+ k.table_name = "cold_jokes"
1154
+ k.create
1155
+
1156
+ k.table_name = "funny_jokes"
1157
+ k.create
1158
+ end
1159
+ end
1160
+
1161
+ def test_clear_cash_when_setting_table_name
1162
+ puts "In base_test test_clear_cash_when_setting_table_name"
1163
+ original_table_name = Joke.table_name
1164
+
1165
+ Joke.table_name = "funny_jokes"
1166
+ before_columns = Joke.columns
1167
+ before_seq = Joke.sequence_name
1168
+
1169
+ Joke.table_name = "cold_jokes"
1170
+ after_columns = Joke.columns
1171
+ after_seq = Joke.sequence_name
1172
+
1173
+ assert_not_equal before_columns, after_columns
1174
+ assert_not_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
1175
+ ensure
1176
+ Joke.table_name = original_table_name
1177
+ end
1178
+
1179
+ def test_dont_clear_sequence_name_when_setting_explicitly
1180
+ puts "In base_test test_dont_clear_sequence_name_when_setting_explicitly"
1181
+ k = Class.new(Joke)
1182
+ k.sequence_name = "black_jokes_seq"
1183
+ k.table_name = "cold_jokes"
1184
+ before_seq = k.sequence_name
1185
+
1186
+ k.table_name = "funny_jokes"
1187
+ after_seq = k.sequence_name
1188
+
1189
+ assert_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
1190
+ end
1191
+
1192
+ def test_dont_clear_inheritance_column_when_setting_explicitly
1193
+ puts "In base_test test_dont_clear_inheritance_column_when_setting_explicitly"
1194
+ k = Class.new(Joke)
1195
+ k.inheritance_column = "my_type"
1196
+ before_inherit = k.inheritance_column
1197
+
1198
+ k.reset_column_information
1199
+ after_inherit = k.inheritance_column
1200
+
1201
+ assert_equal before_inherit, after_inherit unless before_inherit.blank? && after_inherit.blank?
1202
+ end
1203
+
1204
+ def test_set_table_name_symbol_converted_to_string
1205
+ puts "In base_test test_set_table_name_symbol_converted_to_string"
1206
+ k = Class.new(Joke)
1207
+ k.table_name = :cold_jokes
1208
+ assert_equal 'cold_jokes', k.table_name
1209
+ end
1210
+
1211
+ def test_quoted_table_name_after_set_table_name
1212
+ puts "In base_test test_quoted_table_name_after_set_table_name"
1213
+ klass = Class.new(ActiveRecord::Base)
1214
+
1215
+ klass.table_name = "foo"
1216
+ assert_equal "foo", klass.table_name
1217
+ assert_equal klass.connection.quote_table_name("foo"), klass.quoted_table_name
1218
+
1219
+ klass.table_name = "bar"
1220
+ assert_equal "bar", klass.table_name
1221
+ assert_equal klass.connection.quote_table_name("bar"), klass.quoted_table_name
1222
+ end
1223
+
1224
+ def test_set_table_name_with_inheritance
1225
+ puts "In base_test test_set_table_name_with_inheritance"
1226
+ k = Class.new( ActiveRecord::Base )
1227
+ def k.name; "Foo"; end
1228
+ def k.table_name; super + "ks"; end
1229
+ assert_equal "foosks", k.table_name
1230
+ end
1231
+
1232
+ def test_sequence_name_with_abstract_class
1233
+ puts "In base_test test_sequence_name_with_abstract_class"
1234
+ ak = Class.new(ActiveRecord::Base)
1235
+ ak.abstract_class = true
1236
+ k = Class.new(ak)
1237
+ k.table_name = "projects"
1238
+ orig_name = k.sequence_name
1239
+ skip "sequences not supported by db" unless orig_name
1240
+ assert_equal k.reset_sequence_name, orig_name
1241
+ end
1242
+
1243
+ def test_count_with_join
1244
+ puts "In base_test test_count_with_join"
1245
+ res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
1246
+
1247
+ res2 = Post.where("posts.#{QUOTED_TYPE} = 'Post'").joins("LEFT JOIN comments ON posts.id=comments.post_id").count
1248
+ assert_equal res, res2
1249
+
1250
+ res3 = nil
1251
+ assert_nothing_raised do
1252
+ res3 = Post.where("posts.#{QUOTED_TYPE} = 'Post'").joins("LEFT JOIN comments ON posts.id=comments.post_id").count
1253
+ end
1254
+ assert_equal res, res3
1255
+
1256
+ res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
1257
+ res5 = nil
1258
+ assert_nothing_raised do
1259
+ res5 = Post.where("p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id").joins("p, comments co").select("p.id").count
1260
+ end
1261
+
1262
+ assert_equal res4, res5
1263
+
1264
+ res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
1265
+ res7 = nil
1266
+ assert_nothing_raised do
1267
+ res7 = Post.where("p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id").joins("p, comments co").select("p.id").distinct.count
1268
+ end
1269
+ assert_equal res6, res7
1270
+ end
1271
+
1272
+ def test_no_limit_offset
1273
+ puts "In base_test test_no_limit_offset"
1274
+ assert_nothing_raised do
1275
+ Developer.all.merge!(:offset => 2).to_a
1276
+ end
1277
+ end
1278
+
1279
+ def test_find_last
1280
+ puts "In base_test test_find_last"
1281
+ last = Developer.last
1282
+ assert_equal last, Developer.all.merge!(:order => 'id desc').first
1283
+ end
1284
+
1285
+ def test_last
1286
+ puts "In base_test test_last"
1287
+ assert_equal Developer.all.merge!(:order => 'id desc').first, Developer.last
1288
+ end
1289
+
1290
+ def test_all
1291
+ puts "In base_test test_all"
1292
+ developers = Developer.all
1293
+ assert_kind_of ActiveRecord::Relation, developers
1294
+ assert_equal Developer.all, developers
1295
+ end
1296
+
1297
+ def test_all_with_conditions
1298
+ puts "In base_test test_all_with_conditions"
1299
+ assert_equal Developer.all.merge!(:order => 'id desc').to_a, Developer.order('id desc').to_a
1300
+ end
1301
+
1302
+ def test_find_ordered_last
1303
+ puts "In base_test test_find_ordered_last"
1304
+ last = Developer.all.merge!(:order => 'developers.salary ASC').last
1305
+ assert_equal last, Developer.all.merge!(:order => 'developers.salary ASC').to_a.last
1306
+ end
1307
+
1308
+ def test_find_reverse_ordered_last
1309
+ puts "In base_test test_find_reverse_ordered_last"
1310
+ last = Developer.all.merge!(:order => 'developers.salary DESC').last
1311
+ assert_equal last, Developer.all.merge!(:order => 'developers.salary DESC').to_a.last
1312
+ end
1313
+
1314
+ def test_find_multiple_ordered_last
1315
+ puts "In base_test test_find_multiple_ordered_last"
1316
+ last = Developer.all.merge!(:order => 'developers.name, developers.salary DESC').last
1317
+ assert_equal last, Developer.all.merge!(:order => 'developers.name, developers.salary DESC').to_a.last
1318
+ end
1319
+
1320
+ def test_find_keeps_multiple_order_values
1321
+ puts "In base_test test_find_keeps_multiple_order_values"
1322
+ combined = Developer.all.merge!(:order => 'developers.name, developers.salary').to_a
1323
+ assert_equal combined, Developer.all.merge!(:order => ['developers.name', 'developers.salary']).to_a
1324
+ end
1325
+
1326
+ def test_find_keeps_multiple_group_values
1327
+ puts "In base_test test_find_keeps_multiple_group_values"
1328
+ combined = Developer.all.merge!(:group => 'developers.name, developers.salary, developers.id, developers.created_at, developers.updated_at, developers.created_on, developers.updated_on').to_a
1329
+ assert_equal combined, Developer.all.merge!(:group => ['developers.name', 'developers.salary', 'developers.id', 'developers.created_at', 'developers.updated_at', 'developers.created_on', 'developers.updated_on']).to_a
1330
+ end
1331
+
1332
+ def test_find_symbol_ordered_last
1333
+ puts "In base_test test_find_symbol_ordered_last"
1334
+ last = Developer.all.merge!(:order => :salary).last
1335
+ assert_equal last, Developer.all.merge!(:order => :salary).to_a.last
1336
+ end
1337
+
1338
+ def test_abstract_class_table_name
1339
+ puts "In base_test test_abstract_class_table_name"
1340
+ assert_nil AbstractCompany.table_name
1341
+ end
1342
+
1343
+ def test_find_on_abstract_base_class_doesnt_use_type_condition
1344
+ puts "In base_test test_find_on_abstract_base_class_doesnt_use_type_condition"
1345
+ old_class = LooseDescendant
1346
+ Object.send :remove_const, :LooseDescendant
1347
+
1348
+ descendant = old_class.create! :first_name => 'bob'
1349
+ assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
1350
+ ensure
1351
+ unless Object.const_defined?(:LooseDescendant)
1352
+ Object.const_set :LooseDescendant, old_class
1353
+ end
1354
+ end
1355
+
1356
+ def test_assert_queries
1357
+ puts "In base_test test_assert_queries"
1358
+ query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
1359
+ assert_queries(2) { 2.times { query.call } }
1360
+ assert_queries 1, &query
1361
+ assert_no_queries { assert true }
1362
+ end
1363
+
1364
+ def test_benchmark_with_log_level
1365
+ puts "In base_test test_benchmark_with_log_level"
1366
+ original_logger = ActiveRecord::Base.logger
1367
+ log = StringIO.new
1368
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
1369
+ ActiveRecord::Base.logger.level = Logger::WARN
1370
+ ActiveRecord::Base.benchmark("Debug Topic Count", :level => :debug) { Topic.count }
1371
+ ActiveRecord::Base.benchmark("Warn Topic Count", :level => :warn) { Topic.count }
1372
+ ActiveRecord::Base.benchmark("Error Topic Count", :level => :error) { Topic.count }
1373
+ assert_no_match(/Debug Topic Count/, log.string)
1374
+ assert_match(/Warn Topic Count/, log.string)
1375
+ assert_match(/Error Topic Count/, log.string)
1376
+ ensure
1377
+ ActiveRecord::Base.logger = original_logger
1378
+ end
1379
+
1380
+ def test_benchmark_with_use_silence
1381
+ puts "In base_test test_benchmark_with_use_silence"
1382
+ original_logger = ActiveRecord::Base.logger
1383
+ log = StringIO.new
1384
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
1385
+ ActiveRecord::Base.logger.level = Logger::DEBUG
1386
+ ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" }
1387
+ assert_match(/Quiet/, log.string)
1388
+ ensure
1389
+ ActiveRecord::Base.logger = original_logger
1390
+ end
1391
+
1392
+ def test_clear_cache!
1393
+ puts "In base_test test_clear_cache"
1394
+ # preheat cache
1395
+ c1 = Post.connection.schema_cache.columns('posts')
1396
+ ActiveRecord::Base.clear_cache!
1397
+ c2 = Post.connection.schema_cache.columns('posts')
1398
+ c1.each_with_index do |v, i|
1399
+ assert_not_same v, c2[i]
1400
+ end
1401
+ assert_equal c1, c2
1402
+ end
1403
+
1404
+ def test_current_scope_is_reset
1405
+ puts "In base_test test_current_scope_is_reset"
1406
+ Object.const_set :UnloadablePost, Class.new(ActiveRecord::Base)
1407
+ UnloadablePost.send(:current_scope=, UnloadablePost.all)
1408
+
1409
+ UnloadablePost.unloadable
1410
+ klass = UnloadablePost
1411
+ assert_not_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, klass)
1412
+ ActiveSupport::Dependencies.remove_unloadable_constants!
1413
+ assert_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, klass)
1414
+ ensure
1415
+ Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
1416
+ end
1417
+
1418
+ def test_marshal_round_trip
1419
+ puts "In base_test test_marshal_round_trip"
1420
+ expected = posts(:welcome)
1421
+ marshalled = Marshal.dump(expected)
1422
+ actual = Marshal.load(marshalled)
1423
+
1424
+ assert_equal expected.attributes, actual.attributes
1425
+ end
1426
+
1427
+ def test_marshal_new_record_round_trip
1428
+ puts "In base_test test_marshal_new_record_round_trip"
1429
+ marshalled = Marshal.dump(Post.new)
1430
+ post = Marshal.load(marshalled)
1431
+
1432
+ assert post.new_record?, "should be a new record"
1433
+ end
1434
+
1435
+ def test_marshalling_with_associations
1436
+ puts "In base_test test_marshalling_with_associations"
1437
+ post = Post.new
1438
+ post.comments.build
1439
+
1440
+ marshalled = Marshal.dump(post)
1441
+ post = Marshal.load(marshalled)
1442
+
1443
+ assert_equal 1, post.comments.length
1444
+ end
1445
+
1446
+ if Process.respond_to?(:fork) && !in_memory_db?
1447
+ def test_marshal_between_processes
1448
+ puts "In base_test test_marshal_between_processes"
1449
+ # Define a new model to ensure there are no caches
1450
+ if self.class.const_defined?("Post", false)
1451
+ flunk "there should be no post constant"
1452
+ end
1453
+
1454
+ self.class.const_set("Post", Class.new(ActiveRecord::Base) {
1455
+ has_many :comments
1456
+ })
1457
+
1458
+ rd, wr = IO.pipe
1459
+ rd.binmode
1460
+ wr.binmode
1461
+
1462
+ ActiveRecord::Base.connection_handler.clear_all_connections!
1463
+
1464
+ fork do
1465
+ rd.close
1466
+ post = Post.new
1467
+ post.comments.build
1468
+ wr.write Marshal.dump(post)
1469
+ wr.close
1470
+ end
1471
+
1472
+ wr.close
1473
+ assert Marshal.load rd.read
1474
+ rd.close
1475
+ end
1476
+ end
1477
+
1478
+ def test_marshalling_new_record_round_trip_with_associations
1479
+ puts "In base_test test_marshalling_new_record_round_trip_with_associations"
1480
+ post = Post.new
1481
+ post.comments.build
1482
+
1483
+ post = Marshal.load(Marshal.dump(post))
1484
+
1485
+ assert post.new_record?, "should be a new record"
1486
+ end
1487
+
1488
+ def test_attribute_names
1489
+ puts "In base_test test_attribute_names"
1490
+ assert_equal ["id", "type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id", "description"],
1491
+ Company.attribute_names
1492
+ end
1493
+
1494
+ def test_has_attribute
1495
+ puts "In base_test test_has_attribute"
1496
+ assert Company.has_attribute?('id')
1497
+ assert Company.has_attribute?('type')
1498
+ assert Company.has_attribute?('name')
1499
+ assert_not Company.has_attribute?('lastname')
1500
+ assert_not Company.has_attribute?('age')
1501
+ end
1502
+
1503
+ def test_has_attribute_with_symbol
1504
+ puts "In base_test test_has_attribute_with_symbol"
1505
+ assert Company.has_attribute?(:id)
1506
+ assert_not Company.has_attribute?(:age)
1507
+ end
1508
+
1509
+ def test_attribute_names_on_table_not_exists
1510
+ puts "In base_test test_attribute_names_on_table_not_exists"
1511
+ assert_equal [], NonExistentTable.attribute_names
1512
+ end
1513
+
1514
+ def test_attribute_names_on_abstract_class
1515
+ puts "In base_test test_attribute_names_on_abstract_class"
1516
+ assert_equal [], AbstractCompany.attribute_names
1517
+ end
1518
+
1519
+ def test_touch_should_raise_error_on_a_new_object
1520
+ puts "In base_test test_touch_should_raise_error_on_a_new_object"
1521
+ company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals")
1522
+ assert_raises(ActiveRecord::ActiveRecordError) do
1523
+ company.touch :updated_at
1524
+ end
1525
+ end
1526
+
1527
+ def test_uniq_delegates_to_scoped
1528
+ puts "In base_test test_uniq_delegates_to_scoped"
1529
+ assert_deprecated do
1530
+ assert_equal Bird.all.distinct, Bird.uniq
1531
+ end
1532
+ end
1533
+
1534
+ def test_distinct_delegates_to_scoped
1535
+ puts "In base_test test_distinct_delegates_to_scoped"
1536
+ assert_equal Bird.all.distinct, Bird.distinct
1537
+ end
1538
+
1539
+ def test_table_name_with_2_abstract_subclasses
1540
+ puts "In base_test test_table_name_with_2_abstract_subclasses"
1541
+ assert_equal "photos", Photo.table_name
1542
+ end
1543
+
1544
+ def test_column_types_typecast
1545
+ puts "In base_test test_column_types_typecast"
1546
+ topic = Topic.first
1547
+ assert_not_equal 't.lo', topic.author_name
1548
+
1549
+ attrs = topic.attributes.dup
1550
+ attrs.delete 'id'
1551
+
1552
+ typecast = Class.new(ActiveRecord::Type::Value) {
1553
+ def cast value
1554
+ "t.lo"
1555
+ end
1556
+ }
1557
+
1558
+ types = { 'author_name' => typecast.new }
1559
+ topic = Topic.instantiate(attrs, types)
1560
+
1561
+ assert_equal 't.lo', topic.author_name
1562
+ end
1563
+
1564
+ def test_typecasting_aliases
1565
+ puts "In base_test test_typecasting_aliases"
1566
+ assert_equal 10, Topic.select('10 as tenderlove').first.tenderlove
1567
+ end
1568
+
1569
+ def test_slice
1570
+ puts "In base_test test_slice"
1571
+ company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals")
1572
+ hash = company.slice(:name, :rating, "arbitrary_method")
1573
+ assert_equal hash[:name], company.name
1574
+ assert_equal hash['name'], company.name
1575
+ assert_equal hash[:rating], company.rating
1576
+ assert_equal hash['arbitrary_method'], company.arbitrary_method
1577
+ assert_equal hash[:arbitrary_method], company.arbitrary_method
1578
+ assert_nil hash[:firm_name]
1579
+ assert_nil hash['firm_name']
1580
+ end
1581
+
1582
+ def test_default_values_are_deeply_dupped
1583
+ puts "In base_test test_default_values_are_deeply_dupped"
1584
+ company = Company.new
1585
+ company.description << "foo"
1586
+ assert_equal "", Company.new.description
1587
+ end
1588
+
1589
+ test "scoped can take a values hash" do
1590
+ puts "In base_test scoped can take a values hash"
1591
+ klass = Class.new(ActiveRecord::Base)
1592
+ assert_equal ['foo'], klass.all.merge!(select: 'foo').select_values
1593
+ end
1594
+
1595
+ test "connection_handler can be overridden" do
1596
+ puts "In base_test connection_handler can be overridden"
1597
+ klass = Class.new(ActiveRecord::Base)
1598
+ orig_handler = klass.connection_handler
1599
+ new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
1600
+ thread_connection_handler = nil
1601
+
1602
+ t = Thread.new do
1603
+ klass.connection_handler = new_handler
1604
+ thread_connection_handler = klass.connection_handler
1605
+ end
1606
+ t.join
1607
+
1608
+ assert_equal klass.connection_handler, orig_handler
1609
+ assert_equal thread_connection_handler, new_handler
1610
+ end
1611
+
1612
+ test "new threads get default the default connection handler" do
1613
+ puts "In base_test new threads get default the default connection handler"
1614
+ klass = Class.new(ActiveRecord::Base)
1615
+ orig_handler = klass.connection_handler
1616
+ handler = nil
1617
+
1618
+ t = Thread.new do
1619
+ handler = klass.connection_handler
1620
+ end
1621
+ t.join
1622
+
1623
+ assert_equal handler, orig_handler
1624
+ assert_equal klass.connection_handler, orig_handler
1625
+ assert_equal klass.default_connection_handler, orig_handler
1626
+ end
1627
+
1628
+ test "changing a connection handler in a main thread does not poison the other threads" do
1629
+ puts "In base_test changing a connection handler in a main thread does not poison the other threads"
1630
+ klass = Class.new(ActiveRecord::Base)
1631
+ orig_handler = klass.connection_handler
1632
+ new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
1633
+ after_handler = nil
1634
+ latch1 = Concurrent::CountDownLatch.new
1635
+ latch2 = Concurrent::CountDownLatch.new
1636
+
1637
+ t = Thread.new do
1638
+ klass.connection_handler = new_handler
1639
+ latch1.count_down
1640
+ latch2.wait
1641
+ after_handler = klass.connection_handler
1642
+ end
1643
+
1644
+ latch1.wait
1645
+
1646
+ klass.connection_handler = orig_handler
1647
+ latch2.count_down
1648
+ t.join
1649
+
1650
+ assert_equal after_handler, new_handler
1651
+ assert_equal orig_handler, klass.connection_handler
1652
+ end
1653
+
1654
+ # Note: This is a performance optimization for Array#uniq and Hash#[] with
1655
+ # AR::Base objects. If the future has made this irrelevant, feel free to
1656
+ # delete this.
1657
+ test "records without an id have unique hashes" do
1658
+ puts "In base_test records without an id have unique hashes"
1659
+ assert_not_equal Post.new.hash, Post.new.hash
1660
+ end
1661
+
1662
+ test "resetting column information doesn't remove attribute methods" do
1663
+ puts "In base_test changing a connection handler in a main thread does not poison the other threads"
1664
+ topic = topics(:first)
1665
+
1666
+ assert_not topic.id_changed?
1667
+
1668
+ Topic.reset_column_information
1669
+
1670
+ assert_not topic.id_changed?
1671
+ end
1672
+
1673
+ test "ignored columns are not present in columns_hash" do
1674
+ puts "In base_test ignored columns are not present in columns_hash"
1675
+ cache_columns = Developer.connection.schema_cache.columns_hash(Developer.table_name)
1676
+ assert_includes cache_columns.keys, "first_name"
1677
+ assert_not_includes Developer.columns_hash.keys, "first_name"
1678
+ assert_not_includes SubDeveloper.columns_hash.keys, "first_name"
1679
+ assert_not_includes SymbolIgnoredDeveloper.columns_hash.keys, "first_name"
1680
+ end
1681
+
1682
+ test "ignored columns have no attribute methods" do
1683
+ puts "In base_test ignored columns have no attribute methods"
1684
+ refute Developer.new.respond_to?(:first_name)
1685
+ refute Developer.new.respond_to?(:first_name=)
1686
+ refute Developer.new.respond_to?(:first_name?)
1687
+ refute SubDeveloper.new.respond_to?(:first_name)
1688
+ refute SubDeveloper.new.respond_to?(:first_name=)
1689
+ refute SubDeveloper.new.respond_to?(:first_name?)
1690
+ refute SymbolIgnoredDeveloper.new.respond_to?(:first_name)
1691
+ refute SymbolIgnoredDeveloper.new.respond_to?(:first_name=)
1692
+ refute SymbolIgnoredDeveloper.new.respond_to?(:first_name?)
1693
+ end
1694
+
1695
+ test "ignored columns don't prevent explicit declaration of attribute methods" do
1696
+ puts "In base_test ignored columns don't prevent explicit declaration of attribute methods"
1697
+ assert Developer.new.respond_to?(:last_name)
1698
+ assert Developer.new.respond_to?(:last_name=)
1699
+ assert Developer.new.respond_to?(:last_name?)
1700
+ assert SubDeveloper.new.respond_to?(:last_name)
1701
+ assert SubDeveloper.new.respond_to?(:last_name=)
1702
+ assert SubDeveloper.new.respond_to?(:last_name?)
1703
+ assert SymbolIgnoredDeveloper.new.respond_to?(:last_name)
1704
+ assert SymbolIgnoredDeveloper.new.respond_to?(:last_name=)
1705
+ assert SymbolIgnoredDeveloper.new.respond_to?(:last_name?)
1706
+ end
1707
+
1708
+ test "ignored columns are stored as an array of string" do
1709
+ puts "In base_test ignored columns are stored as an array of string"
1710
+ assert_equal(%w(first_name last_name), Developer.ignored_columns)
1711
+ assert_equal(%w(first_name last_name), SymbolIgnoredDeveloper.ignored_columns)
1712
+ end
1713
+ end