ibm_db 5.6.1 → 5.7.0

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 (592) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Makefile +13 -9
  3. data/ext/extconf.rb +176 -110
  4. data/ext/ibm_db.c +60 -0
  5. data/ext/ibm_db.o +0 -0
  6. data/ext/ibm_db.so +0 -0
  7. data/ext/mkmf.log +6 -6
  8. data/ext/ruby_ibm_db_cli.c +14 -10
  9. data/ext/ruby_ibm_db_cli.h +4 -0
  10. data/ext/ruby_ibm_db_cli.o +0 -0
  11. data/lib/IBM_DB.rb +2 -2
  12. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +1254 -277
  13. data/test/active_record/connection_adapters/fake_legacy_adapter.rb +17 -0
  14. data/test/active_record/connection_adapters/fake_misleading_legacy_adapter.rb +8 -0
  15. data/test/activejob/destroy_association_async_job_test.rb +62 -0
  16. data/test/activejob/destroy_association_async_test.rb +147 -11
  17. data/test/activejob/job_runtime_test.rb +41 -0
  18. data/test/activejob/unloadable_base_job.rb +3 -0
  19. data/test/cases/active_record_schema_test.rb +196 -0
  20. data/test/cases/active_record_test.rb +21 -0
  21. data/test/cases/adapter_prevent_writes_test.rb +26 -202
  22. data/test/cases/adapter_test.rb +592 -82
  23. data/test/cases/adapters/abstract_mysql_adapter/active_schema_test.rb +210 -0
  24. data/test/cases/adapters/abstract_mysql_adapter/adapter_prevent_writes_test.rb +111 -0
  25. data/test/cases/adapters/abstract_mysql_adapter/auto_increment_test.rb +48 -0
  26. data/test/cases/adapters/abstract_mysql_adapter/bind_parameter_test.rb +91 -0
  27. data/test/cases/adapters/abstract_mysql_adapter/case_sensitivity_test.rb +65 -0
  28. data/test/cases/adapters/abstract_mysql_adapter/charset_collation_test.rb +85 -0
  29. data/test/cases/adapters/abstract_mysql_adapter/connection_test.rb +267 -0
  30. data/test/cases/adapters/abstract_mysql_adapter/count_deleted_rows_with_lock_test.rb +29 -0
  31. data/test/cases/adapters/abstract_mysql_adapter/json_test.rb +24 -0
  32. data/test/cases/adapters/abstract_mysql_adapter/mysql_boolean_test.rb +102 -0
  33. data/test/cases/adapters/abstract_mysql_adapter/mysql_enum_test.rb +47 -0
  34. data/test/cases/adapters/abstract_mysql_adapter/mysql_explain_test.rb +71 -0
  35. data/test/cases/adapters/abstract_mysql_adapter/nested_deadlock_test.rb +191 -0
  36. data/test/cases/adapters/abstract_mysql_adapter/optimizer_hints_test.rb +69 -0
  37. data/test/cases/adapters/abstract_mysql_adapter/quoting_test.rb +49 -0
  38. data/test/cases/adapters/abstract_mysql_adapter/schema_migrations_test.rb +68 -0
  39. data/test/cases/adapters/abstract_mysql_adapter/schema_test.rb +130 -0
  40. data/test/cases/adapters/abstract_mysql_adapter/set_test.rb +32 -0
  41. data/test/cases/adapters/abstract_mysql_adapter/sp_test.rb +39 -0
  42. data/test/cases/adapters/abstract_mysql_adapter/sql_types_test.rb +16 -0
  43. data/test/cases/adapters/abstract_mysql_adapter/table_options_test.rb +125 -0
  44. data/test/cases/adapters/abstract_mysql_adapter/transaction_test.rb +204 -0
  45. data/test/cases/adapters/abstract_mysql_adapter/unsigned_type_test.rb +77 -0
  46. data/test/cases/adapters/abstract_mysql_adapter/virtual_column_test.rb +69 -0
  47. data/test/cases/adapters/abstract_mysql_adapter/warnings_test.rb +109 -0
  48. data/test/cases/adapters/mysql2/check_constraint_quoting_test.rb +35 -0
  49. data/test/cases/adapters/mysql2/dbconsole_test.rb +87 -0
  50. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +136 -10
  51. data/test/cases/adapters/mysql2/mysql2_rake_test.rb +433 -0
  52. data/test/cases/adapters/postgresql/active_schema_test.rb +8 -4
  53. data/test/cases/adapters/postgresql/array_test.rb +6 -6
  54. data/test/cases/adapters/postgresql/bind_parameter_test.rb +52 -0
  55. data/test/cases/adapters/postgresql/bit_string_test.rb +2 -2
  56. data/test/cases/adapters/postgresql/bytea_test.rb +3 -3
  57. data/test/cases/adapters/postgresql/case_insensitive_test.rb +1 -1
  58. data/test/cases/adapters/postgresql/change_schema_test.rb +32 -1
  59. data/test/cases/adapters/postgresql/cidr_test.rb +17 -0
  60. data/test/cases/adapters/postgresql/citext_test.rb +7 -1
  61. data/test/cases/adapters/postgresql/collation_test.rb +1 -1
  62. data/test/cases/adapters/postgresql/composite_test.rb +1 -1
  63. data/test/cases/adapters/postgresql/connection_test.rb +43 -36
  64. data/test/cases/adapters/postgresql/create_unlogged_tables_test.rb +3 -2
  65. data/test/cases/adapters/postgresql/datatype_test.rb +9 -4
  66. data/test/cases/adapters/postgresql/date_test.rb +2 -2
  67. data/test/cases/adapters/postgresql/dbconsole_test.rb +109 -0
  68. data/test/cases/adapters/postgresql/deferred_constraints_test.rb +55 -0
  69. data/test/cases/adapters/postgresql/domain_test.rb +1 -1
  70. data/test/cases/adapters/postgresql/enum_test.rb +208 -8
  71. data/test/cases/adapters/postgresql/explain_test.rb +25 -6
  72. data/test/cases/adapters/postgresql/extension_migration_test.rb +51 -9
  73. data/test/cases/adapters/postgresql/foreign_table_test.rb +3 -3
  74. data/test/cases/adapters/postgresql/full_text_test.rb +1 -1
  75. data/test/cases/adapters/postgresql/geometric_test.rb +13 -6
  76. data/test/cases/adapters/postgresql/hstore_test.rb +22 -32
  77. data/test/cases/adapters/postgresql/infinity_test.rb +13 -2
  78. data/test/cases/adapters/postgresql/integer_test.rb +1 -1
  79. data/test/cases/adapters/postgresql/interval_test.rb +9 -17
  80. data/test/cases/adapters/postgresql/invertible_migration_test.rb +139 -0
  81. data/test/cases/adapters/postgresql/json_test.rb +5 -0
  82. data/test/cases/adapters/postgresql/ltree_test.rb +1 -1
  83. data/test/cases/adapters/postgresql/money_test.rb +17 -9
  84. data/test/cases/adapters/postgresql/network_test.rb +13 -1
  85. data/test/cases/adapters/postgresql/numbers_test.rb +18 -2
  86. data/test/cases/adapters/postgresql/optimizer_hints_test.rb +9 -9
  87. data/test/cases/adapters/postgresql/partitions_test.rb +5 -2
  88. data/test/cases/adapters/postgresql/postgresql_adapter_prevent_writes_test.rb +7 -110
  89. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +403 -20
  90. data/test/cases/adapters/postgresql/postgresql_rake_test.rb +637 -0
  91. data/test/cases/adapters/postgresql/prepared_statements_disabled_test.rb +1 -1
  92. data/test/cases/adapters/postgresql/quoting_test.rb +60 -1
  93. data/test/cases/adapters/postgresql/range_test.rb +185 -21
  94. data/test/cases/adapters/postgresql/referential_integrity_test.rb +29 -5
  95. data/test/cases/adapters/postgresql/rename_table_test.rb +35 -8
  96. data/test/cases/adapters/postgresql/schema_authorization_test.rb +2 -2
  97. data/test/cases/adapters/postgresql/schema_test.rb +270 -20
  98. data/test/cases/adapters/postgresql/serial_test.rb +5 -5
  99. data/test/cases/adapters/postgresql/statement_pool_test.rb +6 -2
  100. data/test/cases/adapters/postgresql/timestamp_test.rb +122 -5
  101. data/test/cases/adapters/postgresql/transaction_nested_test.rb +130 -6
  102. data/test/cases/adapters/postgresql/transaction_test.rb +37 -11
  103. data/test/cases/adapters/postgresql/type_lookup_test.rb +1 -1
  104. data/test/cases/adapters/postgresql/uuid_test.rb +77 -9
  105. data/test/cases/adapters/postgresql/virtual_column_test.rb +114 -0
  106. data/test/cases/adapters/postgresql/xml_test.rb +1 -1
  107. data/test/cases/adapters/sqlite3/bind_parameter_test.rb +52 -0
  108. data/test/cases/adapters/sqlite3/collation_test.rb +1 -1
  109. data/test/cases/adapters/sqlite3/copy_table_test.rb +28 -7
  110. data/test/cases/adapters/sqlite3/dbconsole_test.rb +81 -0
  111. data/test/cases/adapters/sqlite3/explain_test.rb +3 -3
  112. data/test/cases/adapters/sqlite3/quoting_test.rb +34 -3
  113. data/test/cases/adapters/sqlite3/sqlite3_adapter_prevent_writes_test.rb +9 -102
  114. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +727 -72
  115. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +6 -3
  116. data/test/cases/adapters/sqlite3/sqlite_rake_test.rb +264 -0
  117. data/test/cases/adapters/sqlite3/statement_pool_test.rb +1 -1
  118. data/test/cases/adapters/sqlite3/transaction_test.rb +6 -3
  119. data/test/cases/adapters/sqlite3/virtual_column_test.rb +138 -0
  120. data/test/cases/adapters/sqlite3/virtual_table_test.rb +51 -0
  121. data/test/cases/adapters/trilogy/dbconsole_test.rb +76 -0
  122. data/test/cases/adapters/trilogy/trilogy_adapter_test.rb +473 -0
  123. data/test/cases/adapters/trilogy/trilogy_rake_test.rb +433 -0
  124. data/test/cases/aggregations_test.rb +16 -0
  125. data/test/cases/annotate_test.rb +14 -12
  126. data/test/cases/arel/attributes/attribute_test.rb +86 -47
  127. data/test/cases/arel/collectors/bind_test.rb +1 -1
  128. data/test/cases/arel/collectors/composite_test.rb +11 -1
  129. data/test/cases/arel/collectors/sql_string_test.rb +1 -1
  130. data/test/cases/arel/collectors/substitute_bind_collector_test.rb +1 -1
  131. data/test/cases/arel/delete_manager_test.rb +0 -6
  132. data/test/cases/arel/factory_methods_test.rb +45 -0
  133. data/test/cases/arel/insert_manager_test.rb +1 -7
  134. data/test/cases/arel/nodes/as_test.rb +12 -0
  135. data/test/cases/arel/nodes/ascending_test.rb +1 -1
  136. data/test/cases/arel/nodes/bin_test.rb +1 -1
  137. data/test/cases/arel/nodes/bound_sql_literal_test.rb +31 -0
  138. data/test/cases/arel/nodes/cte_test.rb +46 -0
  139. data/test/cases/arel/nodes/descending_test.rb +1 -1
  140. data/test/cases/arel/nodes/equality_test.rb +3 -3
  141. data/test/cases/arel/nodes/filter_test.rb +37 -0
  142. data/test/cases/arel/nodes/fragments_test.rb +38 -0
  143. data/test/cases/arel/nodes/homogeneous_in_test.rb +52 -0
  144. data/test/cases/arel/nodes/infix_operation_test.rb +1 -1
  145. data/test/cases/arel/nodes/node_test.rb +1 -1
  146. data/test/cases/arel/nodes/or_test.rb +2 -2
  147. data/test/cases/arel/nodes/sql_literal_test.rb +18 -1
  148. data/test/cases/arel/nodes/table_alias_test.rb +12 -0
  149. data/test/cases/arel/nodes/unary_operation_test.rb +1 -1
  150. data/test/cases/arel/nodes/update_statement_test.rb +4 -0
  151. data/test/cases/arel/nodes_test.rb +3 -2
  152. data/test/cases/arel/select_manager_test.rb +12 -12
  153. data/test/cases/arel/support/fake_record.rb +22 -17
  154. data/test/cases/arel/table_test.rb +15 -25
  155. data/test/cases/arel/update_manager_test.rb +51 -6
  156. data/test/cases/arel/visitors/dispatch_contamination_test.rb +1 -1
  157. data/test/cases/arel/visitors/dot_test.rb +177 -2
  158. data/test/cases/arel/visitors/mysql_test.rb +49 -1
  159. data/test/cases/arel/visitors/postgres_test.rb +1 -31
  160. data/test/cases/arel/visitors/sqlite_test.rb +1 -1
  161. data/test/cases/arel/visitors/to_sql_test.rb +330 -20
  162. data/test/cases/assertions/query_assertions_test.rb +136 -0
  163. data/test/cases/associations/belongs_to_associations_test.rb +502 -41
  164. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +1 -1
  165. data/test/cases/associations/cascaded_eager_loading_test.rb +26 -15
  166. data/test/cases/associations/eager_load_nested_include_test.rb +1 -1
  167. data/test/cases/associations/eager_singularization_test.rb +1 -1
  168. data/test/cases/associations/eager_test.rb +255 -93
  169. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +25 -53
  170. data/test/cases/associations/has_many_associations_test.rb +282 -72
  171. data/test/cases/associations/has_many_through_associations_test.rb +172 -45
  172. data/test/cases/associations/has_many_through_disable_joins_associations_test.rb +197 -0
  173. data/test/cases/associations/has_one_associations_test.rb +160 -29
  174. data/test/cases/associations/has_one_through_associations_test.rb +64 -15
  175. data/test/cases/associations/has_one_through_disable_joins_associations_test.rb +82 -0
  176. data/test/cases/associations/inner_join_association_test.rb +36 -6
  177. data/test/cases/associations/inverse_associations_test.rb +177 -40
  178. data/test/cases/associations/join_model_test.rb +17 -12
  179. data/test/cases/associations/left_outer_join_association_test.rb +14 -3
  180. data/test/cases/associations/nested_error_test.rb +116 -0
  181. data/test/cases/associations/nested_through_associations_test.rb +54 -19
  182. data/test/cases/associations/required_test.rb +1 -1
  183. data/test/cases/associations_test.rb +1278 -21
  184. data/test/cases/asynchronous_queries_test.rb +310 -0
  185. data/test/cases/attribute_methods/read_test.rb +6 -0
  186. data/test/cases/attribute_methods/time_zone_converter_test.rb +21 -0
  187. data/test/cases/attribute_methods_test.rb +565 -46
  188. data/test/cases/attributes_test.rb +42 -1
  189. data/test/cases/autosave_association_test.rb +645 -92
  190. data/test/cases/base_prevent_writes_test.rb +28 -159
  191. data/test/cases/base_test.rb +434 -209
  192. data/test/cases/batches_test.rb +441 -57
  193. data/test/cases/binary_test.rb +31 -0
  194. data/test/cases/bind_parameter_test.rb +107 -16
  195. data/test/cases/cache_key_test.rb +7 -7
  196. data/test/cases/calculations_test.rb +541 -110
  197. data/test/cases/callbacks_test.rb +0 -1
  198. data/test/cases/clone_test.rb +5 -4
  199. data/test/cases/coders/yaml_column_test.rb +97 -2
  200. data/test/cases/collection_cache_key_test.rb +24 -16
  201. data/test/cases/column_alias_test.rb +2 -8
  202. data/test/cases/column_definition_test.rb +12 -3
  203. data/test/cases/comment_test.rb +23 -26
  204. data/test/cases/connection_adapters/adapter_leasing_test.rb +9 -9
  205. data/test/cases/connection_adapters/connection_handler_test.rb +145 -99
  206. data/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +79 -55
  207. data/test/cases/connection_adapters/connection_handlers_multi_pool_config_test.rb +17 -20
  208. data/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb +146 -55
  209. data/test/cases/connection_adapters/connection_swapping_nested_test.rb +136 -23
  210. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +96 -27
  211. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +5 -5
  212. data/test/cases/connection_adapters/registration_test.rb +98 -0
  213. data/test/cases/connection_adapters/schema_cache_test.rb +288 -135
  214. data/test/cases/connection_adapters/standalone_connection_test.rb +38 -0
  215. data/test/cases/connection_adapters/statement_pool_test.rb +29 -0
  216. data/test/cases/connection_adapters/type_lookup_test.rb +12 -24
  217. data/test/cases/connection_handling_test.rb +210 -0
  218. data/test/cases/connection_management_test.rb +44 -7
  219. data/test/cases/connection_pool_test.rb +466 -99
  220. data/test/cases/core_test.rb +167 -9
  221. data/test/cases/counter_cache_test.rb +129 -2
  222. data/test/cases/custom_locking_test.rb +3 -3
  223. data/test/cases/database_configurations/hash_config_test.rb +149 -13
  224. data/test/cases/database_configurations/resolver_test.rb +14 -10
  225. data/test/cases/database_configurations/url_config_test.rb +53 -0
  226. data/test/cases/database_configurations_test.rb +86 -43
  227. data/test/cases/database_selector_test.rb +30 -8
  228. data/test/cases/database_statements_test.rb +10 -14
  229. data/test/cases/date_time_precision_test.rb +141 -11
  230. data/test/cases/date_time_test.rb +19 -1
  231. data/test/cases/defaults_test.rb +107 -41
  232. data/test/cases/delegated_type_test.rb +69 -9
  233. data/test/cases/dirty_test.rb +82 -25
  234. data/test/cases/disconnected_test.rb +10 -9
  235. data/test/cases/dup_test.rb +26 -6
  236. data/test/cases/encryption/cipher/aes256_gcm_test.rb +50 -0
  237. data/test/cases/encryption/cipher_test.rb +65 -0
  238. data/test/cases/encryption/concurrency_test.rb +27 -0
  239. data/test/cases/encryption/config_test.rb +21 -0
  240. data/test/cases/encryption/configurable_test.rb +93 -0
  241. data/test/cases/encryption/contexts_test.rb +105 -0
  242. data/test/cases/encryption/derived_secret_key_provider_test.rb +31 -0
  243. data/test/cases/encryption/deterministic_key_provider_test.rb +11 -0
  244. data/test/cases/encryption/encryptable_record_api_test.rb +175 -0
  245. data/test/cases/encryption/encryptable_record_message_pack_serialized_test.rb +42 -0
  246. data/test/cases/encryption/encryptable_record_test.rb +470 -0
  247. data/test/cases/encryption/encrypted_fixtures_test.rb +22 -0
  248. data/test/cases/encryption/encrypting_only_encryptor_test.rb +20 -0
  249. data/test/cases/encryption/encryption_schemes_test.rb +240 -0
  250. data/test/cases/encryption/encryptor_test.rb +113 -0
  251. data/test/cases/encryption/envelope_encryption_key_provider_test.rb +49 -0
  252. data/test/cases/encryption/extended_deterministic_queries_test.rb +81 -0
  253. data/test/cases/encryption/helper.rb +152 -0
  254. data/test/cases/encryption/key_generator_test.rb +55 -0
  255. data/test/cases/encryption/key_provider_test.rb +57 -0
  256. data/test/cases/encryption/key_test.rb +17 -0
  257. data/test/cases/encryption/message_pack_message_serializer_test.rb +70 -0
  258. data/test/cases/encryption/message_serializer_test.rb +82 -0
  259. data/test/cases/encryption/message_test.rb +43 -0
  260. data/test/cases/encryption/null_encryptor_test.rb +21 -0
  261. data/test/cases/encryption/properties_test.rb +69 -0
  262. data/test/cases/encryption/read_only_null_encryptor_test.rb +19 -0
  263. data/test/cases/encryption/scheme_test.rb +58 -0
  264. data/test/cases/encryption/unencrypted_attributes_test.rb +27 -0
  265. data/test/cases/encryption/uniqueness_validations_test.rb +65 -0
  266. data/test/cases/enum_test.rb +374 -72
  267. data/test/cases/errors_test.rb +7 -4
  268. data/test/cases/excluding_test.rb +116 -0
  269. data/test/cases/explain_subscriber_test.rb +6 -1
  270. data/test/cases/explain_test.rb +119 -10
  271. data/test/cases/filter_attributes_test.rb +7 -14
  272. data/test/cases/finder_respond_to_test.rb +3 -3
  273. data/test/cases/finder_test.rb +357 -72
  274. data/test/cases/fixture_set/file_test.rb +9 -0
  275. data/test/cases/fixtures_test.rb +426 -190
  276. data/test/cases/helper.rb +66 -192
  277. data/test/cases/hot_compatibility_test.rb +10 -10
  278. data/test/cases/inheritance_test.rb +51 -61
  279. data/test/cases/inherited_test.rb +40 -0
  280. data/test/cases/insert_all_test.rb +419 -9
  281. data/test/cases/instrumentation_test.rb +202 -30
  282. data/test/cases/integration_test.rb +25 -7
  283. data/test/cases/invalid_connection_test.rb +5 -5
  284. data/test/cases/invertible_migration_test.rb +108 -24
  285. data/test/cases/json_attribute_test.rb +1 -0
  286. data/test/cases/json_serialization_test.rb +5 -5
  287. data/test/cases/json_shared_test_cases.rb +5 -9
  288. data/test/cases/locking_test.rb +67 -31
  289. data/test/cases/log_subscriber_test.rb +17 -15
  290. data/test/cases/marshal_serialization_test.rb +78 -5
  291. data/test/cases/message_pack_test.rb +91 -0
  292. data/test/cases/migration/change_schema_test.rb +77 -46
  293. data/test/cases/migration/change_table_test.rb +129 -114
  294. data/test/cases/migration/check_constraint_test.rb +192 -10
  295. data/test/cases/migration/column_attributes_test.rb +4 -9
  296. data/test/cases/migration/column_positioning_test.rb +2 -2
  297. data/test/cases/migration/columns_test.rb +118 -4
  298. data/test/cases/migration/command_recorder_test.rb +181 -14
  299. data/test/cases/migration/compatibility_test.rb +883 -196
  300. data/test/cases/migration/create_join_table_test.rb +8 -1
  301. data/test/cases/migration/exclusion_constraint_test.rb +192 -0
  302. data/test/cases/migration/foreign_key_test.rb +356 -14
  303. data/test/cases/migration/helper.rb +4 -1
  304. data/test/cases/migration/index_test.rb +67 -2
  305. data/test/cases/migration/invalid_options_test.rb +129 -0
  306. data/test/cases/migration/logger_test.rb +7 -4
  307. data/test/cases/migration/pending_migrations_test.rb +103 -60
  308. data/test/cases/migration/references_foreign_key_test.rb +73 -4
  309. data/test/cases/migration/references_index_test.rb +25 -27
  310. data/test/cases/migration/references_statements_test.rb +27 -3
  311. data/test/cases/migration/rename_table_test.rb +39 -54
  312. data/test/cases/migration/schema_definitions_test.rb +109 -0
  313. data/test/cases/migration/unique_constraint_test.rb +248 -0
  314. data/test/cases/migration_test.rb +677 -220
  315. data/test/cases/migrator_test.rb +102 -75
  316. data/test/cases/multi_db_migrator_test.rb +55 -34
  317. data/test/cases/multiparameter_attributes_test.rb +26 -29
  318. data/test/cases/multiple_db_test.rb +42 -19
  319. data/test/cases/nested_attributes_test.rb +124 -6
  320. data/test/cases/nested_attributes_with_callbacks_test.rb +2 -2
  321. data/test/cases/normalized_attribute_test.rb +117 -0
  322. data/test/cases/null_relation_test.rb +35 -2
  323. data/test/cases/persistence/reload_association_cache_test.rb +20 -0
  324. data/test/cases/persistence_test.rb +629 -22
  325. data/test/cases/pooled_connections_test.rb +57 -56
  326. data/test/cases/prepared_statement_status_test.rb +8 -3
  327. data/test/cases/primary_class_test.rb +134 -0
  328. data/test/cases/primary_keys_test.rb +171 -55
  329. data/test/cases/query_cache_test.rb +558 -263
  330. data/test/cases/query_logs_test.rb +293 -0
  331. data/test/cases/quoting_test.rb +39 -72
  332. data/test/cases/readonly_test.rb +50 -12
  333. data/test/cases/reaper_test.rb +22 -6
  334. data/test/cases/reflection_test.rb +207 -9
  335. data/test/cases/relation/and_test.rb +43 -0
  336. data/test/cases/relation/delegation_test.rb +32 -5
  337. data/test/cases/relation/delete_all_test.rb +27 -6
  338. data/test/cases/relation/field_ordered_values_test.rb +128 -0
  339. data/test/cases/relation/load_async_test.rb +650 -0
  340. data/test/cases/relation/merging_test.rb +80 -109
  341. data/test/cases/relation/mutation_test.rb +12 -7
  342. data/test/cases/relation/or_test.rb +11 -8
  343. data/test/cases/relation/order_test.rb +90 -0
  344. data/test/cases/relation/predicate_builder_test.rb +21 -6
  345. data/test/cases/relation/select_test.rb +162 -3
  346. data/test/cases/relation/structural_compatibility_test.rb +38 -0
  347. data/test/cases/relation/update_all_test.rb +81 -27
  348. data/test/cases/relation/where_chain_test.rb +190 -3
  349. data/test/cases/relation/where_clause_test.rb +43 -1
  350. data/test/cases/relation/where_test.rb +95 -7
  351. data/test/cases/relation/with_test.rb +165 -0
  352. data/test/cases/relation_test.rb +42 -37
  353. data/test/cases/relations_test.rb +436 -138
  354. data/test/cases/reload_models_test.rb +18 -14
  355. data/test/cases/reserved_word_test.rb +2 -1
  356. data/test/cases/result_test.rb +14 -22
  357. data/test/cases/sanitize_test.rb +89 -27
  358. data/test/cases/schema_dumper_test.rb +535 -62
  359. data/test/cases/scoping/default_scoping_test.rb +219 -35
  360. data/test/cases/scoping/named_scoping_test.rb +25 -46
  361. data/test/cases/scoping/relation_scoping_test.rb +112 -4
  362. data/test/cases/secure_password_test.rb +108 -0
  363. data/test/cases/secure_token_test.rb +72 -0
  364. data/test/cases/serialization_test.rb +1 -1
  365. data/test/cases/serialized_attribute_test.rb +305 -60
  366. data/test/cases/shard_keys_test.rb +125 -0
  367. data/test/cases/shard_selector_test.rb +45 -0
  368. data/test/cases/signed_id_test.rb +57 -5
  369. data/test/cases/statement_cache_test.rb +31 -30
  370. data/test/cases/statement_invalid_test.rb +8 -4
  371. data/test/cases/store_test.rb +73 -9
  372. data/test/cases/strict_loading_test.rb +327 -13
  373. data/test/cases/table_metadata_test.rb +16 -0
  374. data/test/cases/tasks/database_tasks_test.rb +517 -244
  375. data/test/cases/test_case.rb +254 -60
  376. data/test/cases/test_case_test.rb +69 -0
  377. data/test/cases/test_databases_test.rb +7 -3
  378. data/test/cases/test_fixtures_test.rb +19 -40
  379. data/test/cases/time_precision_test.rb +17 -5
  380. data/test/cases/timestamp_test.rb +124 -16
  381. data/test/cases/token_for_test.rb +165 -0
  382. data/test/cases/touch_later_test.rb +43 -1
  383. data/test/cases/transaction_callbacks_test.rb +325 -8
  384. data/test/cases/transaction_instrumentation_test.rb +453 -0
  385. data/test/cases/transaction_isolation_test.rb +12 -8
  386. data/test/cases/transactions_test.rb +629 -112
  387. data/test/cases/type/date_time_test.rb +7 -1
  388. data/test/cases/type/time_test.rb +9 -0
  389. data/test/cases/type/type_map_test.rb +108 -73
  390. data/test/cases/type/unsigned_integer_test.rb +12 -0
  391. data/test/cases/type_caster/connection_test.rb +19 -0
  392. data/test/cases/type_test.rb +1 -1
  393. data/test/cases/unconnected_test.rb +7 -7
  394. data/test/cases/unsafe_raw_sql_test.rb +39 -8
  395. data/test/cases/validations/absence_validation_test.rb +1 -1
  396. data/test/cases/validations/association_validation_test.rb +25 -3
  397. data/test/cases/validations/numericality_validation_test.rb +3 -9
  398. data/test/cases/validations/presence_validation_test.rb +1 -1
  399. data/test/cases/validations/uniqueness_validation_test.rb +280 -40
  400. data/test/cases/validations_test.rb +2 -2
  401. data/test/cases/view_test.rb +33 -22
  402. data/test/cases/yaml_serialization_test.rb +23 -17
  403. data/test/config.example.yml +58 -56
  404. data/test/config.rb +1 -0
  405. data/test/fixtures/1_need_quoting.yml +2 -0
  406. data/test/fixtures/accounts.yml +5 -0
  407. data/test/fixtures/aircrafts.yml +7 -0
  408. data/test/fixtures/book_identifiers.yml +11 -0
  409. data/test/fixtures/books.yml +5 -4
  410. data/test/fixtures/cake_designers.yml +5 -0
  411. data/test/fixtures/cars.yml +6 -0
  412. data/test/fixtures/chefs.yml +5 -0
  413. data/test/fixtures/clothing_items.yml +23 -0
  414. data/test/fixtures/clubs.yml +1 -1
  415. data/test/fixtures/comments.yml +2 -1
  416. data/test/fixtures/cpk_authors.yml +8 -0
  417. data/test/fixtures/cpk_books.yml +21 -0
  418. data/test/fixtures/cpk_order_agreements.yml +13 -0
  419. data/test/fixtures/cpk_order_tags.yml +15 -0
  420. data/test/fixtures/cpk_orders.yml +11 -0
  421. data/test/fixtures/cpk_posts.yml +12 -0
  422. data/test/fixtures/cpk_reviews.yml +13 -0
  423. data/test/fixtures/cpk_tags.yml +11 -0
  424. data/test/fixtures/drink_designers.yml +5 -0
  425. data/test/fixtures/encrypted_book_that_ignores_cases.yml +4 -0
  426. data/test/fixtures/encrypted_books.yml +4 -0
  427. data/test/fixtures/fk_object_to_point_to.yml +2 -0
  428. data/test/fixtures/memberships.yml +15 -15
  429. data/test/fixtures/paragraphs.yml +5 -0
  430. data/test/fixtures/parrots.yml +4 -0
  431. data/test/fixtures/people.yml +2 -0
  432. data/test/fixtures/pirates.yml +2 -2
  433. data/test/fixtures/primary_key_error/primary_key_error.yml +6 -0
  434. data/test/fixtures/references.yml +3 -3
  435. data/test/fixtures/sharded_blog_posts.yml +14 -0
  436. data/test/fixtures/sharded_blog_posts_tags.yml +27 -0
  437. data/test/fixtures/sharded_blogs.yml +8 -0
  438. data/test/fixtures/sharded_comments.yml +22 -0
  439. data/test/fixtures/sharded_tags.yml +34 -0
  440. data/test/fixtures/sponsors.yml +2 -2
  441. data/test/fixtures/topics.yml +1 -0
  442. data/test/fixtures/treasures.yml +4 -0
  443. data/test/fixtures/virtual_columns.yml +5 -0
  444. data/test/fixtures/warehouse_things.yml +1 -1
  445. data/test/migrations/old_and_new_versions/20210716122844_add_people_description.rb +5 -0
  446. data/test/migrations/old_and_new_versions/20210716123013_add_people_number_of_legs.rb +5 -0
  447. data/test/migrations/old_and_new_versions/230_add_people_hobby.rb +5 -0
  448. data/test/migrations/old_and_new_versions/231_add_people_last_name.rb +5 -0
  449. data/test/migrations/scope/1_unscoped.rb +7 -0
  450. data/test/migrations/scope/2_mysql_only.mysql.rb +7 -0
  451. data/test/models/admin/user.rb +2 -0
  452. data/test/models/admin/user_json.rb +48 -0
  453. data/test/models/attachment.rb +7 -0
  454. data/test/models/author.rb +70 -3
  455. data/test/models/author_encrypted.rb +16 -0
  456. data/test/models/bird.rb +1 -1
  457. data/test/models/book.rb +18 -11
  458. data/test/models/book_destroy_async.rb +1 -1
  459. data/test/models/book_encrypted.rb +106 -0
  460. data/test/models/book_identifier.rb +5 -0
  461. data/test/models/branch.rb +11 -0
  462. data/test/models/bulb.rb +1 -1
  463. data/test/models/car.rb +8 -1
  464. data/test/models/cat.rb +1 -1
  465. data/test/models/category.rb +3 -1
  466. data/test/models/chat_message.rb +8 -0
  467. data/test/models/chef.rb +52 -0
  468. data/test/models/clothing_item.rb +12 -0
  469. data/test/models/club.rb +4 -1
  470. data/test/models/comment.rb +7 -4
  471. data/test/models/comment_overlapping_counter_cache.rb +15 -0
  472. data/test/models/company.rb +16 -2
  473. data/test/models/computer.rb +1 -0
  474. data/test/models/contact.rb +3 -3
  475. data/test/models/contract.rb +5 -1
  476. data/test/models/cpk/author.rb +9 -0
  477. data/test/models/cpk/book.rb +55 -0
  478. data/test/models/cpk/book_destroy_async.rb +9 -0
  479. data/test/models/cpk/car.rb +9 -0
  480. data/test/models/cpk/car_review.rb +9 -0
  481. data/test/models/cpk/chapter.rb +16 -0
  482. data/test/models/cpk/chapter_destroy_async.rb +10 -0
  483. data/test/models/cpk/comment.rb +9 -0
  484. data/test/models/cpk/order.rb +55 -0
  485. data/test/models/cpk/order_agreement.rb +10 -0
  486. data/test/models/cpk/order_tag.rb +10 -0
  487. data/test/models/cpk/post.rb +10 -0
  488. data/test/models/cpk/posts_tag.rb +10 -0
  489. data/test/models/cpk/review.rb +9 -0
  490. data/test/models/cpk/tag.rb +10 -0
  491. data/test/models/cpk.rb +15 -0
  492. data/test/models/customer.rb +3 -1
  493. data/test/models/destroy_async_parent.rb +1 -1
  494. data/test/models/developer.rb +44 -3
  495. data/test/models/discount.rb +4 -0
  496. data/test/models/drink_designer.rb +1 -0
  497. data/test/models/editor.rb +8 -0
  498. data/test/models/editorship.rb +6 -0
  499. data/test/models/entry.rb +5 -0
  500. data/test/models/essay.rb +6 -1
  501. data/test/models/essay_destroy_async.rb +1 -0
  502. data/test/models/eye.rb +87 -21
  503. data/test/models/face.rb +1 -1
  504. data/test/models/friendship.rb +3 -0
  505. data/test/models/hardback.rb +7 -0
  506. data/test/models/hotel.rb +2 -0
  507. data/test/models/human.rb +2 -2
  508. data/test/models/invoice.rb +2 -1
  509. data/test/models/invokes_an_undefined_method.rb +5 -0
  510. data/test/models/line_item.rb +6 -0
  511. data/test/models/member.rb +9 -4
  512. data/test/models/membership.rb +2 -2
  513. data/test/models/message.rb +2 -1
  514. data/test/models/need_quoting.rb +5 -0
  515. data/test/models/paragraph.rb +5 -0
  516. data/test/models/parrot.rb +6 -3
  517. data/test/models/person.rb +7 -4
  518. data/test/models/pirate.rb +4 -1
  519. data/test/models/pk_autopopulated_by_a_trigger_record.rb +5 -0
  520. data/test/models/post.rb +65 -2
  521. data/test/models/post_encrypted.rb +15 -0
  522. data/test/models/post_with_prefetched_pk.rb +15 -0
  523. data/test/models/project.rb +1 -0
  524. data/test/models/publication.rb +16 -0
  525. data/test/models/raises_argument_error.rb +5 -0
  526. data/test/models/raises_no_method_error.rb +5 -0
  527. data/test/models/recipient.rb +5 -0
  528. data/test/models/reference.rb +1 -1
  529. data/test/models/reply.rb +1 -1
  530. data/test/models/room.rb +3 -0
  531. data/test/models/sharded/blog.rb +12 -0
  532. data/test/models/sharded/blog_post.rb +17 -0
  533. data/test/models/sharded/blog_post_destroy_async.rb +14 -0
  534. data/test/models/sharded/blog_post_tag.rb +11 -0
  535. data/test/models/sharded/blog_post_with_revision.rb +11 -0
  536. data/test/models/sharded/comment.rb +12 -0
  537. data/test/models/sharded/comment_destroy_async.rb +12 -0
  538. data/test/models/sharded/tag.rb +11 -0
  539. data/test/models/sharded.rb +8 -0
  540. data/test/models/ship.rb +1 -1
  541. data/test/models/shipping_line.rb +11 -0
  542. data/test/models/subscriber.rb +1 -0
  543. data/test/models/subscription.rb +3 -1
  544. data/test/models/too_long_table_name.rb +5 -0
  545. data/test/models/topic.rb +3 -1
  546. data/test/models/traffic_light.rb +2 -2
  547. data/test/models/traffic_light_encrypted.rb +21 -0
  548. data/test/models/translation.rb +9 -0
  549. data/test/models/treasure.rb +1 -1
  550. data/test/models/tyre.rb +1 -1
  551. data/test/models/user.rb +16 -0
  552. data/test/models/user_with_invalid_relation.rb +28 -0
  553. data/test/models/uuid_comment.rb +5 -0
  554. data/test/models/uuid_entry.rb +5 -0
  555. data/test/models/uuid_message.rb +5 -0
  556. data/test/models/zine.rb +2 -1
  557. data/test/schema/mysql2_specific_schema.rb +26 -12
  558. data/test/schema/postgresql_specific_schema.rb +121 -13
  559. data/test/schema/schema.rb +361 -103
  560. data/test/schema/sqlite_specific_schema.rb +17 -6
  561. data/test/schema/trilogy_specific_schema.rb +96 -0
  562. data/test/support/adapter_helper.rb +104 -0
  563. data/test/support/async_helper.rb +15 -0
  564. data/test/support/config.rb +1 -1
  565. data/test/support/connection.rb +14 -2
  566. data/test/support/ddl_helper.rb +1 -1
  567. data/test/support/fake_adapter.rb +42 -0
  568. data/test/support/load_schema_helper.rb +22 -0
  569. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic.dump +0 -0
  570. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_6_1_topic_associations.dump +0 -0
  571. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic.dump +0 -0
  572. data/test/support/marshal_compatibility_fixtures/IBM_DB/rails_7_1_topic_associations.dump +0 -0
  573. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic.dump +0 -0
  574. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_6_1_topic_associations.dump +0 -0
  575. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic.dump +0 -0
  576. data/test/support/marshal_compatibility_fixtures/Mysql2/rails_7_1_topic_associations.dump +0 -0
  577. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic.dump +0 -0
  578. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_6_1_topic_associations.dump +0 -0
  579. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic.dump +0 -0
  580. data/test/support/marshal_compatibility_fixtures/PostgreSQL/rails_7_1_topic_associations.dump +0 -0
  581. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic.dump +0 -0
  582. data/test/support/marshal_compatibility_fixtures/SQLite/rails_6_1_topic_associations.dump +0 -0
  583. data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic.dump +0 -0
  584. data/test/support/marshal_compatibility_fixtures/SQLite/rails_7_1_topic_associations.dump +0 -0
  585. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic.dump +0 -0
  586. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_6_1_topic_associations.dump +0 -0
  587. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic.dump +0 -0
  588. data/test/support/marshal_compatibility_fixtures/Trilogy/rails_7_1_topic_associations.dump +0 -0
  589. data/test/support/schema_dumping_helper.rb +15 -9
  590. data/test/support/tools.rb +37 -0
  591. data/test/support/yaml_compatibility_fixtures/rails_4_1_no_symbol.yml +22 -0
  592. metadata +247 -15
@@ -4,6 +4,7 @@ require "cases/helper"
4
4
  require "models/minimalistic"
5
5
  require "models/developer"
6
6
  require "models/auto_id"
7
+ require "models/author"
7
8
  require "models/boolean"
8
9
  require "models/computer"
9
10
  require "models/topic"
@@ -13,21 +14,101 @@ require "models/reply"
13
14
  require "models/contact"
14
15
  require "models/keyboard"
15
16
  require "models/numeric_data"
17
+ require "models/cpk"
18
+ require "models/book_identifier"
16
19
 
17
20
  class AttributeMethodsTest < ActiveRecord::TestCase
18
21
  include InTimeZone
19
22
 
20
- fixtures :topics, :developers, :companies, :computers
23
+ class EpochTimestamp < ActiveRecord::Type::DateTime
24
+ def deserialize(time_or_int)
25
+ Time.at(time_or_int).utc if time_or_int
26
+ end
27
+
28
+ def serialize(time)
29
+ time.to_i if time
30
+ end
31
+ end
32
+
33
+ ActiveRecord::Type.register(:epoch_timestamp, EpochTimestamp)
34
+
35
+ fixtures :topics, :developers, :companies, :computers, :book_identifiers
21
36
 
22
37
  def setup
23
- @old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
38
+ @old_matchers = ActiveRecord::Base.send(:attribute_method_patterns).dup
24
39
  @target = Class.new(ActiveRecord::Base)
25
40
  @target.table_name = "topics"
26
41
  end
27
42
 
28
43
  teardown do
29
- ActiveRecord::Base.send(:attribute_method_matchers).clear
30
- ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
44
+ ActiveRecord::Base.send(:attribute_method_patterns).clear
45
+ ActiveRecord::Base.send(:attribute_method_patterns).concat(@old_matchers)
46
+ end
47
+
48
+ test "#id_value alias is defined if id column exist" do
49
+ new_topic_model = Class.new(ActiveRecord::Base) do
50
+ self.table_name = "topics"
51
+ end
52
+
53
+ new_topic_model.define_attribute_methods
54
+ assert_includes new_topic_model.attribute_names, "id"
55
+ assert_includes new_topic_model.attribute_aliases, "id_value"
56
+ end
57
+
58
+ test "#id_value alias is not defined if id_value column exist" do
59
+ new_book_identifier_model = Class.new(ActiveRecord::Base) do
60
+ self.table_name = "book_identifiers"
61
+ end
62
+
63
+ new_book_identifier_model.define_attribute_methods
64
+ assert_includes new_book_identifier_model.attribute_names, "id"
65
+ assert_includes new_book_identifier_model.attribute_names, "id_value"
66
+ if current_adapter?(:IBM_DBAdapter)
67
+ assert_equal "id", new_book_identifier_model.attribute_aliases["id_value"]
68
+ else
69
+ assert_empty new_book_identifier_model.attribute_aliases
70
+ end
71
+ end
72
+
73
+ test "aliasing `id` attribute allows reading the column value" do
74
+ topic = Topic.create(id: 123_456, title: "title").becomes(TitlePrimaryKeyTopic)
75
+
76
+ assert_equal(123_456, topic.id_value)
77
+ end
78
+
79
+ test "aliasing `id` attribute allows reading the column value for a CPK model" do
80
+ order = ::Cpk::Order.create(id: [1, 123_456])
81
+
82
+ assert_not_nil(order.id_value)
83
+ assert_equal(123_456, order.id_value)
84
+ end
85
+
86
+ test "#id_value alias returns the value in the id column, when id column exists" do
87
+ topic = Topic.new
88
+ assert_nil topic.id_value
89
+
90
+ topic = Topic.find(1)
91
+ assert_equal 1, topic.id_value
92
+ end
93
+
94
+ test "#id_value returns the value in the id_value column, when id_value column exists" do
95
+ book_identifier = BookIdentifier.new
96
+ assert_nil book_identifier.id_value
97
+
98
+ book_identifier = BookIdentifier.find(1)
99
+ assert_equal book_identifiers(:awdr_isbn13).id_value, book_identifier.id_value
100
+ end
101
+
102
+ test "#id_value alias is not defined if id column doesn't exist" do
103
+ keyboard = Keyboard.create!
104
+
105
+ assert_empty keyboard.attribute_aliases
106
+ end
107
+
108
+ test "#id_value alias returns id column only for composite primary key models" do
109
+ order = ::Cpk::Order.create(id: [1, 2])
110
+
111
+ assert_equal 2, order.id_value
31
112
  end
32
113
 
33
114
  test "attribute_for_inspect with a string" do
@@ -41,14 +122,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase
41
122
  test "attribute_for_inspect with a date" do
42
123
  t = topics(:first)
43
124
 
44
- assert_equal %("#{t.written_on.to_s(:inspect)}"), t.attribute_for_inspect(:written_on)
125
+ assert_equal %("#{t.written_on.to_fs(:inspect)}"), t.attribute_for_inspect(:written_on)
45
126
  end
46
127
 
47
128
  test "attribute_for_inspect with an array" do
48
129
  t = topics(:first)
49
- t.content = [Object.new]
50
-
51
- assert_match %r(\[#<Object:0x[0-9a-f]+>\]), t.attribute_for_inspect(:content)
130
+ t.content = ["some_value"]
131
+ assert_match %r(\["some_value"\]), t.attribute_for_inspect(:content)
52
132
  end
53
133
 
54
134
  test "attribute_for_inspect with a long array" do
@@ -97,8 +177,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase
97
177
 
98
178
  test "caching a nil primary key" do
99
179
  klass = Class.new(Minimalistic)
100
- assert_called(klass, :reset_primary_key, returns: nil) do
101
- 2.times { klass.primary_key }
180
+ klass.primary_key # warm once
181
+
182
+ assert_not_called(klass, :reset_primary_key) do
183
+ klass.primary_key
102
184
  end
103
185
  end
104
186
 
@@ -194,7 +276,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
194
276
  assert_equal category_attrs, category.attributes_before_type_cast
195
277
  end
196
278
 
197
- if current_adapter?(:Mysql2Adapter)
279
+ if current_adapter?(:Mysql2Adapter, :TrilogyAdapter)
198
280
  test "read attributes_before_type_cast on a boolean" do
199
281
  bool = Boolean.create!("value" => false)
200
282
  assert_equal 0, bool.reload.attributes_before_type_cast["value"]
@@ -216,7 +298,25 @@ class AttributeMethodsTest < ActiveRecord::TestCase
216
298
  end
217
299
  end
218
300
 
219
- test "read attributes_after_type_cast on a date" do
301
+ test "read_attribute_for_database" do
302
+ topic = Topic.new(content: ["ok"])
303
+ assert_equal "---\n- ok\n", topic.read_attribute_for_database("content")
304
+ end
305
+
306
+ test "read_attribute_for_database with aliased attribute" do
307
+ topic = Topic.new(title: "Hello")
308
+ assert_equal "Hello", topic.read_attribute_for_database(:heading)
309
+ end
310
+
311
+ test "attributes_for_database" do
312
+ topic = Topic.new
313
+ topic.content = { "one" => 1, "two" => 2 }
314
+
315
+ db_attributes = Topic.instantiate(topic.attributes_for_database).attributes
316
+ assert_equal topic.attributes, db_attributes
317
+ end
318
+
319
+ test "read attributes after type cast on a date" do
220
320
  tz = "Pacific Time (US & Canada)"
221
321
 
222
322
  in_time_zone tz do
@@ -266,7 +366,11 @@ class AttributeMethodsTest < ActiveRecord::TestCase
266
366
  end
267
367
 
268
368
  test "case-sensitive attributes hash" do
269
- assert_equal @loaded_fixtures["computers"]["workstation"].to_hash, Computer.first.attributes
369
+ expected = ["created_at", "developer", "extendedWarranty", "id", "system", "timezone", "updated_at"]
370
+ if current_adapter?(:IBM_DBAdapter)
371
+ expected[2] = "extendedwarranty"
372
+ end
373
+ assert_equal expected, Computer.first.attributes.keys.sort
270
374
  end
271
375
 
272
376
  test "attributes without primary key" do
@@ -279,16 +383,16 @@ class AttributeMethodsTest < ActiveRecord::TestCase
279
383
  end
280
384
 
281
385
  test "hashes are not mangled" do
282
- new_topic = { title: "New Topic", content: { key: "First value" } }
283
- new_topic_values = { title: "AnotherTopic", content: { key: "Second value" } }
386
+ new_topic = { "title" => "New Topic", "content" => { "key" => "First value" } }
387
+ new_topic_values = { "title" => "AnotherTopic", "content" => { "key" => "Second value" } }
284
388
 
285
389
  topic = Topic.new(new_topic)
286
- assert_equal new_topic[:title], topic.title
287
- assert_equal new_topic[:content], topic.content
390
+ assert_equal new_topic["title"], topic.title
391
+ assert_equal new_topic["content"], topic.content
288
392
 
289
393
  topic.attributes = new_topic_values
290
- assert_equal new_topic_values[:title], topic.title
291
- assert_equal new_topic_values[:content], topic.content
394
+ assert_equal new_topic_values["title"], topic.title
395
+ assert_equal new_topic_values["content"], topic.content
292
396
  end
293
397
 
294
398
  test "create through factory" do
@@ -323,6 +427,12 @@ class AttributeMethodsTest < ActiveRecord::TestCase
323
427
  topic = Topic.first
324
428
  assert_raises(ActiveModel::MissingAttributeError) { topic.update_columns(no_column_exists: "Hello!") }
325
429
  assert_raises(ActiveModel::UnknownAttributeError) { topic.update(no_column_exists: "Hello!") }
430
+ assert_raises(ActiveModel::MissingAttributeError) { topic[:no_column_exists] = "Hello!" }
431
+ end
432
+
433
+ test "write_attribute does not raise when the attribute isn't selected" do
434
+ topic = Topic.select(:id).first
435
+ assert_nothing_raised { topic[:title] = "Hello!" }
326
436
  end
327
437
 
328
438
  test "write_attribute allows writing to aliased attributes" do
@@ -351,12 +461,13 @@ class AttributeMethodsTest < ActiveRecord::TestCase
351
461
  assert_equal "Don't change the topic", topic[:heading]
352
462
  end
353
463
 
354
- test "read_attribute raises ActiveModel::MissingAttributeError when the attribute does not exist" do
355
- computer = Computer.select("id").first
356
- assert_raises(ActiveModel::MissingAttributeError) { computer[:developer] }
357
- assert_raises(ActiveModel::MissingAttributeError) { computer[:extendedwarranty] }
358
- assert_raises(ActiveModel::MissingAttributeError) { computer[:no_column_exists] = "Hello!" }
359
- assert_nothing_raised { computer[:developer] = "Hello!" }
464
+ test "read_attribute raises ActiveModel::MissingAttributeError when the attribute isn't selected" do
465
+ computer = Computer.select(:id, :extendedWarranty).first
466
+ assert_raises(ActiveModel::MissingAttributeError, match: /attribute 'developer' for Computer/) do
467
+ computer[:developer]
468
+ end
469
+ assert_nothing_raised { computer[:extendedWarranty] }
470
+ assert_nothing_raised { computer[:no_column_exists] }
360
471
  end
361
472
 
362
473
  test "read_attribute when false" do
@@ -370,9 +481,9 @@ class AttributeMethodsTest < ActiveRecord::TestCase
370
481
  test "read_attribute when true" do
371
482
  topic = topics(:first)
372
483
  topic.approved = true
373
- assert topic.approved?, "approved should be true"
484
+ assert_predicate topic, :approved?, "approved should be true"
374
485
  topic.approved = "true"
375
- assert topic.approved?, "approved should be true"
486
+ assert_predicate topic, :approved?, "approved should be true"
376
487
  end
377
488
 
378
489
  test "boolean attributes writing and reading" do
@@ -384,10 +495,10 @@ class AttributeMethodsTest < ActiveRecord::TestCase
384
495
  assert_not topic.approved?, "approved should be false"
385
496
 
386
497
  topic.approved = "true"
387
- assert topic.approved?, "approved should be true"
498
+ assert_predicate topic, :approved?, "approved should be true"
388
499
 
389
500
  topic.approved = "true"
390
- assert topic.approved?, "approved should be true"
501
+ assert_predicate topic, :approved?, "approved should be true"
391
502
  end
392
503
 
393
504
  test "overridden write_attribute" do
@@ -429,6 +540,16 @@ class AttributeMethodsTest < ActiveRecord::TestCase
429
540
  assert_equal "a", topic[:title]
430
541
  end
431
542
 
543
+ test "read overridden attribute with predicate respects override" do
544
+ topic = Topic.new
545
+
546
+ topic.approved = true
547
+
548
+ def topic.approved; false; end
549
+
550
+ assert_not topic.approved?, "overridden approved should be false"
551
+ end
552
+
432
553
  test "string attribute predicate" do
433
554
  [nil, "", " "].each do |value|
434
555
  assert_equal false, Topic.new(author_name: value).author_name?
@@ -509,7 +630,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
509
630
  assert_predicate topic, :user_defined_time?
510
631
  end
511
632
 
512
- test "user-defined json attribute predicate" do
633
+ test "user-defined JSON attribute predicate" do
513
634
  klass = Class.new(ActiveRecord::Base) do
514
635
  self.table_name = Topic.table_name
515
636
 
@@ -602,7 +723,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
602
723
  end
603
724
 
604
725
  test "should unserialize attributes for frozen records" do
605
- myobj = { value1: :value2 }
726
+ myobj = { "value1" => "value2" }
606
727
  topic = Topic.create(content: myobj)
607
728
  topic.freeze
608
729
  assert_equal myobj, topic.content
@@ -610,28 +731,23 @@ class AttributeMethodsTest < ActiveRecord::TestCase
610
731
 
611
732
  test "typecast attribute from select to false" do
612
733
  Topic.create(title: "Budget")
613
- # Oracle does not support boolean expressions in SELECT.
614
- if current_adapter?(:OracleAdapter) or current_adapter?(:IBM_DBAdapter)
615
- topic = Topic.all.merge!(select: "topics.*, 0 as is_test").first
616
- else
617
- topic = Topic.all.merge!(select: "topics.*, 1=2 as is_test").first
618
- end
734
+ topic = Topic.all.merge!(select: "topics.*, 1=2 as is_test").first
619
735
  assert_not_predicate topic, :is_test?
620
736
  end
621
737
 
622
738
  test "typecast attribute from select to true" do
623
739
  Topic.create(title: "Budget")
624
- # Oracle does not support boolean expressions in SELECT.
625
- if current_adapter?(:OracleAdapter) or current_adapter?(:IBM_DBAdapter)
626
- topic = Topic.all.merge!(select: "topics.*, 1 as is_test").first
740
+ select_sql = if current_adapter?(:IBM_DBAdapter)
741
+ "topics.*, CASE WHEN 2=2 THEN 1 ELSE 0 END as is_test"
627
742
  else
628
- topic = Topic.all.merge!(select: "topics.*, 2=2 as is_test").first
743
+ "topics.*, 2=2 as is_test"
629
744
  end
745
+ topic = Topic.all.merge!(select: select_sql).first
630
746
  assert_predicate topic, :is_test?
631
747
  end
632
748
 
633
- test "raises ActiveRecord::DangerousAttributeError when defining an AR method in a model" do
634
- %w(save create_or_update).each do |method|
749
+ test "raises ActiveRecord::DangerousAttributeError when defining an AR method or dangerous Object method in a model" do
750
+ %w(save create_or_update hash dup frozen?).each do |method|
635
751
  klass = Class.new(ActiveRecord::Base)
636
752
  klass.class_eval "def #{method}() 'defined #{method}' end"
637
753
  assert_raise ActiveRecord::DangerousAttributeError do
@@ -839,9 +955,67 @@ class AttributeMethodsTest < ActiveRecord::TestCase
839
955
  end
840
956
 
841
957
  test "time zone-aware attributes do not recurse infinitely on invalid values" do
958
+ model = new_topic_like_ar_class { }
959
+
960
+ type = model.type_for_attribute(:bonus_time)
961
+ assert_kind_of ActiveRecord::Type::Time, type
962
+
963
+ invalid_time = []
964
+ record = model.new(bonus_time: invalid_time)
965
+ assert_equal invalid_time, record.bonus_time
966
+
967
+ invalid_time = Time.current.utc.to_i
968
+ record = model.new(bonus_time: invalid_time)
969
+ assert_equal invalid_time, record.bonus_time
970
+
842
971
  in_time_zone "Pacific Time (US & Canada)" do
843
- record = @target.new(bonus_time: [])
844
- assert_nil record.bonus_time
972
+ model = new_topic_like_ar_class { }
973
+
974
+ type = model.type_for_attribute(:bonus_time)
975
+ assert_kind_of ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter, type
976
+
977
+ invalid_time = []
978
+ record = model.new(bonus_time: invalid_time)
979
+ assert_equal invalid_time, record.bonus_time
980
+
981
+ invalid_time = Time.current.utc.to_i
982
+ record = model.new(bonus_time: invalid_time)
983
+ assert_equal invalid_time, record.bonus_time
984
+ end
985
+ end
986
+
987
+ test "time zone-aware custom attributes" do
988
+ timestamp = Time.current.utc.to_i
989
+
990
+ model = Class.new(ActiveRecord::Base)
991
+ model.table_name = "minimalistics"
992
+
993
+ model.attribute :expires_at, :epoch_timestamp
994
+
995
+ type = model.type_for_attribute(:expires_at)
996
+ assert_kind_of EpochTimestamp, type
997
+
998
+ record_1 = model.create!(expires_at: timestamp)
999
+ assert_equal timestamp, record_1.expires_at.to_i
1000
+
1001
+ model.insert!({ expires_at: timestamp })
1002
+ record_2 = model.last
1003
+ assert_not_equal record_1, record_2
1004
+ assert_equal timestamp, record_2.expires_at.to_i
1005
+
1006
+ in_time_zone "Pacific Time (US & Canada)" do
1007
+ model.attribute :expires_at, :epoch_timestamp
1008
+
1009
+ type = model.type_for_attribute(:expires_at)
1010
+ assert_kind_of ActiveRecord::AttributeMethods::TimeZoneConversion::TimeZoneConverter, type
1011
+
1012
+ record_1 = model.create!(expires_at: timestamp)
1013
+ assert_equal timestamp, record_1.expires_at.to_i
1014
+
1015
+ model.insert!({ expires_at: timestamp })
1016
+ record_2 = model.last
1017
+ assert_not_equal record_1, record_2
1018
+ assert_equal timestamp, record_2.expires_at.to_i
845
1019
  end
846
1020
  end
847
1021
 
@@ -953,13 +1127,106 @@ class AttributeMethodsTest < ActiveRecord::TestCase
953
1127
  assert subklass.method_defined?(:id), "subklass is missing id method"
954
1128
  end
955
1129
 
1130
+ test "#undefine_attribute_methods undefines alias attribute methods" do
1131
+ topic_class = Class.new(ActiveRecord::Base) do
1132
+ self.table_name = "topics"
1133
+
1134
+ alias_attribute :subject_to_be_undefined, :title
1135
+ end
1136
+
1137
+ topic = topic_class.new(title: "New topic")
1138
+ assert_equal("New topic", topic.subject_to_be_undefined)
1139
+ assert_equal true, topic_class.method_defined?(:subject_to_be_undefined)
1140
+ topic_class.undefine_attribute_methods
1141
+ assert_equal false, topic_class.method_defined?(:subject_to_be_undefined)
1142
+
1143
+ topic.subject_to_be_undefined
1144
+ assert_equal true, topic_class.method_defined?(:subject_to_be_undefined)
1145
+
1146
+ topic_class.undefine_attribute_methods
1147
+ assert_equal true, topic.respond_to?(:subject_to_be_undefined)
1148
+ assert_equal true, topic_class.method_defined?(:subject_to_be_undefined)
1149
+ end
1150
+
1151
+ test "#define_attribute_methods brings back undefined aliases" do
1152
+ topic_class = Class.new(ActiveRecord::Base) do
1153
+ self.table_name = "topics"
1154
+
1155
+ alias_attribute :title_alias_to_be_undefined, :title
1156
+ end
1157
+
1158
+ topic = topic_class.new(title: "New topic")
1159
+ assert_equal("New topic", topic.title_alias_to_be_undefined)
1160
+ topic_class.undefine_attribute_methods
1161
+
1162
+ assert_equal false, topic_class.method_defined?(:title_alias_to_be_undefined)
1163
+
1164
+ topic_class.define_attribute_methods
1165
+
1166
+ assert_equal true, topic_class.method_defined?(:title_alias_to_be_undefined)
1167
+ assert_equal "New topic", topic.title_alias_to_be_undefined
1168
+ end
1169
+
956
1170
  test "define_attribute_method works with both symbol and string" do
957
1171
  klass = Class.new(ActiveRecord::Base)
1172
+ klass.table_name = "foo"
958
1173
 
959
1174
  assert_nothing_raised { klass.define_attribute_method(:foo) }
960
1175
  assert_nothing_raised { klass.define_attribute_method("bar") }
961
1176
  end
962
1177
 
1178
+ test "#method_missing define methods on the fly in a thread safe way" do
1179
+ skip "IBM DB adapter intermittently misses on-the-fly attribute methods under thread contention" if current_adapter?(:IBM_DBAdapter)
1180
+
1181
+ topic_class = Class.new(ActiveRecord::Base) do
1182
+ self.table_name = "topics"
1183
+ end
1184
+
1185
+ topic = topic_class.new(title: "New topic")
1186
+ topic_class.undefine_attribute_methods
1187
+ def topic.method_missing(...)
1188
+ sleep 0.1 # required to cause a race condition
1189
+ super
1190
+ end
1191
+
1192
+ threads = 5.times.map do
1193
+ Thread.new do
1194
+ assert_equal "New topic", topic.title
1195
+ end
1196
+ end
1197
+ threads.each(&:join)
1198
+ ensure
1199
+ threads&.each(&:kill)
1200
+ end
1201
+
1202
+ test "#method_missing define methods on the fly in a thread safe way, even when decorated" do
1203
+ skip "IBM DB adapter intermittently misses decorated on-the-fly attribute methods under thread contention" if current_adapter?(:IBM_DBAdapter)
1204
+
1205
+ topic_class = Class.new(ActiveRecord::Base) do
1206
+ self.table_name = "topics"
1207
+
1208
+ def title
1209
+ "title:#{super}"
1210
+ end
1211
+ end
1212
+
1213
+ topic = topic_class.new(title: "New topic")
1214
+ topic_class.undefine_attribute_methods
1215
+ def topic.method_missing(...)
1216
+ sleep 0.1 # required to cause a race condition
1217
+ super
1218
+ end
1219
+
1220
+ threads = 5.times.map do
1221
+ Thread.new do
1222
+ assert_equal "title:New topic", topic.title
1223
+ end
1224
+ end
1225
+ threads.each(&:join)
1226
+ ensure
1227
+ threads&.each(&:kill)
1228
+ end
1229
+
963
1230
  test "read_attribute with nil should not asplode" do
964
1231
  assert_nil Topic.new.read_attribute(nil)
965
1232
  end
@@ -1062,7 +1329,7 @@ class AttributeMethodsTest < ActiveRecord::TestCase
1062
1329
  model = @target.select("id").last!
1063
1330
 
1064
1331
  assert_equal ["id"], model.attribute_names
1065
- # Sanity check, make sure other columns exist.
1332
+ # Ensure other columns exist.
1066
1333
  assert_not_equal ["id"], @target.column_names
1067
1334
  end
1068
1335
 
@@ -1094,6 +1361,258 @@ class AttributeMethodsTest < ActiveRecord::TestCase
1094
1361
  assert_equal "abcd", model.read_attribute_before_type_cast("new_bank_balance")
1095
1362
  end
1096
1363
 
1364
+ ToBeLoadedFirst = Class.new(ActiveRecord::Base) do
1365
+ self.table_name = "topics"
1366
+ alias_attribute :subject, :author_name
1367
+ end
1368
+
1369
+ ToBeLoadedSecond = Class.new(ActiveRecord::Base) do
1370
+ self.table_name = "topics"
1371
+ alias_attribute :subject, :title
1372
+ end
1373
+
1374
+ test "#alias_attribute override methods defined in parent models" do
1375
+ parent_model = Class.new(ActiveRecord::Base) do
1376
+ self.abstract_class = true
1377
+
1378
+ def subject
1379
+ "Abstract Subject"
1380
+ end
1381
+ end
1382
+
1383
+ subclass = Class.new(parent_model) do
1384
+ self.table_name = "topics"
1385
+ alias_attribute :subject, :title
1386
+ end
1387
+
1388
+ obj = subclass.new
1389
+ obj.title = "hey"
1390
+ assert_equal("hey", obj.subject)
1391
+ end
1392
+
1393
+ test "aliases to the same attribute name do not conflict with each other" do
1394
+ first_model_object = ToBeLoadedFirst.new(author_name: "author 1")
1395
+ assert_equal("author 1", first_model_object.subject)
1396
+ assert_equal([nil, "author 1"], first_model_object.subject_change)
1397
+ second_model_object = ToBeLoadedSecond.new(title: "foo")
1398
+ assert_equal("foo", second_model_object.subject)
1399
+ assert_equal([nil, "foo"], second_model_object.subject_change)
1400
+ end
1401
+
1402
+ test "#alias_attribute with an overridden original method does not use the overridden original method" do
1403
+ class_with_deprecated_alias_attribute_behavior = Class.new(ActiveRecord::Base) do
1404
+ self.table_name = "topics"
1405
+ alias_attribute :subject, :title
1406
+
1407
+ def title_was
1408
+ "overridden_title_was"
1409
+ end
1410
+ end
1411
+
1412
+ obj = class_with_deprecated_alias_attribute_behavior.new
1413
+ obj.title = "hey"
1414
+ assert_equal("hey", obj.subject)
1415
+ assert_nil(obj.subject_was)
1416
+ end
1417
+
1418
+ test "#alias_attribute with an overridden original method from a module does not use the overridden original method" do
1419
+ title_was_override = Module.new do
1420
+ def title_was
1421
+ "overridden_title_was"
1422
+ end
1423
+ end
1424
+
1425
+ class_with_deprecated_alias_attribute_behavior_from_module = Class.new(ActiveRecord::Base) do
1426
+ self.table_name = "topics"
1427
+ include title_was_override
1428
+ alias_attribute :subject, :title
1429
+ end
1430
+
1431
+ obj = class_with_deprecated_alias_attribute_behavior_from_module.new
1432
+ obj.title = "hey"
1433
+ assert_equal("hey", obj.subject)
1434
+ assert_nil(obj.subject_was)
1435
+ end
1436
+
1437
+ ClassWithDeprecatedAliasAttributeBehaviorResolved = Class.new(ActiveRecord::Base) do
1438
+ self.table_name = "topics"
1439
+ alias_attribute :subject, :title
1440
+
1441
+ def title_was
1442
+ "overridden_title_was"
1443
+ end
1444
+
1445
+ def subject_was
1446
+ "overridden_subject_was"
1447
+ end
1448
+ end
1449
+
1450
+ test "#alias_attribute with an overridden original method along with an overridden alias method uses the overridden alias method" do
1451
+ obj = ClassWithDeprecatedAliasAttributeBehaviorResolved.new
1452
+ obj.title = "hey"
1453
+ assert_equal("hey", obj.subject)
1454
+ assert_equal("overridden_subject_was", obj.subject_was)
1455
+ end
1456
+
1457
+ test "#alias_attribute with an overridden original method along with an overridden alias method in a parent class uses the overridden alias method" do
1458
+ child_with_deprecated_behavior_resolved = Class.new(ClassWithDeprecatedAliasAttributeBehaviorResolved)
1459
+
1460
+ obj = child_with_deprecated_behavior_resolved.new
1461
+ obj.title = "hey"
1462
+ assert_equal("hey", obj.subject)
1463
+ assert_equal("overridden_subject_was", obj.subject_was)
1464
+ end
1465
+
1466
+ ParentWithAlias = Class.new(ActiveRecord::Base) do
1467
+ self.table_name = "topics"
1468
+ alias_attribute :parents_subject, :title
1469
+ end
1470
+
1471
+ AbstractClassInBetween = Class.new(ParentWithAlias) do
1472
+ self.abstract_class = true
1473
+ alias_attribute :parents_subject, :title
1474
+ end
1475
+
1476
+ ChildWithAnAliasFromAbstractClass = Class.new(AbstractClassInBetween) do
1477
+ end
1478
+
1479
+ test "#alias_attribute with the same alias as parent doesn't issue a deprecation" do
1480
+ ParentWithAlias.new # eagerly generate parents alias methods
1481
+ obj = assert_not_deprecated(ActiveRecord.deprecator) do
1482
+ ChildWithAnAliasFromAbstractClass.new
1483
+ end
1484
+ obj.title = "hey"
1485
+ assert_equal("hey", obj.parents_subject)
1486
+ end
1487
+
1488
+ test "#alias_attribute method on an abstract class is available on subclasses" do
1489
+ superclass = Class.new(ActiveRecord::Base) do
1490
+ self.abstract_class = true
1491
+ alias_attribute :id_value, :id
1492
+ end
1493
+ subclass = Class.new(superclass) { self.table_name = "topics" }
1494
+
1495
+ object = subclass.build(id: 123_456)
1496
+
1497
+ assert_equal 123_456, object.id_value
1498
+ end
1499
+
1500
+ test "#alias_attribute with an _in_database method issues raises an error" do
1501
+ class_with_generated_attribute_method_target = Class.new(ActiveRecord::Base) do
1502
+ def self.name
1503
+ "ClassWithGeneratedAttributeMethodTarget"
1504
+ end
1505
+
1506
+ self.table_name = "topics"
1507
+
1508
+ alias_attribute :saved_title, :title_in_database
1509
+ end
1510
+
1511
+ message = <<~MESSAGE.squish
1512
+ ClassWithGeneratedAttributeMethodTarget model aliases
1513
+ `title_in_database`, but `title_in_database` is not an attribute.
1514
+ Use `alias_method :saved_title, :title_in_database` or define the method manually.
1515
+ MESSAGE
1516
+
1517
+ error = assert_raises(ArgumentError) do
1518
+ class_with_generated_attribute_method_target.new
1519
+ end
1520
+
1521
+ assert_equal message, error.message
1522
+ end
1523
+
1524
+ test "#alias_attribute with enum method raises an error" do
1525
+ class_with_enum_method_target = Class.new(ActiveRecord::Base) do
1526
+ def self.name
1527
+ "ClassWithEnumMethodTarget"
1528
+ end
1529
+
1530
+ self.table_name = "books"
1531
+
1532
+ attribute :status, :string
1533
+
1534
+ enum :status, {
1535
+ pending: "0",
1536
+ completed: "1",
1537
+ }
1538
+ alias_attribute :is_pending?, :pending?
1539
+ end
1540
+
1541
+ message = <<~MESSAGE.squish
1542
+ ClassWithEnumMethodTarget model aliases `pending?`, but `pending?` is not an attribute. Use `alias_method :is_pending?, :pending?` or define the method manually.
1543
+ MESSAGE
1544
+
1545
+ error = assert_raises(ArgumentError) do
1546
+ class_with_enum_method_target.new
1547
+ end
1548
+ assert_equal message, error.message
1549
+ end
1550
+
1551
+ test "#alias_attribute with an association method raises an error" do
1552
+ class_with_association_target = Class.new(ActiveRecord::Base) do
1553
+ def self.name
1554
+ "ClassWithAssociationTarget"
1555
+ end
1556
+
1557
+ self.table_name = "books"
1558
+
1559
+ belongs_to :author
1560
+
1561
+ alias_attribute :written_by, :author
1562
+ end
1563
+
1564
+ message = <<~MESSAGE.squish
1565
+ ClassWithAssociationTarget model aliases `author`, but `author` is not an attribute. Use `alias_method :written_by, :author` or define the method manually.
1566
+ MESSAGE
1567
+
1568
+ error = assert_raises(ArgumentError) do
1569
+ class_with_association_target.new
1570
+ end
1571
+ assert_equal message, error.message
1572
+ end
1573
+
1574
+ test "#alias_attribute method on a STI class is available on subclasses" do
1575
+ superclass = Class.new(ActiveRecord::Base) do
1576
+ self.table_name = "comments"
1577
+ alias_attribute :text, :body
1578
+ end
1579
+
1580
+ subclass = Class.new(superclass) do
1581
+ self.abstract_class = true
1582
+ end
1583
+
1584
+ subsubclass = Class.new(subclass)
1585
+
1586
+ comment = subsubclass.build(body: "Text")
1587
+ assert_equal "Text", comment.text
1588
+ end
1589
+
1590
+ test "#alias_attribute with a manually defined method raises an error" do
1591
+ class_with_aliased_manually_defined_method = Class.new(ActiveRecord::Base) do
1592
+ def self.name
1593
+ "ClassWithAliasedManuallyDefinedMethod"
1594
+ end
1595
+
1596
+ self.table_name = "books"
1597
+
1598
+ alias_attribute :print, :publish
1599
+
1600
+ def publish
1601
+ "Publishing!"
1602
+ end
1603
+ end
1604
+
1605
+ message = <<~MESSAGE.squish
1606
+ ClassWithAliasedManuallyDefinedMethod model aliases `publish`, but `publish` is not an attribute.
1607
+ Use `alias_method :print, :publish` or define the method manually.
1608
+ MESSAGE
1609
+
1610
+ error = assert_raises(ArgumentError) do
1611
+ class_with_aliased_manually_defined_method.new
1612
+ end
1613
+ assert_equal message, error.message
1614
+ end
1615
+
1097
1616
  private
1098
1617
  def new_topic_like_ar_class(&block)
1099
1618
  klass = Class.new(ActiveRecord::Base) do