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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (586) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +4 -0
  3. data/LICENSE +1 -1
  4. data/MANIFEST +14 -14
  5. data/ParameterizedQueries README +6 -6
  6. data/README +208 -225
  7. data/ext/Makefile.nt32 +181 -181
  8. data/ext/Makefile.nt32.191 +212 -212
  9. data/ext/extconf.rb +291 -291
  10. data/ext/ibm_db.c +11887 -11887
  11. data/ext/ruby_ibm_db.h +241 -241
  12. data/ext/ruby_ibm_db_cli.c +866 -866
  13. data/ext/ruby_ibm_db_cli.h +500 -500
  14. data/init.rb +41 -41
  15. data/lib/IBM_DB.rb +27 -27
  16. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3452 -3177
  17. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -2
  18. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  19. data/lib/mswin32/ibm_db.rb +91 -123
  20. data/lib/mswin32/rb2x/i386/ibm_db.so +0 -0
  21. data/test/active_record/connection_adapters/fake_adapter.rb +49 -46
  22. data/test/assets/example.log +1 -1
  23. data/test/assets/test.txt +1 -1
  24. data/test/cases/adapter_test.rb +351 -276
  25. data/test/cases/adapters/mysql2/active_schema_test.rb +193 -0
  26. data/test/cases/adapters/mysql2/bind_parameter_test.rb +50 -0
  27. data/test/cases/adapters/mysql2/boolean_test.rb +100 -0
  28. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +63 -0
  29. data/test/cases/adapters/mysql2/charset_collation_test.rb +54 -0
  30. data/test/cases/adapters/mysql2/connection_test.rb +210 -0
  31. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +45 -0
  32. data/test/cases/adapters/mysql2/enum_test.rb +26 -0
  33. data/test/cases/adapters/mysql2/explain_test.rb +21 -0
  34. data/test/cases/adapters/mysql2/json_test.rb +195 -0
  35. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +83 -0
  36. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  37. data/test/cases/adapters/mysql2/schema_migrations_test.rb +59 -0
  38. data/test/cases/adapters/mysql2/schema_test.rb +126 -0
  39. data/test/cases/adapters/mysql2/sp_test.rb +36 -0
  40. data/test/cases/adapters/mysql2/sql_types_test.rb +14 -0
  41. data/test/cases/adapters/mysql2/table_options_test.rb +42 -0
  42. data/test/cases/adapters/mysql2/unsigned_type_test.rb +66 -0
  43. data/test/cases/adapters/postgresql/active_schema_test.rb +98 -0
  44. data/test/cases/adapters/postgresql/array_test.rb +339 -0
  45. data/test/cases/adapters/postgresql/bit_string_test.rb +82 -0
  46. data/test/cases/adapters/postgresql/bytea_test.rb +134 -0
  47. data/test/cases/adapters/postgresql/case_insensitive_test.rb +26 -0
  48. data/test/cases/adapters/postgresql/change_schema_test.rb +38 -0
  49. data/test/cases/adapters/postgresql/cidr_test.rb +25 -0
  50. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  51. data/test/cases/adapters/postgresql/collation_test.rb +53 -0
  52. data/test/cases/adapters/postgresql/composite_test.rb +132 -0
  53. data/test/cases/adapters/postgresql/connection_test.rb +257 -0
  54. data/test/cases/adapters/postgresql/datatype_test.rb +92 -0
  55. data/test/cases/adapters/postgresql/domain_test.rb +47 -0
  56. data/test/cases/adapters/postgresql/enum_test.rb +91 -0
  57. data/test/cases/adapters/postgresql/explain_test.rb +20 -0
  58. data/test/cases/adapters/postgresql/extension_migration_test.rb +63 -0
  59. data/test/cases/adapters/postgresql/full_text_test.rb +44 -0
  60. data/test/cases/adapters/postgresql/geometric_test.rb +378 -0
  61. data/test/cases/adapters/postgresql/hstore_test.rb +382 -0
  62. data/test/cases/adapters/postgresql/infinity_test.rb +69 -0
  63. data/test/cases/adapters/postgresql/integer_test.rb +25 -0
  64. data/test/cases/adapters/postgresql/json_test.rb +237 -0
  65. data/test/cases/adapters/postgresql/ltree_test.rb +53 -0
  66. data/test/cases/adapters/postgresql/money_test.rb +96 -0
  67. data/test/cases/adapters/postgresql/network_test.rb +94 -0
  68. data/test/cases/adapters/postgresql/numbers_test.rb +49 -0
  69. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +405 -0
  70. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  71. data/test/cases/adapters/postgresql/quoting_test.rb +44 -0
  72. data/test/cases/adapters/postgresql/range_test.rb +343 -0
  73. data/test/cases/adapters/postgresql/referential_integrity_test.rb +111 -0
  74. data/test/cases/adapters/postgresql/rename_table_test.rb +34 -0
  75. data/test/cases/adapters/postgresql/schema_authorization_test.rb +119 -0
  76. data/test/cases/adapters/postgresql/schema_test.rb +597 -0
  77. data/test/cases/adapters/postgresql/serial_test.rb +154 -0
  78. data/test/cases/adapters/postgresql/statement_pool_test.rb +41 -0
  79. data/test/cases/adapters/postgresql/timestamp_test.rb +90 -0
  80. data/test/cases/adapters/postgresql/type_lookup_test.rb +33 -0
  81. data/test/cases/adapters/postgresql/utils_test.rb +62 -0
  82. data/test/cases/adapters/postgresql/uuid_test.rb +294 -0
  83. data/test/cases/adapters/postgresql/xml_test.rb +54 -0
  84. data/test/cases/adapters/sqlite3/collation_test.rb +53 -0
  85. data/test/cases/adapters/sqlite3/copy_table_test.rb +98 -0
  86. data/test/cases/adapters/sqlite3/explain_test.rb +21 -0
  87. data/test/cases/adapters/sqlite3/quoting_test.rb +101 -0
  88. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +441 -0
  89. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  90. data/test/cases/adapters/sqlite3/statement_pool_test.rb +20 -0
  91. data/test/cases/aggregations_test.rb +168 -158
  92. data/test/cases/ar_schema_test.rb +146 -161
  93. data/test/cases/associations/association_scope_test.rb +16 -21
  94. data/test/cases/associations/belongs_to_associations_test.rb +1141 -1029
  95. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +41 -0
  96. data/test/cases/associations/callbacks_test.rb +190 -192
  97. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
  98. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
  99. data/test/cases/associations/eager_load_nested_include_test.rb +126 -128
  100. data/test/cases/associations/eager_singularization_test.rb +148 -148
  101. data/test/cases/associations/eager_test.rb +1514 -1429
  102. data/test/cases/associations/extension_test.rb +87 -82
  103. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1004 -972
  104. data/test/cases/associations/has_many_associations_test.rb +2501 -2182
  105. data/test/cases/associations/has_many_through_associations_test.rb +1271 -1204
  106. data/test/cases/associations/has_one_associations_test.rb +707 -610
  107. data/test/cases/associations/has_one_through_associations_test.rb +383 -380
  108. data/test/cases/associations/inner_join_association_test.rb +139 -139
  109. data/test/cases/associations/inverse_associations_test.rb +733 -706
  110. data/test/cases/associations/join_model_test.rb +777 -754
  111. data/test/cases/associations/left_outer_join_association_test.rb +88 -0
  112. data/test/cases/associations/nested_through_associations_test.rb +579 -579
  113. data/test/cases/associations/required_test.rb +102 -82
  114. data/test/cases/associations_test.rb +385 -380
  115. data/test/cases/attribute_decorators_test.rb +125 -125
  116. data/test/cases/attribute_methods/read_test.rb +60 -60
  117. data/test/cases/attribute_methods_test.rb +1009 -952
  118. data/test/cases/attribute_set_test.rb +270 -210
  119. data/test/cases/attribute_test.rb +246 -180
  120. data/test/cases/attributes_test.rb +253 -136
  121. data/test/cases/autosave_association_test.rb +1708 -1595
  122. data/test/cases/base_test.rb +1713 -1664
  123. data/test/cases/batches_test.rb +489 -212
  124. data/test/cases/binary_test.rb +44 -52
  125. data/test/cases/bind_parameter_test.rb +110 -100
  126. data/test/cases/cache_key_test.rb +25 -0
  127. data/test/cases/calculations_test.rb +798 -646
  128. data/test/cases/callbacks_test.rb +636 -543
  129. data/test/cases/clone_test.rb +40 -40
  130. data/test/cases/coders/json_test.rb +15 -0
  131. data/test/cases/coders/yaml_column_test.rb +63 -63
  132. data/test/cases/collection_cache_key_test.rb +115 -0
  133. data/test/cases/column_alias_test.rb +17 -17
  134. data/test/cases/column_definition_test.rb +92 -123
  135. data/test/cases/comment_test.rb +143 -0
  136. data/test/cases/connection_adapters/adapter_leasing_test.rb +56 -54
  137. data/test/cases/connection_adapters/connection_handler_test.rb +160 -53
  138. data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
  139. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +255 -293
  140. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +69 -65
  141. data/test/cases/connection_adapters/quoting_test.rb +13 -13
  142. data/test/cases/connection_adapters/schema_cache_test.rb +61 -56
  143. data/test/cases/connection_adapters/type_lookup_test.rb +118 -110
  144. data/test/cases/connection_management_test.rb +112 -122
  145. data/test/cases/connection_pool_test.rb +521 -346
  146. data/test/cases/connection_specification/resolver_test.rb +131 -116
  147. data/test/cases/core_test.rb +112 -112
  148. data/test/cases/counter_cache_test.rb +214 -209
  149. data/test/cases/custom_locking_test.rb +17 -17
  150. data/test/cases/database_statements_test.rb +34 -19
  151. data/test/cases/{invalid_date_test.rb → date_test.rb} +44 -32
  152. data/test/cases/date_time_precision_test.rb +106 -0
  153. data/test/cases/date_time_test.rb +61 -61
  154. data/test/cases/defaults_test.rb +218 -223
  155. data/test/cases/dirty_test.rb +763 -785
  156. data/test/cases/disconnected_test.rb +30 -28
  157. data/test/cases/dup_test.rb +157 -157
  158. data/test/cases/enum_test.rb +444 -290
  159. data/test/cases/errors_test.rb +16 -0
  160. data/test/cases/explain_subscriber_test.rb +64 -64
  161. data/test/cases/explain_test.rb +87 -76
  162. data/test/cases/finder_respond_to_test.rb +60 -60
  163. data/test/cases/finder_test.rb +1294 -1169
  164. data/test/cases/fixture_set/file_test.rb +156 -138
  165. data/test/cases/fixtures_test.rb +988 -908
  166. data/test/cases/forbidden_attributes_protection_test.rb +165 -99
  167. data/test/cases/habtm_destroy_order_test.rb +61 -61
  168. data/test/cases/helper.rb +204 -210
  169. data/test/cases/hot_compatibility_test.rb +142 -54
  170. data/test/cases/i18n_test.rb +45 -45
  171. data/test/cases/inheritance_test.rb +606 -375
  172. data/test/cases/integration_test.rb +155 -139
  173. data/test/cases/invalid_connection_test.rb +24 -22
  174. data/test/cases/invertible_migration_test.rb +387 -295
  175. data/test/cases/json_serialization_test.rb +311 -302
  176. data/test/cases/locking_test.rb +493 -477
  177. data/test/cases/log_subscriber_test.rb +225 -136
  178. data/test/cases/migration/change_schema_test.rb +458 -512
  179. data/test/cases/migration/change_table_test.rb +256 -224
  180. data/test/cases/migration/column_attributes_test.rb +176 -192
  181. data/test/cases/migration/column_positioning_test.rb +56 -56
  182. data/test/cases/migration/columns_test.rb +310 -304
  183. data/test/cases/migration/command_recorder_test.rb +350 -305
  184. data/test/cases/migration/compatibility_test.rb +118 -0
  185. data/test/cases/migration/create_join_table_test.rb +157 -148
  186. data/test/cases/migration/foreign_key_test.rb +360 -328
  187. data/test/cases/migration/helper.rb +39 -39
  188. data/test/cases/migration/index_test.rb +218 -216
  189. data/test/cases/migration/logger_test.rb +36 -36
  190. data/test/cases/migration/pending_migrations_test.rb +52 -53
  191. data/test/cases/migration/references_foreign_key_test.rb +216 -169
  192. data/test/cases/migration/references_index_test.rb +101 -101
  193. data/test/cases/migration/references_statements_test.rb +136 -116
  194. data/test/cases/migration/rename_table_test.rb +93 -93
  195. data/test/cases/migration_test.rb +1157 -959
  196. data/test/cases/migrator_test.rb +470 -388
  197. data/test/cases/mixin_test.rb +68 -70
  198. data/test/cases/modules_test.rb +172 -173
  199. data/test/cases/multiparameter_attributes_test.rb +372 -350
  200. data/test/cases/multiple_db_test.rb +122 -115
  201. data/test/cases/nested_attributes_test.rb +1098 -1070
  202. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
  203. data/test/cases/persistence_test.rb +1001 -909
  204. data/test/cases/pooled_connections_test.rb +81 -81
  205. data/test/cases/primary_keys_test.rb +376 -237
  206. data/test/cases/query_cache_test.rb +446 -326
  207. data/test/cases/quoting_test.rb +202 -156
  208. data/test/cases/readonly_test.rb +119 -118
  209. data/test/cases/reaper_test.rb +85 -85
  210. data/test/cases/reflection_test.rb +509 -463
  211. data/test/cases/relation/delegation_test.rb +63 -68
  212. data/test/cases/relation/merging_test.rb +157 -161
  213. data/test/cases/relation/mutation_test.rb +183 -165
  214. data/test/cases/relation/or_test.rb +92 -0
  215. data/test/cases/relation/predicate_builder_test.rb +16 -14
  216. data/test/cases/relation/record_fetch_warning_test.rb +40 -0
  217. data/test/cases/relation/where_chain_test.rb +105 -181
  218. data/test/cases/relation/where_clause_test.rb +182 -0
  219. data/test/cases/relation/where_test.rb +322 -300
  220. data/test/cases/relation_test.rb +328 -319
  221. data/test/cases/relations_test.rb +2026 -1815
  222. data/test/cases/reload_models_test.rb +22 -22
  223. data/test/cases/result_test.rb +90 -80
  224. data/test/cases/sanitize_test.rb +176 -83
  225. data/test/cases/schema_dumper_test.rb +457 -463
  226. data/test/cases/schema_loading_test.rb +52 -0
  227. data/test/cases/scoping/default_scoping_test.rb +528 -454
  228. data/test/cases/scoping/named_scoping_test.rb +561 -524
  229. data/test/cases/scoping/relation_scoping_test.rb +400 -357
  230. data/test/cases/secure_token_test.rb +32 -0
  231. data/test/cases/serialization_test.rb +104 -104
  232. data/test/cases/serialized_attribute_test.rb +364 -277
  233. data/test/cases/statement_cache_test.rb +136 -98
  234. data/test/cases/store_test.rb +195 -194
  235. data/test/cases/suppressor_test.rb +63 -0
  236. data/test/cases/tasks/database_tasks_test.rb +462 -398
  237. data/test/cases/tasks/mysql_rake_test.rb +345 -324
  238. data/test/cases/tasks/postgresql_rake_test.rb +304 -250
  239. data/test/cases/tasks/sqlite_rake_test.rb +220 -193
  240. data/test/cases/test_case.rb +131 -123
  241. data/test/cases/test_fixtures_test.rb +36 -0
  242. data/test/cases/time_precision_test.rb +102 -0
  243. data/test/cases/timestamp_test.rb +501 -467
  244. data/test/cases/touch_later_test.rb +121 -0
  245. data/test/cases/transaction_callbacks_test.rb +518 -452
  246. data/test/cases/transaction_isolation_test.rb +106 -106
  247. data/test/cases/transactions_test.rb +834 -817
  248. data/test/cases/type/adapter_specific_registry_test.rb +133 -0
  249. data/test/cases/type/date_time_test.rb +14 -0
  250. data/test/cases/type/integer_test.rb +27 -121
  251. data/test/cases/type/string_test.rb +22 -36
  252. data/test/cases/type/type_map_test.rb +177 -177
  253. data/test/cases/type_test.rb +39 -0
  254. data/test/cases/types_test.rb +24 -141
  255. data/test/cases/unconnected_test.rb +33 -33
  256. data/test/cases/validations/absence_validation_test.rb +73 -0
  257. data/test/cases/validations/association_validation_test.rb +97 -86
  258. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
  259. data/test/cases/validations/i18n_validation_test.rb +86 -90
  260. data/test/cases/validations/length_validation_test.rb +79 -47
  261. data/test/cases/validations/presence_validation_test.rb +103 -68
  262. data/test/cases/validations/uniqueness_validation_test.rb +548 -457
  263. data/test/cases/validations_repair_helper.rb +19 -23
  264. data/test/cases/validations_test.rb +194 -165
  265. data/test/cases/view_test.rb +216 -119
  266. data/test/cases/yaml_serialization_test.rb +121 -126
  267. data/test/config.example.yml +97 -0
  268. data/test/config.rb +5 -5
  269. data/test/fixtures/accounts.yml +29 -29
  270. data/test/fixtures/admin/accounts.yml +2 -2
  271. data/test/fixtures/admin/users.yml +10 -10
  272. data/test/fixtures/author_addresses.original +11 -0
  273. data/test/fixtures/author_addresses.yml +17 -17
  274. data/test/fixtures/author_favorites.yml +3 -3
  275. data/test/fixtures/authors.original +17 -0
  276. data/test/fixtures/authors.yml +23 -23
  277. data/test/fixtures/bad_posts.yml +9 -0
  278. data/test/fixtures/binaries.yml +133 -133
  279. data/test/fixtures/books.yml +31 -11
  280. data/test/fixtures/bulbs.yml +5 -5
  281. data/test/fixtures/cars.yml +9 -9
  282. data/test/fixtures/categories.yml +19 -19
  283. data/test/fixtures/categories/special_categories.yml +9 -9
  284. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
  285. data/test/fixtures/categories_ordered.yml +7 -7
  286. data/test/fixtures/categories_posts.yml +31 -31
  287. data/test/fixtures/categorizations.yml +23 -23
  288. data/test/fixtures/clubs.yml +8 -8
  289. data/test/fixtures/collections.yml +3 -3
  290. data/test/fixtures/colleges.yml +3 -3
  291. data/test/fixtures/comments.yml +65 -65
  292. data/test/fixtures/companies.yml +67 -67
  293. data/test/fixtures/computers.yml +10 -10
  294. data/test/fixtures/content.yml +3 -0
  295. data/test/fixtures/content_positions.yml +3 -0
  296. data/test/fixtures/courses.yml +8 -8
  297. data/test/fixtures/customers.yml +25 -25
  298. data/test/fixtures/dashboards.yml +6 -6
  299. data/test/fixtures/dead_parrots.yml +5 -0
  300. data/test/fixtures/developers.yml +22 -22
  301. data/test/fixtures/developers_projects.yml +16 -16
  302. data/test/fixtures/dog_lovers.yml +7 -7
  303. data/test/fixtures/dogs.yml +4 -4
  304. data/test/fixtures/doubloons.yml +3 -3
  305. data/test/fixtures/edges.yml +5 -5
  306. data/test/fixtures/entrants.yml +14 -14
  307. data/test/fixtures/essays.yml +6 -6
  308. data/test/fixtures/faces.yml +11 -11
  309. data/test/fixtures/fk_test_has_fk.yml +3 -3
  310. data/test/fixtures/fk_test_has_pk.yml +1 -1
  311. data/test/fixtures/friendships.yml +4 -4
  312. data/test/fixtures/funny_jokes.yml +10 -10
  313. data/test/fixtures/interests.yml +33 -33
  314. data/test/fixtures/items.yml +3 -3
  315. data/test/fixtures/jobs.yml +7 -7
  316. data/test/fixtures/legacy_things.yml +3 -3
  317. data/test/fixtures/live_parrots.yml +4 -0
  318. data/test/fixtures/mateys.yml +4 -4
  319. data/test/fixtures/member_details.yml +8 -8
  320. data/test/fixtures/member_types.yml +6 -6
  321. data/test/fixtures/members.yml +11 -11
  322. data/test/fixtures/memberships.yml +34 -34
  323. data/test/fixtures/men.yml +5 -5
  324. data/test/fixtures/minimalistics.yml +2 -2
  325. data/test/fixtures/minivans.yml +5 -5
  326. data/test/fixtures/mixed_case_monkeys.yml +6 -6
  327. data/test/fixtures/mixins.yml +29 -29
  328. data/test/fixtures/movies.yml +7 -7
  329. data/test/fixtures/naked/yml/accounts.yml +1 -1
  330. data/test/fixtures/naked/yml/companies.yml +1 -1
  331. data/test/fixtures/naked/yml/courses.yml +1 -1
  332. data/test/fixtures/naked/yml/parrots.yml +2 -0
  333. data/test/fixtures/naked/yml/trees.yml +3 -0
  334. data/test/fixtures/nodes.yml +29 -0
  335. data/test/fixtures/organizations.yml +5 -5
  336. data/test/fixtures/other_comments.yml +6 -0
  337. data/test/fixtures/other_dogs.yml +2 -0
  338. data/test/fixtures/other_posts.yml +7 -0
  339. data/test/fixtures/other_topics.yml +42 -42
  340. data/test/fixtures/owners.yml +9 -9
  341. data/test/fixtures/parrots.yml +27 -27
  342. data/test/fixtures/parrots_pirates.yml +7 -7
  343. data/test/fixtures/people.yml +24 -24
  344. data/test/fixtures/peoples_treasures.yml +3 -3
  345. data/test/fixtures/pets.yml +19 -19
  346. data/test/fixtures/pirates.yml +15 -12
  347. data/test/fixtures/posts.yml +80 -80
  348. data/test/fixtures/price_estimates.yml +16 -7
  349. data/test/fixtures/products.yml +4 -4
  350. data/test/fixtures/projects.yml +7 -7
  351. data/test/fixtures/ratings.yml +14 -14
  352. data/test/fixtures/readers.yml +11 -11
  353. data/test/fixtures/references.yml +17 -17
  354. data/test/fixtures/reserved_words/distinct.yml +5 -5
  355. data/test/fixtures/reserved_words/distinct_select.yml +11 -11
  356. data/test/fixtures/reserved_words/group.yml +14 -14
  357. data/test/fixtures/reserved_words/select.yml +8 -8
  358. data/test/fixtures/reserved_words/values.yml +7 -7
  359. data/test/fixtures/ships.yml +6 -6
  360. data/test/fixtures/speedometers.yml +8 -8
  361. data/test/fixtures/sponsors.yml +12 -12
  362. data/test/fixtures/string_key_objects.yml +7 -7
  363. data/test/fixtures/subscribers.yml +10 -10
  364. data/test/fixtures/subscriptions.yml +12 -12
  365. data/test/fixtures/taggings.yml +78 -78
  366. data/test/fixtures/tags.yml +11 -11
  367. data/test/fixtures/tasks.yml +7 -7
  368. data/test/fixtures/teapots.yml +3 -3
  369. data/test/fixtures/to_be_linked/accounts.yml +2 -2
  370. data/test/fixtures/to_be_linked/users.yml +10 -10
  371. data/test/fixtures/topics.yml +49 -49
  372. data/test/fixtures/toys.yml +14 -14
  373. data/test/fixtures/traffic_lights.yml +9 -9
  374. data/test/fixtures/treasures.yml +10 -10
  375. data/test/fixtures/trees.yml +3 -0
  376. data/test/fixtures/uuid_children.yml +3 -3
  377. data/test/fixtures/uuid_parents.yml +2 -2
  378. data/test/fixtures/variants.yml +4 -4
  379. data/test/fixtures/vegetables.yml +19 -19
  380. data/test/fixtures/vertices.yml +3 -3
  381. data/test/fixtures/warehouse_things.yml +2 -2
  382. data/test/fixtures/zines.yml +5 -5
  383. data/test/migrations/10_urban/9_add_expressions.rb +11 -11
  384. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
  385. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
  386. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -9
  387. data/test/migrations/missing/1_people_have_last_names.rb +9 -9
  388. data/test/migrations/missing/3_we_need_reminders.rb +12 -12
  389. data/test/migrations/missing/4_innocent_jointable.rb +12 -12
  390. data/test/migrations/rename/1_we_need_things.rb +11 -11
  391. data/test/migrations/rename/2_rename_things.rb +9 -9
  392. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
  393. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
  394. data/test/migrations/to_copy2/1_create_articles.rb +7 -7
  395. data/test/migrations/to_copy2/2_create_comments.rb +7 -7
  396. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
  397. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
  398. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
  399. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
  400. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
  401. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
  402. data/test/migrations/valid/2_we_need_reminders.rb +12 -12
  403. data/test/migrations/valid/3_innocent_jointable.rb +12 -12
  404. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
  405. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -12
  406. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -12
  407. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
  408. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
  409. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
  410. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
  411. data/test/models/admin.rb +5 -5
  412. data/test/models/admin/account.rb +3 -3
  413. data/test/models/admin/randomly_named_c1.rb +6 -2
  414. data/test/models/admin/user.rb +40 -40
  415. data/test/models/aircraft.rb +5 -4
  416. data/test/models/arunit2_model.rb +3 -3
  417. data/test/models/author.rb +209 -212
  418. data/test/models/auto_id.rb +4 -4
  419. data/test/models/autoloadable/extra_firm.rb +2 -2
  420. data/test/models/binary.rb +2 -2
  421. data/test/models/bird.rb +12 -12
  422. data/test/models/book.rb +23 -18
  423. data/test/models/boolean.rb +2 -2
  424. data/test/models/bulb.rb +52 -51
  425. data/test/models/cake_designer.rb +3 -3
  426. data/test/models/car.rb +29 -26
  427. data/test/models/carrier.rb +2 -2
  428. data/test/models/cat.rb +10 -0
  429. data/test/models/categorization.rb +19 -19
  430. data/test/models/category.rb +35 -35
  431. data/test/models/chef.rb +8 -7
  432. data/test/models/citation.rb +3 -3
  433. data/test/models/club.rb +25 -23
  434. data/test/models/college.rb +10 -10
  435. data/test/models/column.rb +3 -3
  436. data/test/models/column_name.rb +3 -3
  437. data/test/models/comment.rb +76 -64
  438. data/test/models/company.rb +230 -228
  439. data/test/models/company_in_module.rb +98 -98
  440. data/test/models/computer.rb +3 -3
  441. data/test/models/contact.rb +41 -41
  442. data/test/models/content.rb +40 -0
  443. data/test/models/contract.rb +20 -20
  444. data/test/models/country.rb +7 -7
  445. data/test/models/course.rb +6 -6
  446. data/test/models/customer.rb +83 -77
  447. data/test/models/customer_carrier.rb +14 -14
  448. data/test/models/dashboard.rb +3 -3
  449. data/test/models/default.rb +2 -2
  450. data/test/models/department.rb +4 -4
  451. data/test/models/developer.rb +274 -255
  452. data/test/models/dog.rb +5 -5
  453. data/test/models/dog_lover.rb +5 -5
  454. data/test/models/doubloon.rb +12 -12
  455. data/test/models/drink_designer.rb +3 -3
  456. data/test/models/edge.rb +5 -5
  457. data/test/models/electron.rb +5 -5
  458. data/test/models/engine.rb +4 -4
  459. data/test/models/entrant.rb +3 -3
  460. data/test/models/essay.rb +5 -5
  461. data/test/models/event.rb +3 -3
  462. data/test/models/eye.rb +37 -37
  463. data/test/models/face.rb +9 -9
  464. data/test/models/friendship.rb +6 -6
  465. data/test/models/guid.rb +2 -2
  466. data/test/models/guitar.rb +4 -0
  467. data/test/models/hotel.rb +11 -9
  468. data/test/models/image.rb +3 -3
  469. data/test/models/interest.rb +5 -5
  470. data/test/models/invoice.rb +4 -4
  471. data/test/models/item.rb +7 -7
  472. data/test/models/job.rb +7 -7
  473. data/test/models/joke.rb +7 -7
  474. data/test/models/keyboard.rb +3 -3
  475. data/test/models/legacy_thing.rb +3 -3
  476. data/test/models/lesson.rb +11 -11
  477. data/test/models/line_item.rb +3 -3
  478. data/test/models/liquid.rb +4 -4
  479. data/test/models/man.rb +11 -11
  480. data/test/models/matey.rb +4 -4
  481. data/test/models/member.rb +42 -41
  482. data/test/models/member_detail.rb +8 -7
  483. data/test/models/member_type.rb +3 -3
  484. data/test/models/membership.rb +35 -35
  485. data/test/models/mentor.rb +3 -0
  486. data/test/models/minimalistic.rb +2 -2
  487. data/test/models/minivan.rb +9 -9
  488. data/test/models/mixed_case_monkey.rb +3 -3
  489. data/test/models/mocktail_designer.rb +2 -0
  490. data/test/models/molecule.rb +6 -6
  491. data/test/models/movie.rb +5 -5
  492. data/test/models/node.rb +5 -0
  493. data/test/models/non_primary_key.rb +2 -0
  494. data/test/models/notification.rb +3 -0
  495. data/test/models/order.rb +4 -4
  496. data/test/models/organization.rb +14 -14
  497. data/test/models/other_dog.rb +5 -0
  498. data/test/models/owner.rb +37 -34
  499. data/test/models/parrot.rb +28 -29
  500. data/test/models/person.rb +142 -143
  501. data/test/models/personal_legacy_thing.rb +4 -4
  502. data/test/models/pet.rb +18 -15
  503. data/test/models/pet_treasure.rb +6 -0
  504. data/test/models/pirate.rb +92 -92
  505. data/test/models/possession.rb +3 -3
  506. data/test/models/post.rb +273 -264
  507. data/test/models/price_estimate.rb +4 -4
  508. data/test/models/professor.rb +5 -5
  509. data/test/models/project.rb +40 -31
  510. data/test/models/publisher.rb +2 -2
  511. data/test/models/publisher/article.rb +4 -4
  512. data/test/models/publisher/magazine.rb +3 -3
  513. data/test/models/randomly_named_c1.rb +1 -1
  514. data/test/models/rating.rb +4 -4
  515. data/test/models/reader.rb +23 -23
  516. data/test/models/recipe.rb +3 -0
  517. data/test/models/record.rb +2 -2
  518. data/test/models/reference.rb +22 -22
  519. data/test/models/reply.rb +61 -61
  520. data/test/models/ship.rb +39 -33
  521. data/test/models/ship_part.rb +8 -8
  522. data/test/models/shop.rb +17 -17
  523. data/test/models/shop_account.rb +6 -6
  524. data/test/models/speedometer.rb +6 -6
  525. data/test/models/sponsor.rb +7 -7
  526. data/test/models/string_key_object.rb +3 -3
  527. data/test/models/student.rb +4 -4
  528. data/test/models/subject.rb +16 -16
  529. data/test/models/subscriber.rb +8 -8
  530. data/test/models/subscription.rb +4 -4
  531. data/test/models/tag.rb +13 -7
  532. data/test/models/tagging.rb +13 -13
  533. data/test/models/task.rb +5 -5
  534. data/test/models/topic.rb +118 -124
  535. data/test/models/toy.rb +6 -6
  536. data/test/models/traffic_light.rb +4 -4
  537. data/test/models/treasure.rb +14 -14
  538. data/test/models/treaty.rb +7 -7
  539. data/test/models/tree.rb +3 -0
  540. data/test/models/tuning_peg.rb +4 -0
  541. data/test/models/tyre.rb +11 -11
  542. data/test/models/user.rb +14 -0
  543. data/test/models/uuid_child.rb +3 -3
  544. data/test/models/uuid_item.rb +6 -0
  545. data/test/models/uuid_parent.rb +3 -3
  546. data/test/models/vegetables.rb +24 -24
  547. data/test/models/vehicle.rb +6 -6
  548. data/test/models/vertex.rb +9 -9
  549. data/test/models/warehouse_thing.rb +5 -5
  550. data/test/models/wheel.rb +3 -3
  551. data/test/models/without_table.rb +3 -3
  552. data/test/models/zine.rb +3 -3
  553. data/test/schema/mysql2_specific_schema.rb +68 -58
  554. data/test/schema/oracle_specific_schema.rb +40 -43
  555. data/test/schema/postgresql_specific_schema.rb +114 -202
  556. data/test/schema/schema.rb +1057 -952
  557. data/test/schema/schema.rb.original +1057 -0
  558. data/test/schema/sqlite_specific_schema.rb +18 -22
  559. data/test/support/config.rb +43 -43
  560. data/test/support/connection.rb +23 -22
  561. data/test/support/connection_helper.rb +14 -14
  562. data/test/support/ddl_helper.rb +8 -8
  563. data/test/support/schema_dumping_helper.rb +20 -20
  564. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  565. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  566. metadata +129 -28
  567. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  568. data/lib/mswin32/rb21x/i386/ibm_db.so +0 -0
  569. data/lib/mswin32/rb22x/i386/ibm_db.so +0 -0
  570. data/lib/mswin32/rb23x/i386/ibm_db.so +0 -0
  571. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +0 -26
  572. data/test/cases/attribute_methods/serialization_test.rb +0 -29
  573. data/test/cases/migration/change_schema_test - Copy.rb +0 -448
  574. data/test/cases/migration/foreign_key_test - Changed.rb +0 -325
  575. data/test/cases/migration/table_and_index_test.rb +0 -24
  576. data/test/cases/relation/where_test2.rb +0 -36
  577. data/test/cases/type/decimal_test.rb +0 -56
  578. data/test/cases/type/unsigned_integer_test.rb +0 -18
  579. data/test/cases/xml_serialization_test.rb +0 -457
  580. data/test/connections/native_ibm_db/connection.rb +0 -44
  581. data/test/fixtures/naked/csv/accounts.csv +0 -1
  582. data/test/schema/i5/ibm_db_specific_schema.rb +0 -137
  583. data/test/schema/ids/ibm_db_specific_schema.rb +0 -140
  584. data/test/schema/luw/ibm_db_specific_schema.rb +0 -137
  585. data/test/schema/mysql_specific_schema.rb +0 -70
  586. data/test/schema/zOS/ibm_db_specific_schema.rb +0 -208
@@ -1,125 +1,125 @@
1
- require 'cases/helper'
2
-
3
- module ActiveRecord
4
- class AttributeDecoratorsTest < ActiveRecord::TestCase
5
- class Model < ActiveRecord::Base
6
- self.table_name = 'attribute_decorators_model'
7
- end
8
-
9
- class StringDecorator < SimpleDelegator
10
- def initialize(delegate, decoration = "decorated!")
11
- @decoration = decoration
12
- super(delegate)
13
- end
14
-
15
- def type_cast_from_user(value)
16
- "#{super} #{@decoration}"
17
- end
18
-
19
- alias type_cast_from_database type_cast_from_user
20
- end
21
-
22
- setup do
23
- @connection = ActiveRecord::Base.connection
24
- @connection.create_table :attribute_decorators_model, force: true do |t|
25
- t.string :a_string
26
- end
27
- end
28
-
29
- teardown do
30
- return unless @connection
31
- @connection.drop_table 'attribute_decorators_model' if @connection.table_exists? 'attribute_decorators_model'
32
- Model.attribute_type_decorations.clear
33
- Model.reset_column_information
34
- end
35
-
36
- test "attributes can be decorated" do
37
- model = Model.new(a_string: 'Hello')
38
- assert_equal 'Hello', model.a_string
39
-
40
- Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
41
-
42
- model = Model.new(a_string: 'Hello')
43
- assert_equal 'Hello decorated!', model.a_string
44
- end
45
-
46
- test "decoration does not eagerly load existing columns" do
47
- Model.reset_column_information
48
- assert_no_queries do
49
- Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
50
- end
51
- end
52
-
53
- test "undecorated columns are not touched" do
54
- Model.attribute :another_string, Type::String.new, default: 'something or other'
55
- Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
56
-
57
- assert_equal 'something or other', Model.new.another_string
58
- end
59
-
60
- test "decorators can be chained" do
61
- Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
62
- Model.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) }
63
-
64
- model = Model.new(a_string: 'Hello!')
65
-
66
- assert_equal 'Hello! decorated! decorated!', model.a_string
67
- end
68
-
69
- test "decoration of the same type multiple times is idempotent" do
70
- Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
71
- Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
72
-
73
- model = Model.new(a_string: 'Hello')
74
- assert_equal 'Hello decorated!', model.a_string
75
- end
76
-
77
- test "decorations occur in order of declaration" do
78
- Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
79
- Model.decorate_attribute_type(:a_string, :other) do |type|
80
- StringDecorator.new(type, 'decorated again!')
81
- end
82
-
83
- model = Model.new(a_string: 'Hello!')
84
-
85
- assert_equal 'Hello! decorated! decorated again!', model.a_string
86
- end
87
-
88
- test "decorating attributes does not modify parent classes" do
89
- Model.attribute :another_string, Type::String.new, default: 'whatever'
90
- Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
91
- child_class = Class.new(Model)
92
- child_class.decorate_attribute_type(:another_string, :test) { |t| StringDecorator.new(t) }
93
- child_class.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) }
94
-
95
- model = Model.new(a_string: 'Hello!')
96
- child = child_class.new(a_string: 'Hello!')
97
-
98
- assert_equal 'Hello! decorated!', model.a_string
99
- assert_equal 'whatever', model.another_string
100
- assert_equal 'Hello! decorated! decorated!', child.a_string
101
- assert_equal 'whatever decorated!', child.another_string
102
- end
103
-
104
- class Multiplier < SimpleDelegator
105
- def type_cast_from_user(value)
106
- return if value.nil?
107
- value * 2
108
- end
109
- alias type_cast_from_database type_cast_from_user
110
- end
111
-
112
- test "decorating with a proc" do
113
- Model.attribute :an_int, Type::Integer.new
114
- type_is_integer = proc { |_, type| type.type == :integer }
115
- Model.decorate_matching_attribute_types type_is_integer, :multiplier do |type|
116
- Multiplier.new(type)
117
- end
118
-
119
- model = Model.new(a_string: 'whatever', an_int: 1)
120
-
121
- assert_equal 'whatever', model.a_string
122
- assert_equal 2, model.an_int
123
- end
124
- end
125
- end
1
+ require 'cases/helper'
2
+
3
+ module ActiveRecord
4
+ class AttributeDecoratorsTest < ActiveRecord::TestCase
5
+ class Model < ActiveRecord::Base
6
+ self.table_name = 'attribute_decorators_model'
7
+ end
8
+
9
+ class StringDecorator < SimpleDelegator
10
+ def initialize(delegate, decoration = "decorated!")
11
+ @decoration = decoration
12
+ super(delegate)
13
+ end
14
+
15
+ def cast(value)
16
+ "#{super} #{@decoration}"
17
+ end
18
+
19
+ alias deserialize cast
20
+ end
21
+
22
+ setup do
23
+ @connection = ActiveRecord::Base.connection
24
+ @connection.create_table :attribute_decorators_model, force: true do |t|
25
+ t.string :a_string
26
+ end
27
+ end
28
+
29
+ teardown do
30
+ return unless @connection
31
+ @connection.drop_table 'attribute_decorators_model', if_exists: true
32
+ Model.attribute_type_decorations.clear
33
+ Model.reset_column_information
34
+ end
35
+
36
+ test "attributes can be decorated" do
37
+ model = Model.new(a_string: 'Hello')
38
+ assert_equal 'Hello', model.a_string
39
+
40
+ Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
41
+
42
+ model = Model.new(a_string: 'Hello')
43
+ assert_equal 'Hello decorated!', model.a_string
44
+ end
45
+
46
+ test "decoration does not eagerly load existing columns" do
47
+ Model.reset_column_information
48
+ assert_no_queries do
49
+ Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
50
+ end
51
+ end
52
+
53
+ test "undecorated columns are not touched" do
54
+ Model.attribute :another_string, :string, default: 'something or other'
55
+ Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
56
+
57
+ assert_equal 'something or other', Model.new.another_string
58
+ end
59
+
60
+ test "decorators can be chained" do
61
+ Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
62
+ Model.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) }
63
+
64
+ model = Model.new(a_string: 'Hello!')
65
+
66
+ assert_equal 'Hello! decorated! decorated!', model.a_string
67
+ end
68
+
69
+ test "decoration of the same type multiple times is idempotent" do
70
+ Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
71
+ Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
72
+
73
+ model = Model.new(a_string: 'Hello')
74
+ assert_equal 'Hello decorated!', model.a_string
75
+ end
76
+
77
+ test "decorations occur in order of declaration" do
78
+ Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
79
+ Model.decorate_attribute_type(:a_string, :other) do |type|
80
+ StringDecorator.new(type, 'decorated again!')
81
+ end
82
+
83
+ model = Model.new(a_string: 'Hello!')
84
+
85
+ assert_equal 'Hello! decorated! decorated again!', model.a_string
86
+ end
87
+
88
+ test "decorating attributes does not modify parent classes" do
89
+ Model.attribute :another_string, :string, default: 'whatever'
90
+ Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
91
+ child_class = Class.new(Model)
92
+ child_class.decorate_attribute_type(:another_string, :test) { |t| StringDecorator.new(t) }
93
+ child_class.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) }
94
+
95
+ model = Model.new(a_string: 'Hello!')
96
+ child = child_class.new(a_string: 'Hello!')
97
+
98
+ assert_equal 'Hello! decorated!', model.a_string
99
+ assert_equal 'whatever', model.another_string
100
+ assert_equal 'Hello! decorated! decorated!', child.a_string
101
+ assert_equal 'whatever decorated!', child.another_string
102
+ end
103
+
104
+ class Multiplier < SimpleDelegator
105
+ def cast(value)
106
+ return if value.nil?
107
+ value * 2
108
+ end
109
+ alias deserialize cast
110
+ end
111
+
112
+ test "decorating with a proc" do
113
+ Model.attribute :an_int, :integer
114
+ type_is_integer = proc { |_, type| type.type == :integer }
115
+ Model.decorate_matching_attribute_types type_is_integer, :multiplier do |type|
116
+ Multiplier.new(type)
117
+ end
118
+
119
+ model = Model.new(a_string: 'whatever', an_int: 1)
120
+
121
+ assert_equal 'whatever', model.a_string
122
+ assert_equal 2, model.an_int
123
+ end
124
+ end
125
+ end
@@ -1,60 +1,60 @@
1
- require "cases/helper"
2
- require 'thread'
3
-
4
- module ActiveRecord
5
- module AttributeMethods
6
- class ReadTest < ActiveRecord::TestCase
7
- class FakeColumn < Struct.new(:name)
8
- def type; :integer; end
9
- end
10
-
11
- def setup
12
- @klass = Class.new do
13
- def self.superclass; Base; end
14
- def self.base_class; self; end
15
- def self.decorate_matching_attribute_types(*); end
16
- def self.initialize_generated_modules; end
17
-
18
- include ActiveRecord::AttributeMethods
19
-
20
- def self.column_names
21
- %w{ one two three }
22
- end
23
-
24
- def self.primary_key
25
- end
26
-
27
- def self.columns
28
- column_names.map { FakeColumn.new(name) }
29
- end
30
-
31
- def self.columns_hash
32
- Hash[column_names.map { |name|
33
- [name, FakeColumn.new(name)]
34
- }]
35
- end
36
- end
37
- end
38
-
39
- def test_define_attribute_methods
40
- instance = @klass.new
41
-
42
- @klass.column_names.each do |name|
43
- assert !instance.methods.map(&:to_s).include?(name)
44
- end
45
-
46
- @klass.define_attribute_methods
47
-
48
- @klass.column_names.each do |name|
49
- assert instance.methods.map(&:to_s).include?(name), "#{name} is not defined"
50
- end
51
- end
52
-
53
- def test_attribute_methods_generated?
54
- assert_not @klass.method_defined?(:one)
55
- @klass.define_attribute_methods
56
- assert @klass.method_defined?(:one)
57
- end
58
- end
59
- end
60
- end
1
+ require "cases/helper"
2
+ require 'thread'
3
+
4
+ module ActiveRecord
5
+ module AttributeMethods
6
+ class ReadTest < ActiveRecord::TestCase
7
+ class FakeColumn < Struct.new(:name)
8
+ def type; :integer; end
9
+ end
10
+
11
+ def setup
12
+ @klass = Class.new do
13
+ def self.superclass; Base; end
14
+ def self.base_class; self; end
15
+ def self.decorate_matching_attribute_types(*); end
16
+ def self.initialize_generated_modules; end
17
+
18
+ include ActiveRecord::AttributeMethods
19
+
20
+ def self.attribute_names
21
+ %w{ one two three }
22
+ end
23
+
24
+ def self.primary_key
25
+ end
26
+
27
+ def self.columns
28
+ attribute_names.map { FakeColumn.new(name) }
29
+ end
30
+
31
+ def self.columns_hash
32
+ Hash[attribute_names.map { |name|
33
+ [name, FakeColumn.new(name)]
34
+ }]
35
+ end
36
+ end
37
+ end
38
+
39
+ def test_define_attribute_methods
40
+ instance = @klass.new
41
+
42
+ @klass.attribute_names.each do |name|
43
+ assert !instance.methods.map(&:to_s).include?(name)
44
+ end
45
+
46
+ @klass.define_attribute_methods
47
+
48
+ @klass.attribute_names.each do |name|
49
+ assert instance.methods.map(&:to_s).include?(name), "#{name} is not defined"
50
+ end
51
+ end
52
+
53
+ def test_attribute_methods_generated?
54
+ assert_not @klass.method_defined?(:one)
55
+ @klass.define_attribute_methods
56
+ assert @klass.method_defined?(:one)
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,952 +1,1009 @@
1
- require "cases/helper"
2
- require 'models/minimalistic'
3
- require 'models/developer'
4
- require 'models/computer'
5
- require 'models/auto_id'
6
- require 'models/boolean'
7
- require 'models/computer'
8
- require 'models/topic'
9
- require 'models/company'
10
- require 'models/category'
11
- require 'models/reply'
12
- require 'models/contact'
13
- require 'models/keyboard'
14
-
15
- class AttributeMethodsTest < ActiveRecord::TestCase
16
- include InTimeZone
17
-
18
- fixtures :topics, :developers, :companies, :computers
19
-
20
- def setup
21
- @old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
22
- @target = Class.new(ActiveRecord::Base)
23
- @target.table_name = 'topics'
24
- end
25
-
26
- teardown do
27
- ActiveRecord::Base.send(:attribute_method_matchers).clear
28
- ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
29
- end
30
-
31
- def test_attribute_for_inspect
32
- t = topics(:first)
33
- t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
34
-
35
- assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
36
- assert_equal '"The First Topic Now Has A Title With\nNewlines And ..."', t.attribute_for_inspect(:title)
37
- end
38
-
39
- def test_attribute_present
40
- t = Topic.new
41
- t.title = "hello there!"
42
- t.written_on = Time.now
43
- t.author_name = ""
44
- assert t.attribute_present?("title")
45
- assert t.attribute_present?("written_on")
46
- assert !t.attribute_present?("content")
47
- assert !t.attribute_present?("author_name")
48
- end
49
-
50
- def test_attribute_present_with_booleans
51
- b1 = Boolean.new
52
- b1.value = false
53
- assert b1.attribute_present?(:value)
54
-
55
- b2 = Boolean.new
56
- b2.value = true
57
- assert b2.attribute_present?(:value)
58
-
59
- b3 = Boolean.new
60
- assert !b3.attribute_present?(:value)
61
-
62
- b4 = Boolean.new
63
- b4.value = false
64
- b4.save!
65
- assert Boolean.find(b4.id).attribute_present?(:value)
66
- end
67
-
68
- def test_caching_nil_primary_key
69
- klass = Class.new(Minimalistic)
70
- klass.expects(:reset_primary_key).returns(nil).once
71
- 2.times { klass.primary_key }
72
- end
73
-
74
- def test_attribute_keys_on_new_instance
75
- t = Topic.new
76
- assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
77
- assert_raise(NoMethodError) { t.title2 }
78
- end
79
-
80
- def test_boolean_attributes
81
- assert !Topic.find(1).approved?
82
- assert Topic.find(2).approved?
83
- end
84
-
85
- def test_set_attributes
86
- topic = Topic.find(1)
87
- topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
88
- topic.save
89
- assert_equal("Budget", topic.title)
90
- assert_equal("Jason", topic.author_name)
91
- assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
92
- end
93
-
94
- def test_set_attributes_without_hash
95
- topic = Topic.new
96
- assert_raise(ArgumentError) { topic.attributes = '' }
97
- end
98
-
99
- def test_integers_as_nil
100
- test = AutoId.create('value' => '')
101
- assert_nil AutoId.find(test.id).value
102
- end
103
-
104
- def test_set_attributes_with_block
105
- topic = Topic.new do |t|
106
- t.title = "Budget"
107
- t.author_name = "Jason"
108
- end
109
-
110
- assert_equal("Budget", topic.title)
111
- assert_equal("Jason", topic.author_name)
112
- end
113
-
114
- def test_respond_to?
115
- topic = Topic.find(1)
116
- assert_respond_to topic, "title"
117
- assert_respond_to topic, "title?"
118
- assert_respond_to topic, "title="
119
- assert_respond_to topic, :title
120
- assert_respond_to topic, :title?
121
- assert_respond_to topic, :title=
122
- assert_respond_to topic, "author_name"
123
- assert_respond_to topic, "attribute_names"
124
- assert !topic.respond_to?("nothingness")
125
- assert !topic.respond_to?(:nothingness)
126
- end
127
-
128
- def test_respond_to_with_custom_primary_key
129
- keyboard = Keyboard.create
130
- assert_not_nil keyboard.key_number
131
- assert_equal keyboard.key_number, keyboard.id
132
- assert keyboard.respond_to?('key_number')
133
- assert keyboard.respond_to?('id')
134
- end
135
-
136
- def test_id_before_type_cast_with_custom_primary_key
137
- keyboard = Keyboard.create
138
- keyboard.key_number = '10'
139
- assert_equal '10', keyboard.id_before_type_cast
140
- assert_equal nil, keyboard.read_attribute_before_type_cast('id')
141
- assert_equal '10', keyboard.read_attribute_before_type_cast('key_number')
142
- assert_equal '10', keyboard.read_attribute_before_type_cast(:key_number)
143
- end
144
-
145
- # Syck calls respond_to? before actually calling initialize
146
- def test_respond_to_with_allocated_object
147
- klass = Class.new(ActiveRecord::Base) do
148
- self.table_name = 'topics'
149
- end
150
-
151
- topic = klass.allocate
152
- assert !topic.respond_to?("nothingness")
153
- assert !topic.respond_to?(:nothingness)
154
- assert_respond_to topic, "title"
155
- assert_respond_to topic, :title
156
- end
157
-
158
- # IRB inspects the return value of "MyModel.allocate".
159
- def test_allocated_object_can_be_inspected
160
- topic = Topic.allocate
161
- assert_equal "#<Topic not initialized>", topic.inspect
162
- end
163
-
164
- def test_array_content
165
- topic = Topic.new
166
- topic.content = %w( one two three )
167
- topic.save
168
-
169
- assert_equal(%w( one two three ), Topic.find(topic.id).content)
170
- end
171
-
172
- def test_read_attributes_before_type_cast
173
- category = Category.new({:name=>"Test category", :type => nil})
174
- category_attrs = {"name"=>"Test category", "id" => nil, "type" => nil, "categorizations_count" => nil}
175
- assert_equal category_attrs , category.attributes_before_type_cast
176
- end
177
-
178
- if current_adapter?(:MysqlAdapter)
179
- def test_read_attributes_before_type_cast_on_boolean
180
- bool = Boolean.create({ "value" => false })
181
- if RUBY_PLATFORM =~ /java/
182
- # JRuby will return the value before typecast as string
183
- assert_equal "0", bool.reload.attributes_before_type_cast["value"]
184
- else
185
- assert_equal 0, bool.reload.attributes_before_type_cast["value"]
186
- end
187
- end
188
- end
189
-
190
- def test_read_attributes_before_type_cast_on_datetime
191
- in_time_zone "Pacific Time (US & Canada)" do
192
- record = @target.new
193
-
194
- record.written_on = "345643456"
195
- assert_equal "345643456", record.written_on_before_type_cast
196
- assert_equal nil, record.written_on
197
-
198
- record.written_on = "2009-10-11 12:13:14"
199
- assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast
200
- assert_equal Time.zone.parse("2009-10-11 12:13:14"), record.written_on
201
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
202
- end
203
- end
204
-
205
- def test_read_attributes_after_type_cast_on_datetime
206
- tz = "Pacific Time (US & Canada)"
207
-
208
- in_time_zone tz do
209
- record = @target.new
210
-
211
- date_string = "2011-03-24"
212
- time = Time.zone.parse date_string
213
-
214
- record.written_on = date_string
215
- assert_equal date_string, record.written_on_before_type_cast
216
- assert_equal time, record.written_on
217
- assert_equal ActiveSupport::TimeZone[tz], record.written_on.time_zone
218
-
219
- record.save
220
- record.reload
221
-
222
- assert_equal time, record.written_on
223
- end
224
- end
225
-
226
- def test_hash_content
227
- topic = Topic.new
228
- topic.content = { "one" => 1, "two" => 2 }
229
- topic.save
230
-
231
- assert_equal 2, Topic.find(topic.id).content["two"]
232
-
233
- topic.content_will_change!
234
- topic.content["three"] = 3
235
- topic.save
236
-
237
- assert_equal 3, Topic.find(topic.id).content["three"]
238
- end
239
-
240
- def test_update_array_content
241
- topic = Topic.new
242
- topic.content = %w( one two three )
243
-
244
- topic.content.push "four"
245
- assert_equal(%w( one two three four ), topic.content)
246
-
247
- topic.save
248
-
249
- topic = Topic.find(topic.id)
250
- topic.content << "five"
251
- assert_equal(%w( one two three four five ), topic.content)
252
- end
253
-
254
- def test_case_sensitive_attributes_hash
255
- # DB2 is not case-sensitive
256
- return true if current_adapter?(:DB2Adapter) || current_adapter?(:IBM_DBAdapter)
257
-
258
- assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.first.attributes
259
- end
260
-
261
- def test_attributes_without_primary_key
262
- klass = Class.new(ActiveRecord::Base) do
263
- self.table_name = 'developers_projects'
264
- end
265
-
266
- assert_equal klass.column_names, klass.new.attributes.keys
267
- assert_not klass.new.has_attribute?('id')
268
- end
269
-
270
- def test_hashes_not_mangled
271
- new_topic = { :title => "New Topic" }
272
- new_topic_values = { :title => "AnotherTopic" }
273
-
274
- topic = Topic.new(new_topic)
275
- assert_equal new_topic[:title], topic.title
276
-
277
- topic.attributes= new_topic_values
278
- assert_equal new_topic_values[:title], topic.title
279
- end
280
-
281
- def test_create_through_factory
282
- topic = Topic.create("title" => "New Topic")
283
- topicReloaded = Topic.find(topic.id)
284
- assert_equal(topic, topicReloaded)
285
- end
286
-
287
- def test_write_attribute
288
- topic = Topic.new
289
- topic.send(:write_attribute, :title, "Still another topic")
290
- assert_equal "Still another topic", topic.title
291
-
292
- topic[:title] = "Still another topic: part 2"
293
- assert_equal "Still another topic: part 2", topic.title
294
-
295
- topic.send(:write_attribute, "title", "Still another topic: part 3")
296
- assert_equal "Still another topic: part 3", topic.title
297
-
298
- topic["title"] = "Still another topic: part 4"
299
- assert_equal "Still another topic: part 4", topic.title
300
- end
301
-
302
- def test_read_attribute
303
- topic = Topic.new
304
- topic.title = "Don't change the topic"
305
- assert_equal "Don't change the topic", topic.read_attribute("title")
306
- assert_equal "Don't change the topic", topic["title"]
307
-
308
- assert_equal "Don't change the topic", topic.read_attribute(:title)
309
- assert_equal "Don't change the topic", topic[:title]
310
- end
311
-
312
- def test_read_attribute_raises_missing_attribute_error_when_not_exists
313
- computer = Computer.select('id').first
314
- assert_raises(ActiveModel::MissingAttributeError) { computer[:developer] }
315
- assert_raises(ActiveModel::MissingAttributeError) { computer[:extendedWarranty] }
316
- assert_raises(ActiveModel::MissingAttributeError) { computer[:no_column_exists] = 'Hello!' }
317
- assert_nothing_raised { computer[:developer] = 'Hello!' }
318
- end
319
-
320
- def test_read_attribute_when_false
321
- topic = topics(:first)
322
- topic.approved = false
323
- assert !topic.approved?, "approved should be false"
324
- topic.approved = "false"
325
- assert !topic.approved?, "approved should be false"
326
- end
327
-
328
- def test_read_attribute_when_true
329
- topic = topics(:first)
330
- topic.approved = true
331
- assert topic.approved?, "approved should be true"
332
- topic.approved = "true"
333
- assert topic.approved?, "approved should be true"
334
- end
335
-
336
- def test_read_write_boolean_attribute
337
- topic = Topic.new
338
- topic.approved = "false"
339
- assert !topic.approved?, "approved should be false"
340
-
341
- topic.approved = "false"
342
- assert !topic.approved?, "approved should be false"
343
-
344
- topic.approved = "true"
345
- assert topic.approved?, "approved should be true"
346
-
347
- topic.approved = "true"
348
- assert topic.approved?, "approved should be true"
349
- end
350
-
351
- def test_overridden_write_attribute
352
- topic = Topic.new
353
- def topic.write_attribute(attr_name, value)
354
- super(attr_name, value.downcase)
355
- end
356
-
357
- topic.send(:write_attribute, :title, "Yet another topic")
358
- assert_equal "yet another topic", topic.title
359
-
360
- topic[:title] = "Yet another topic: part 2"
361
- assert_equal "yet another topic: part 2", topic.title
362
-
363
- topic.send(:write_attribute, "title", "Yet another topic: part 3")
364
- assert_equal "yet another topic: part 3", topic.title
365
-
366
- topic["title"] = "Yet another topic: part 4"
367
- assert_equal "yet another topic: part 4", topic.title
368
- end
369
-
370
- def test_overridden_read_attribute
371
- topic = Topic.new
372
- topic.title = "Stop changing the topic"
373
- def topic.read_attribute(attr_name)
374
- super(attr_name).upcase
375
- end
376
-
377
- assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute("title")
378
- assert_equal "STOP CHANGING THE TOPIC", topic["title"]
379
-
380
- assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute(:title)
381
- assert_equal "STOP CHANGING THE TOPIC", topic[:title]
382
- end
383
-
384
- def test_read_overridden_attribute
385
- topic = Topic.new(:title => 'a')
386
- def topic.title() 'b' end
387
- assert_equal 'a', topic[:title]
388
- end
389
-
390
- def test_query_attribute_string
391
- [nil, "", " "].each do |value|
392
- assert_equal false, Topic.new(:author_name => value).author_name?
393
- end
394
-
395
- assert_equal true, Topic.new(:author_name => "Name").author_name?
396
- end
397
-
398
- def test_query_attribute_number
399
- [nil, 0, "0"].each do |value|
400
- assert_equal false, Developer.new(:salary => value).salary?
401
- end
402
-
403
- assert_equal true, Developer.new(:salary => 1).salary?
404
- assert_equal true, Developer.new(:salary => "1").salary?
405
- end
406
-
407
- def test_query_attribute_boolean
408
- [nil, "", false, "false", "f", 0].each do |value|
409
- assert_equal false, Topic.new(:approved => value).approved?
410
- end
411
-
412
- [true, "true", "1", 1].each do |value|
413
- assert_equal true, Topic.new(:approved => value).approved?
414
- end
415
- end
416
-
417
- def test_query_attribute_with_custom_fields
418
- object = Company.find_by_sql(<<-SQL).first
419
- SELECT c1.*, c2.type as string_value, c2.rating as int_value
420
- FROM companies c1, companies c2
421
- WHERE c1.firm_id = c2.id
422
- AND c1.id = 2
423
- SQL
424
-
425
- assert_equal "Firm", object.string_value
426
- assert object.string_value?
427
-
428
- object.string_value = " "
429
- assert !object.string_value?
430
-
431
- assert_equal 1, object.int_value.to_i
432
- assert object.int_value?
433
-
434
- object.int_value = "0"
435
- assert !object.int_value?
436
- end
437
-
438
- def test_non_attribute_access_and_assignment
439
- topic = Topic.new
440
- assert !topic.respond_to?("mumbo")
441
- assert_raise(NoMethodError) { topic.mumbo }
442
- assert_raise(NoMethodError) { topic.mumbo = 5 }
443
- end
444
-
445
- def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing
446
- topic = @target.new(:title => 'Budget')
447
- assert topic.respond_to?('title')
448
- assert_equal 'Budget', topic.title
449
- assert !topic.respond_to?('title_hello_world')
450
- assert_raise(NoMethodError) { topic.title_hello_world }
451
- end
452
-
453
- def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing
454
- topic = @target.new(:title => 'Budget')
455
- %w(default_ title_).each do |prefix|
456
- @target.class_eval "def #{prefix}attribute(*args) args end"
457
- @target.attribute_method_prefix prefix
458
-
459
- meth = "#{prefix}title"
460
- assert topic.respond_to?(meth)
461
- assert_equal ['title'], topic.send(meth)
462
- assert_equal ['title', 'a'], topic.send(meth, 'a')
463
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
464
- end
465
- end
466
-
467
- def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing
468
- %w(_default _title_default _it! _candidate= able?).each do |suffix|
469
- @target.class_eval "def attribute#{suffix}(*args) args end"
470
- @target.attribute_method_suffix suffix
471
- topic = @target.new(:title => 'Budget')
472
-
473
- meth = "title#{suffix}"
474
- assert topic.respond_to?(meth)
475
- assert_equal ['title'], topic.send(meth)
476
- assert_equal ['title', 'a'], topic.send(meth, 'a')
477
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
478
- end
479
- end
480
-
481
- def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing
482
- [['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix|
483
- @target.class_eval "def #{prefix}attribute#{suffix}(*args) args end"
484
- @target.attribute_method_affix({ :prefix => prefix, :suffix => suffix })
485
- topic = @target.new(:title => 'Budget')
486
-
487
- meth = "#{prefix}title#{suffix}"
488
- assert topic.respond_to?(meth)
489
- assert_equal ['title'], topic.send(meth)
490
- assert_equal ['title', 'a'], topic.send(meth, 'a')
491
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
492
- end
493
- end
494
-
495
- def test_should_unserialize_attributes_for_frozen_records
496
- myobj = {:value1 => :value2}
497
- topic = Topic.create("content" => myobj)
498
- topic.freeze
499
- assert_equal myobj, topic.content
500
- end
501
-
502
- def test_typecast_attribute_from_select_to_false
503
- Topic.create(:title => 'Budget')
504
- # Oracle does not support boolean expressions in SELECT
505
- if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
506
- topic = Topic.all.merge!(:select => "topics.*, 0 as is_test").first
507
- else
508
- topic = Topic.all.merge!(:select => "topics.*, 1=2 as is_test").first
509
- end
510
- assert !topic.is_test?
511
- end
512
-
513
- def test_typecast_attribute_from_select_to_true
514
- Topic.create(:title => 'Budget')
515
- # Oracle does not support boolean expressions in SELECT
516
- if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
517
- topic = Topic.all.merge!(:select => "topics.*, 1 as is_test").first
518
- else
519
- topic = Topic.all.merge!(:select => "topics.*, 2=2 as is_test").first
520
- end
521
- assert topic.is_test?
522
- end
523
-
524
- def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
525
- %w(save create_or_update).each do |method|
526
- klass = Class.new ActiveRecord::Base
527
- klass.class_eval "def #{method}() 'defined #{method}' end"
528
- assert_raise ActiveRecord::DangerousAttributeError do
529
- klass.instance_method_already_implemented?(method)
530
- end
531
- end
532
- end
533
-
534
- def test_deprecated_cache_attributes
535
- assert_deprecated do
536
- Topic.cache_attributes :replies_count
537
- end
538
-
539
- assert_deprecated do
540
- Topic.cached_attributes
541
- end
542
-
543
- assert_deprecated do
544
- Topic.cache_attribute? :replies_count
545
- end
546
- end
547
-
548
- def test_converted_values_are_returned_after_assignment
549
- developer = Developer.new(name: 1337, salary: "50000")
550
-
551
- assert_equal "50000", developer.salary_before_type_cast
552
- assert_equal 1337, developer.name_before_type_cast
553
-
554
- assert_equal 50000, developer.salary
555
- assert_equal "1337", developer.name
556
-
557
- developer.save!
558
-
559
- assert_equal "50000", developer.salary_before_type_cast
560
- assert_equal 1337, developer.name_before_type_cast
561
-
562
- assert_equal 50000, developer.salary
563
- assert_equal "1337", developer.name
564
- end
565
-
566
- def test_write_nil_to_time_attributes
567
- in_time_zone "Pacific Time (US & Canada)" do
568
- record = @target.new
569
- record.written_on = nil
570
- assert_nil record.written_on
571
- end
572
- end
573
-
574
- def test_write_time_to_date_attributes
575
- in_time_zone "Pacific Time (US & Canada)" do
576
- record = @target.new
577
- record.last_read = Time.utc(2010, 1, 1, 10)
578
- assert_equal Date.civil(2010, 1, 1), record.last_read
579
- end
580
- end
581
-
582
- def test_time_attributes_are_retrieved_in_current_time_zone
583
- in_time_zone "Pacific Time (US & Canada)" do
584
- utc_time = Time.utc(2008, 1, 1)
585
- record = @target.new
586
- record[:written_on] = utc_time
587
- assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
588
- assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
589
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
590
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
591
- end
592
- end
593
-
594
- def test_setting_time_zone_aware_attribute_to_utc
595
- in_time_zone "Pacific Time (US & Canada)" do
596
- utc_time = Time.utc(2008, 1, 1)
597
- record = @target.new
598
- record.written_on = utc_time
599
- assert_equal utc_time, record.written_on
600
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
601
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
602
- end
603
- end
604
-
605
- def test_setting_time_zone_aware_attribute_in_other_time_zone
606
- utc_time = Time.utc(2008, 1, 1)
607
- cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
608
- in_time_zone "Pacific Time (US & Canada)" do
609
- record = @target.new
610
- record.written_on = cst_time
611
- assert_equal utc_time, record.written_on
612
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
613
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
614
- end
615
- end
616
-
617
- def test_setting_time_zone_aware_read_attribute
618
- utc_time = Time.utc(2008, 1, 1)
619
- cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
620
- in_time_zone "Pacific Time (US & Canada)" do
621
- record = @target.create(:written_on => cst_time).reload
622
- assert_equal utc_time, record[:written_on]
623
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record[:written_on].time_zone
624
- assert_equal Time.utc(2007, 12, 31, 16), record[:written_on].time
625
- end
626
- end
627
-
628
- def test_setting_time_zone_aware_attribute_with_string
629
- utc_time = Time.utc(2008, 1, 1)
630
- (-11..13).each do |timezone_offset|
631
- time_string = utc_time.in_time_zone(timezone_offset).to_s
632
- in_time_zone "Pacific Time (US & Canada)" do
633
- record = @target.new
634
- record.written_on = time_string
635
- assert_equal Time.zone.parse(time_string), record.written_on
636
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
637
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
638
- end
639
- end
640
- end
641
-
642
- def test_time_zone_aware_attribute_saved
643
- in_time_zone 1 do
644
- record = @target.create(:written_on => '2012-02-20 10:00')
645
-
646
- record.written_on = '2012-02-20 09:00'
647
- record.save
648
- assert_equal Time.zone.local(2012, 02, 20, 9), record.reload.written_on
649
- end
650
- end
651
-
652
- def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
653
- in_time_zone "Pacific Time (US & Canada)" do
654
- record = @target.new
655
- record.written_on = ' '
656
- assert_nil record.written_on
657
- assert_nil record[:written_on]
658
- end
659
- end
660
-
661
- def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
662
- time_string = 'Tue Jan 01 00:00:00 2008'
663
- (-11..13).each do |timezone_offset|
664
- in_time_zone timezone_offset do
665
- record = @target.new
666
- record.written_on = time_string
667
- assert_equal Time.zone.parse(time_string), record.written_on
668
- assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
669
- assert_equal Time.utc(2008, 1, 1), record.written_on.time
670
- end
671
- end
672
- end
673
-
674
- def test_setting_time_zone_aware_attribute_in_current_time_zone
675
- utc_time = Time.utc(2008, 1, 1)
676
- in_time_zone "Pacific Time (US & Canada)" do
677
- record = @target.new
678
- record.written_on = utc_time.in_time_zone
679
- assert_equal utc_time, record.written_on
680
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
681
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
682
- end
683
- end
684
-
685
- def test_yaml_dumping_record_with_time_zone_aware_attribute
686
- in_time_zone "Pacific Time (US & Canada)" do
687
- record = Topic.new(id: 1)
688
- record.written_on = "Jan 01 00:00:00 2014"
689
- assert_equal record, YAML.load(YAML.dump(record))
690
- end
691
- end
692
-
693
- def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
694
- Topic.skip_time_zone_conversion_for_attributes = [:field_a]
695
- Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
696
-
697
- assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
698
- assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
699
- end
700
-
701
- def test_read_attributes_respect_access_control
702
- privatize("title")
703
-
704
- topic = @target.new(:title => "The pros and cons of programming naked.")
705
- assert !topic.respond_to?(:title)
706
- exception = assert_raise(NoMethodError) { topic.title }
707
- assert exception.message.include?("private method")
708
- assert_equal "I'm private", topic.send(:title)
709
- end
710
-
711
- def test_write_attributes_respect_access_control
712
- privatize("title=(value)")
713
-
714
- topic = @target.new
715
- assert !topic.respond_to?(:title=)
716
- exception = assert_raise(NoMethodError) { topic.title = "Pants"}
717
- assert exception.message.include?("private method")
718
- topic.send(:title=, "Very large pants")
719
- end
720
-
721
- def test_question_attributes_respect_access_control
722
- privatize("title?")
723
-
724
- topic = @target.new(:title => "Isaac Newton's pants")
725
- assert !topic.respond_to?(:title?)
726
- exception = assert_raise(NoMethodError) { topic.title? }
727
- assert exception.message.include?("private method")
728
- assert topic.send(:title?)
729
- end
730
-
731
- def test_bulk_update_respects_access_control
732
- privatize("title=(value)")
733
-
734
- assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(:title => "Rants about pants") }
735
- assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
736
- end
737
-
738
- def test_bulk_update_raise_unknown_attribute_error
739
- error = assert_raises(ActiveRecord::UnknownAttributeError) {
740
- Topic.new(hello: "world")
741
- }
742
- assert_instance_of Topic, error.record
743
- assert_equal "hello", error.attribute
744
- assert_equal "unknown attribute 'hello' for Topic.", error.message
745
- end
746
-
747
- # This test is related to a bug in Ruby 2.2.1.
748
- # It can be safely removed once that bug is fixed.
749
- #
750
- # xref: https://bugs.ruby-lang.org/issues/10969
751
- def test_bulk_does_not_raise_name_error
752
- nope rescue nil # necessary to trigger the bug
753
- assert_raises(ActiveRecord::UnknownAttributeError) {
754
- Topic.new(hello: "world")
755
- }
756
- end
757
-
758
- def test_methods_override_in_multi_level_subclass
759
- klass = Class.new(Developer) do
760
- def name
761
- "dev:#{read_attribute(:name)}"
762
- end
763
- end
764
-
765
- 2.times { klass = Class.new klass }
766
- dev = klass.new(name: 'arthurnn')
767
- dev.save!
768
- assert_equal 'dev:arthurnn', dev.reload.name
769
- end
770
-
771
- def test_global_methods_are_overwritten
772
- klass = Class.new(ActiveRecord::Base) do
773
- self.table_name = 'computers'
774
- end
775
-
776
- assert !klass.instance_method_already_implemented?(:system)
777
- computer = klass.new
778
- assert_nil computer.system
779
- end
780
-
781
- def test_global_methods_are_overwritte_when_subclassing
782
- klass = Class.new(ActiveRecord::Base) { self.abstract_class = true }
783
-
784
- subklass = Class.new(klass) do
785
- self.table_name = 'computers'
786
- end
787
-
788
- assert !klass.instance_method_already_implemented?(:system)
789
- assert !subklass.instance_method_already_implemented?(:system)
790
- computer = subklass.new
791
- assert_nil computer.system
792
- end
793
-
794
- def test_instance_method_should_be_defined_on_the_base_class
795
- subklass = Class.new(Topic)
796
-
797
- Topic.define_attribute_methods
798
-
799
- instance = subklass.new
800
- instance.id = 5
801
- assert_equal 5, instance.id
802
- assert subklass.method_defined?(:id), "subklass is missing id method"
803
-
804
- Topic.undefine_attribute_methods
805
-
806
- assert_equal 5, instance.id
807
- assert subklass.method_defined?(:id), "subklass is missing id method"
808
- end
809
-
810
- def test_read_attribute_with_nil_should_not_asplode
811
- assert_equal nil, Topic.new.read_attribute(nil)
812
- end
813
-
814
- # If B < A, and A defines an accessor for 'foo', we don't want to override
815
- # that by defining a 'foo' method in the generated methods module for B.
816
- # (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].)
817
- def test_inherited_custom_accessors
818
- klass = new_topic_like_ar_class do
819
- self.abstract_class = true
820
- def title; "omg"; end
821
- def title=(val); self.author_name = val; end
822
- end
823
- subklass = Class.new(klass)
824
- [klass, subklass].each(&:define_attribute_methods)
825
-
826
- topic = subklass.find(1)
827
- assert_equal "omg", topic.title
828
-
829
- topic.title = "lol"
830
- assert_equal "lol", topic.author_name
831
- end
832
-
833
- def test_inherited_custom_accessors_with_reserved_names
834
- klass = Class.new(ActiveRecord::Base) do
835
- self.table_name = 'computers'
836
- self.abstract_class = true
837
- def system; "omg"; end
838
- def system=(val); self.developer = val; end
839
- end
840
-
841
- subklass = Class.new(klass)
842
- [klass, subklass].each(&:define_attribute_methods)
843
-
844
- computer = subklass.find(1)
845
- assert_equal "omg", computer.system
846
-
847
- computer.developer = 99
848
- assert_equal 99, computer.developer
849
- end
850
-
851
- def test_on_the_fly_super_invokable_generated_attribute_methods_via_method_missing
852
- klass = new_topic_like_ar_class do
853
- def title
854
- super + '!'
855
- end
856
- end
857
-
858
- real_topic = topics(:first)
859
- assert_equal real_topic.title + '!', klass.find(real_topic.id).title
860
- end
861
-
862
- def test_on_the_fly_super_invokable_generated_predicate_attribute_methods_via_method_missing
863
- klass = new_topic_like_ar_class do
864
- def title?
865
- !super
866
- end
867
- end
868
-
869
- real_topic = topics(:first)
870
- assert_equal !real_topic.title?, klass.find(real_topic.id).title?
871
- end
872
-
873
- def test_calling_super_when_parent_does_not_define_method_raises_error
874
- klass = new_topic_like_ar_class do
875
- def some_method_that_is_not_on_super
876
- super
877
- end
878
- end
879
-
880
- assert_raise(NoMethodError) do
881
- klass.new.some_method_that_is_not_on_super
882
- end
883
- end
884
-
885
- def test_attribute_method?
886
- assert @target.attribute_method?(:title)
887
- assert @target.attribute_method?(:title=)
888
- assert_not @target.attribute_method?(:wibble)
889
- end
890
-
891
- def test_attribute_method_returns_false_if_table_does_not_exist
892
- @target.table_name = 'wibble'
893
- assert_not @target.attribute_method?(:title)
894
- end
895
-
896
- def test_attribute_names_on_new_record
897
- model = @target.new
898
-
899
- assert_equal @target.column_names, model.attribute_names
900
- end
901
-
902
- def test_attribute_names_on_queried_record
903
- model = @target.last!
904
-
905
- assert_equal @target.column_names, model.attribute_names
906
- end
907
-
908
- def test_attribute_names_with_custom_select
909
- model = @target.select('id').last!
910
-
911
- assert_equal ['id'], model.attribute_names
912
- # Sanity check, make sure other columns exist
913
- assert_not_equal ['id'], @target.column_names
914
- end
915
-
916
- def test_came_from_user
917
- model = @target.first
918
-
919
- assert_not model.id_came_from_user?
920
- model.id = "omg"
921
- assert model.id_came_from_user?
922
- end
923
-
924
- private
925
-
926
- def new_topic_like_ar_class(&block)
927
- klass = Class.new(ActiveRecord::Base) do
928
- self.table_name = 'topics'
929
- class_eval(&block)
930
- end
931
-
932
- assert_empty klass.generated_attribute_methods.instance_methods(false)
933
- klass
934
- end
935
-
936
- def cached_columns
937
- Topic.columns.map(&:name)
938
- end
939
-
940
- def time_related_columns_on_topic
941
- Topic.columns.select { |c| [:time, :date, :datetime, :timestamp].include?(c.type) }
942
- end
943
-
944
- def privatize(method_signature)
945
- @target.class_eval(<<-private_method, __FILE__, __LINE__ + 1)
946
- private
947
- def #{method_signature}
948
- "I'm private"
949
- end
950
- private_method
951
- end
952
- end
1
+ require "cases/helper"
2
+ require 'models/minimalistic'
3
+ require 'models/developer'
4
+ require 'models/auto_id'
5
+ require 'models/boolean'
6
+ require 'models/computer'
7
+ require 'models/topic'
8
+ require 'models/company'
9
+ require 'models/category'
10
+ require 'models/reply'
11
+ require 'models/contact'
12
+ require 'models/keyboard'
13
+
14
+ class AttributeMethodsTest < ActiveRecord::TestCase
15
+ include InTimeZone
16
+
17
+ fixtures :topics, :developers, :companies, :computers
18
+
19
+ def setup
20
+ @old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
21
+ @target = Class.new(ActiveRecord::Base)
22
+ @target.table_name = 'topics'
23
+ end
24
+
25
+ teardown do
26
+ ActiveRecord::Base.send(:attribute_method_matchers).clear
27
+ ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
28
+ end
29
+
30
+ def test_attribute_for_inspect_string
31
+ t = topics(:first)
32
+ t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
33
+
34
+ assert_equal '"The First Topic Now Has A Title With\nNewlines And ..."', t.attribute_for_inspect(:title)
35
+ end
36
+
37
+ def test_attribute_for_inspect_date
38
+ t = topics(:first)
39
+
40
+ assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
41
+ end
42
+
43
+ def test_attribute_for_inspect_array
44
+ t = topics(:first)
45
+ t.content = [Object.new]
46
+
47
+ assert_match %r(\[#<Object:0x[0-9a-f]+>\]), t.attribute_for_inspect(:content)
48
+ end
49
+
50
+ def test_attribute_for_inspect_long_array
51
+ t = topics(:first)
52
+ t.content = (1..11).to_a
53
+
54
+ assert_equal "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]", t.attribute_for_inspect(:content)
55
+ end
56
+
57
+ def test_attribute_present
58
+ t = Topic.new
59
+ t.title = "hello there!"
60
+ t.written_on = Time.now
61
+ t.author_name = ""
62
+ assert t.attribute_present?("title")
63
+ assert t.attribute_present?("written_on")
64
+ assert !t.attribute_present?("content")
65
+ assert !t.attribute_present?("author_name")
66
+ end
67
+
68
+ def test_attribute_present_with_booleans
69
+ b1 = Boolean.new
70
+ b1.value = false
71
+ assert b1.attribute_present?(:value)
72
+
73
+ b2 = Boolean.new
74
+ b2.value = true
75
+ assert b2.attribute_present?(:value)
76
+
77
+ b3 = Boolean.new
78
+ assert !b3.attribute_present?(:value)
79
+
80
+ b4 = Boolean.new
81
+ b4.value = false
82
+ b4.save!
83
+ assert Boolean.find(b4.id).attribute_present?(:value)
84
+ end
85
+
86
+ def test_caching_nil_primary_key
87
+ klass = Class.new(Minimalistic)
88
+ assert_called(klass, :reset_primary_key, returns: nil) do
89
+ 2.times { klass.primary_key }
90
+ end
91
+ end
92
+
93
+ def test_attribute_keys_on_new_instance
94
+ t = Topic.new
95
+ assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
96
+ assert_raise(NoMethodError) { t.title2 }
97
+ end
98
+
99
+ def test_boolean_attributes
100
+ assert !Topic.find(1).approved?
101
+ assert Topic.find(2).approved?
102
+ end
103
+
104
+ def test_set_attributes
105
+ topic = Topic.find(1)
106
+ topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
107
+ topic.save
108
+ assert_equal("Budget", topic.title)
109
+ assert_equal("Jason", topic.author_name)
110
+ assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
111
+ end
112
+
113
+ def test_set_attributes_without_hash
114
+ topic = Topic.new
115
+ assert_raise(ArgumentError) { topic.attributes = '' }
116
+ end
117
+
118
+ def test_integers_as_nil
119
+ test = AutoId.create('value' => '')
120
+ assert_nil AutoId.find(test.id).value
121
+ end
122
+
123
+ def test_set_attributes_with_block
124
+ topic = Topic.new do |t|
125
+ t.title = "Budget"
126
+ t.author_name = "Jason"
127
+ end
128
+
129
+ assert_equal("Budget", topic.title)
130
+ assert_equal("Jason", topic.author_name)
131
+ end
132
+
133
+ def test_respond_to?
134
+ topic = Topic.find(1)
135
+ assert_respond_to topic, "title"
136
+ assert_respond_to topic, "title?"
137
+ assert_respond_to topic, "title="
138
+ assert_respond_to topic, :title
139
+ assert_respond_to topic, :title?
140
+ assert_respond_to topic, :title=
141
+ assert_respond_to topic, "author_name"
142
+ assert_respond_to topic, "attribute_names"
143
+ assert !topic.respond_to?("nothingness")
144
+ assert !topic.respond_to?(:nothingness)
145
+ end
146
+
147
+ def test_respond_to_with_custom_primary_key
148
+ keyboard = Keyboard.create
149
+ assert_not_nil keyboard.key_number
150
+ assert_equal keyboard.key_number, keyboard.id
151
+ assert keyboard.respond_to?('key_number')
152
+ assert keyboard.respond_to?('id')
153
+ end
154
+
155
+ def test_id_before_type_cast_with_custom_primary_key
156
+ keyboard = Keyboard.create
157
+ keyboard.key_number = '10'
158
+ assert_equal '10', keyboard.id_before_type_cast
159
+ assert_equal nil, keyboard.read_attribute_before_type_cast('id')
160
+ assert_equal '10', keyboard.read_attribute_before_type_cast('key_number')
161
+ assert_equal '10', keyboard.read_attribute_before_type_cast(:key_number)
162
+ end
163
+
164
+ # Syck calls respond_to? before actually calling initialize
165
+ def test_respond_to_with_allocated_object
166
+ klass = Class.new(ActiveRecord::Base) do
167
+ self.table_name = 'topics'
168
+ end
169
+
170
+ topic = klass.allocate
171
+ assert !topic.respond_to?("nothingness")
172
+ assert !topic.respond_to?(:nothingness)
173
+ assert_respond_to topic, "title"
174
+ assert_respond_to topic, :title
175
+ end
176
+
177
+ # IRB inspects the return value of "MyModel.allocate".
178
+ def test_allocated_object_can_be_inspected
179
+ topic = Topic.allocate
180
+ assert_equal "#<Topic not initialized>", topic.inspect
181
+ end
182
+
183
+ def test_array_content
184
+ topic = Topic.new
185
+ topic.content = %w( one two three )
186
+ topic.save
187
+
188
+ assert_equal(%w( one two three ), Topic.find(topic.id).content)
189
+ end
190
+
191
+ def test_read_attributes_before_type_cast
192
+ category = Category.new({:name=>"Test category", :type => nil})
193
+ category_attrs = {"name"=>"Test category", "id" => nil, "type" => nil, "categorizations_count" => nil}
194
+ assert_equal category_attrs , category.attributes_before_type_cast
195
+ end
196
+
197
+ if current_adapter?(:Mysql2Adapter)
198
+ def test_read_attributes_before_type_cast_on_boolean
199
+ bool = Boolean.create!({ "value" => false })
200
+ if RUBY_PLATFORM =~ /java/
201
+ # JRuby will return the value before typecast as string
202
+ assert_equal "0", bool.reload.attributes_before_type_cast["value"]
203
+ else
204
+ assert_equal 0, bool.reload.attributes_before_type_cast["value"]
205
+ end
206
+ end
207
+ end
208
+
209
+ def test_read_attributes_before_type_cast_on_datetime
210
+ in_time_zone "Pacific Time (US & Canada)" do
211
+ record = @target.new
212
+
213
+ record.written_on = "345643456"
214
+ assert_equal "345643456", record.written_on_before_type_cast
215
+ assert_equal nil, record.written_on
216
+
217
+ record.written_on = "2009-10-11 12:13:14"
218
+ assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast
219
+ assert_equal Time.zone.parse("2009-10-11 12:13:14"), record.written_on
220
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
221
+ end
222
+ end
223
+
224
+ def test_read_attributes_after_type_cast_on_datetime
225
+ tz = "Pacific Time (US & Canada)"
226
+
227
+ in_time_zone tz do
228
+ record = @target.new
229
+
230
+ date_string = "2011-03-24"
231
+ time = Time.zone.parse date_string
232
+
233
+ record.written_on = date_string
234
+ assert_equal date_string, record.written_on_before_type_cast
235
+ assert_equal time, record.written_on
236
+ assert_equal ActiveSupport::TimeZone[tz], record.written_on.time_zone
237
+
238
+ record.save
239
+ record.reload
240
+
241
+ assert_equal time, record.written_on
242
+ end
243
+ end
244
+
245
+ def test_hash_content
246
+ topic = Topic.new
247
+ topic.content = { "one" => 1, "two" => 2 }
248
+ topic.save
249
+
250
+ assert_equal 2, Topic.find(topic.id).content["two"]
251
+
252
+ topic.content_will_change!
253
+ topic.content["three"] = 3
254
+ topic.save
255
+
256
+ assert_equal 3, Topic.find(topic.id).content["three"]
257
+ end
258
+
259
+ def test_update_array_content
260
+ topic = Topic.new
261
+ topic.content = %w( one two three )
262
+
263
+ topic.content.push "four"
264
+ assert_equal(%w( one two three four ), topic.content)
265
+
266
+ topic.save
267
+
268
+ topic = Topic.find(topic.id)
269
+ topic.content << "five"
270
+ assert_equal(%w( one two three four five ), topic.content)
271
+ end
272
+
273
+ def test_case_sensitive_attributes_hash
274
+ # DB2 is not case-sensitive
275
+ return true if current_adapter?(:DB2Adapter)
276
+
277
+ assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.first.attributes
278
+ end
279
+
280
+ def test_attributes_without_primary_key
281
+ klass = Class.new(ActiveRecord::Base) do
282
+ self.table_name = 'developers_projects'
283
+ end
284
+
285
+ assert_equal klass.column_names, klass.new.attributes.keys
286
+ assert_not klass.new.has_attribute?('id')
287
+ end
288
+
289
+ def test_hashes_not_mangled
290
+ new_topic = { :title => "New Topic" }
291
+ new_topic_values = { :title => "AnotherTopic" }
292
+
293
+ topic = Topic.new(new_topic)
294
+ assert_equal new_topic[:title], topic.title
295
+
296
+ topic.attributes= new_topic_values
297
+ assert_equal new_topic_values[:title], topic.title
298
+ end
299
+
300
+ def test_create_through_factory
301
+ topic = Topic.create("title" => "New Topic")
302
+ topicReloaded = Topic.find(topic.id)
303
+ assert_equal(topic, topicReloaded)
304
+ end
305
+
306
+ def test_write_attribute
307
+ topic = Topic.new
308
+ topic.send(:write_attribute, :title, "Still another topic")
309
+ assert_equal "Still another topic", topic.title
310
+
311
+ topic[:title] = "Still another topic: part 2"
312
+ assert_equal "Still another topic: part 2", topic.title
313
+
314
+ topic.send(:write_attribute, "title", "Still another topic: part 3")
315
+ assert_equal "Still another topic: part 3", topic.title
316
+
317
+ topic["title"] = "Still another topic: part 4"
318
+ assert_equal "Still another topic: part 4", topic.title
319
+ end
320
+
321
+ def test_read_attribute
322
+ topic = Topic.new
323
+ topic.title = "Don't change the topic"
324
+ assert_equal "Don't change the topic", topic.read_attribute("title")
325
+ assert_equal "Don't change the topic", topic["title"]
326
+
327
+ assert_equal "Don't change the topic", topic.read_attribute(:title)
328
+ assert_equal "Don't change the topic", topic[:title]
329
+ end
330
+
331
+ def test_read_attribute_raises_missing_attribute_error_when_not_exists
332
+ computer = Computer.select('id').first
333
+ assert_raises(ActiveModel::MissingAttributeError) { computer[:developer] }
334
+ assert_raises(ActiveModel::MissingAttributeError) { computer[:extendedWarranty] }
335
+ assert_raises(ActiveModel::MissingAttributeError) { computer[:no_column_exists] = 'Hello!' }
336
+ assert_nothing_raised { computer[:developer] = 'Hello!' }
337
+ end
338
+
339
+ def test_read_attribute_when_false
340
+ topic = topics(:first)
341
+ topic.approved = false
342
+ assert !topic.approved?, "approved should be false"
343
+ topic.approved = "false"
344
+ assert !topic.approved?, "approved should be false"
345
+ end
346
+
347
+ def test_read_attribute_when_true
348
+ topic = topics(:first)
349
+ topic.approved = true
350
+ assert topic.approved?, "approved should be true"
351
+ topic.approved = "true"
352
+ assert topic.approved?, "approved should be true"
353
+ end
354
+
355
+ def test_read_write_boolean_attribute
356
+ topic = Topic.new
357
+ topic.approved = "false"
358
+ assert !topic.approved?, "approved should be false"
359
+
360
+ topic.approved = "false"
361
+ assert !topic.approved?, "approved should be false"
362
+
363
+ topic.approved = "true"
364
+ assert topic.approved?, "approved should be true"
365
+
366
+ topic.approved = "true"
367
+ assert topic.approved?, "approved should be true"
368
+ end
369
+
370
+ def test_overridden_write_attribute
371
+ topic = Topic.new
372
+ def topic.write_attribute(attr_name, value)
373
+ super(attr_name, value.downcase)
374
+ end
375
+
376
+ topic.send(:write_attribute, :title, "Yet another topic")
377
+ assert_equal "yet another topic", topic.title
378
+
379
+ topic[:title] = "Yet another topic: part 2"
380
+ assert_equal "yet another topic: part 2", topic.title
381
+
382
+ topic.send(:write_attribute, "title", "Yet another topic: part 3")
383
+ assert_equal "yet another topic: part 3", topic.title
384
+
385
+ topic["title"] = "Yet another topic: part 4"
386
+ assert_equal "yet another topic: part 4", topic.title
387
+ end
388
+
389
+ def test_overridden_read_attribute
390
+ topic = Topic.new
391
+ topic.title = "Stop changing the topic"
392
+ def topic.read_attribute(attr_name)
393
+ super(attr_name).upcase
394
+ end
395
+
396
+ assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute("title")
397
+ assert_equal "STOP CHANGING THE TOPIC", topic["title"]
398
+
399
+ assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute(:title)
400
+ assert_equal "STOP CHANGING THE TOPIC", topic[:title]
401
+ end
402
+
403
+ def test_read_overridden_attribute
404
+ topic = Topic.new(:title => 'a')
405
+ def topic.title() 'b' end
406
+ assert_equal 'a', topic[:title]
407
+ end
408
+
409
+ def test_query_attribute_string
410
+ [nil, "", " "].each do |value|
411
+ assert_equal false, Topic.new(:author_name => value).author_name?
412
+ end
413
+
414
+ assert_equal true, Topic.new(:author_name => "Name").author_name?
415
+ end
416
+
417
+ def test_query_attribute_number
418
+ [nil, 0, "0"].each do |value|
419
+ assert_equal false, Developer.new(:salary => value).salary?
420
+ end
421
+
422
+ assert_equal true, Developer.new(:salary => 1).salary?
423
+ assert_equal true, Developer.new(:salary => "1").salary?
424
+ end
425
+
426
+ def test_query_attribute_boolean
427
+ [nil, "", false, "false", "f", 0].each do |value|
428
+ assert_equal false, Topic.new(:approved => value).approved?
429
+ end
430
+
431
+ [true, "true", "1", 1].each do |value|
432
+ assert_equal true, Topic.new(:approved => value).approved?
433
+ end
434
+ end
435
+
436
+ def test_query_attribute_with_custom_fields
437
+ object = Company.find_by_sql(<<-SQL).first
438
+ SELECT c1.*, c2.type as string_value, c2.rating as int_value
439
+ FROM companies c1, companies c2
440
+ WHERE c1.firm_id = c2.id
441
+ AND c1.id = 2
442
+ SQL
443
+
444
+ assert_equal "Firm", object.string_value
445
+ assert object.string_value?
446
+
447
+ object.string_value = " "
448
+ assert !object.string_value?
449
+
450
+ assert_equal 1, object.int_value.to_i
451
+ assert object.int_value?
452
+
453
+ object.int_value = "0"
454
+ assert !object.int_value?
455
+ end
456
+
457
+ def test_non_attribute_access_and_assignment
458
+ topic = Topic.new
459
+ assert !topic.respond_to?("mumbo")
460
+ assert_raise(NoMethodError) { topic.mumbo }
461
+ assert_raise(NoMethodError) { topic.mumbo = 5 }
462
+ end
463
+
464
+ def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing
465
+ topic = @target.new(:title => 'Budget')
466
+ assert topic.respond_to?('title')
467
+ assert_equal 'Budget', topic.title
468
+ assert !topic.respond_to?('title_hello_world')
469
+ assert_raise(NoMethodError) { topic.title_hello_world }
470
+ end
471
+
472
+ def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing
473
+ topic = @target.new(:title => 'Budget')
474
+ %w(default_ title_).each do |prefix|
475
+ @target.class_eval "def #{prefix}attribute(*args) args end"
476
+ @target.attribute_method_prefix prefix
477
+
478
+ meth = "#{prefix}title"
479
+ assert topic.respond_to?(meth)
480
+ assert_equal ['title'], topic.send(meth)
481
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
482
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
483
+ end
484
+ end
485
+
486
+ def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing
487
+ %w(_default _title_default _it! _candidate= able?).each do |suffix|
488
+ @target.class_eval "def attribute#{suffix}(*args) args end"
489
+ @target.attribute_method_suffix suffix
490
+ topic = @target.new(:title => 'Budget')
491
+
492
+ meth = "title#{suffix}"
493
+ assert topic.respond_to?(meth)
494
+ assert_equal ['title'], topic.send(meth)
495
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
496
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
497
+ end
498
+ end
499
+
500
+ def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing
501
+ [['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix|
502
+ @target.class_eval "def #{prefix}attribute#{suffix}(*args) args end"
503
+ @target.attribute_method_affix({ :prefix => prefix, :suffix => suffix })
504
+ topic = @target.new(:title => 'Budget')
505
+
506
+ meth = "#{prefix}title#{suffix}"
507
+ assert topic.respond_to?(meth)
508
+ assert_equal ['title'], topic.send(meth)
509
+ assert_equal ['title', 'a'], topic.send(meth, 'a')
510
+ assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
511
+ end
512
+ end
513
+
514
+ def test_should_unserialize_attributes_for_frozen_records
515
+ myobj = {:value1 => :value2}
516
+ topic = Topic.create("content" => myobj)
517
+ topic.freeze
518
+ assert_equal myobj, topic.content
519
+ end
520
+
521
+ def test_typecast_attribute_from_select_to_false
522
+ Topic.create(:title => 'Budget')
523
+ # Oracle does not support boolean expressions in SELECT
524
+ if current_adapter?(:OracleAdapter, :FbAdapter)
525
+ topic = Topic.all.merge!(:select => "topics.*, 0 as is_test").first
526
+ else
527
+ topic = Topic.all.merge!(:select => "topics.*, 1=2 as is_test").first
528
+ end
529
+ assert !topic.is_test?
530
+ end
531
+
532
+ def test_typecast_attribute_from_select_to_true
533
+ Topic.create(:title => 'Budget')
534
+ # Oracle does not support boolean expressions in SELECT
535
+ if current_adapter?(:OracleAdapter, :FbAdapter)
536
+ topic = Topic.all.merge!(:select => "topics.*, 1 as is_test").first
537
+ else
538
+ topic = Topic.all.merge!(:select => "topics.*, 2=2 as is_test").first
539
+ end
540
+ assert topic.is_test?
541
+ end
542
+
543
+ def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
544
+ %w(save create_or_update).each do |method|
545
+ klass = Class.new ActiveRecord::Base
546
+ klass.class_eval "def #{method}() 'defined #{method}' end"
547
+ assert_raise ActiveRecord::DangerousAttributeError do
548
+ klass.instance_method_already_implemented?(method)
549
+ end
550
+ end
551
+ end
552
+
553
+ def test_converted_values_are_returned_after_assignment
554
+ developer = Developer.new(name: 1337, salary: "50000")
555
+
556
+ assert_equal "50000", developer.salary_before_type_cast
557
+ assert_equal 1337, developer.name_before_type_cast
558
+
559
+ assert_equal 50000, developer.salary
560
+ assert_equal "1337", developer.name
561
+
562
+ developer.save!
563
+
564
+ assert_equal 50000, developer.salary
565
+ assert_equal "1337", developer.name
566
+ end
567
+
568
+ def test_write_nil_to_time_attributes
569
+ in_time_zone "Pacific Time (US & Canada)" do
570
+ record = @target.new
571
+ record.written_on = nil
572
+ assert_nil record.written_on
573
+ end
574
+ end
575
+
576
+ def test_write_time_to_date_attributes
577
+ in_time_zone "Pacific Time (US & Canada)" do
578
+ record = @target.new
579
+ record.last_read = Time.utc(2010, 1, 1, 10)
580
+ assert_equal Date.civil(2010, 1, 1), record.last_read
581
+ end
582
+ end
583
+
584
+ def test_time_attributes_are_retrieved_in_current_time_zone
585
+ in_time_zone "Pacific Time (US & Canada)" do
586
+ utc_time = Time.utc(2008, 1, 1)
587
+ record = @target.new
588
+ record[:written_on] = utc_time
589
+ assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
590
+ assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
591
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
592
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
593
+ end
594
+ end
595
+
596
+ def test_setting_time_zone_aware_attribute_to_utc
597
+ in_time_zone "Pacific Time (US & Canada)" do
598
+ utc_time = Time.utc(2008, 1, 1)
599
+ record = @target.new
600
+ record.written_on = utc_time
601
+ assert_equal utc_time, record.written_on
602
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
603
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
604
+ end
605
+ end
606
+
607
+ def test_setting_time_zone_aware_attribute_in_other_time_zone
608
+ utc_time = Time.utc(2008, 1, 1)
609
+ cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
610
+ in_time_zone "Pacific Time (US & Canada)" do
611
+ record = @target.new
612
+ record.written_on = cst_time
613
+ assert_equal utc_time, record.written_on
614
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
615
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
616
+ end
617
+ end
618
+
619
+ def test_setting_time_zone_aware_read_attribute
620
+ utc_time = Time.utc(2008, 1, 1)
621
+ cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
622
+ in_time_zone "Pacific Time (US & Canada)" do
623
+ record = @target.create(:written_on => cst_time).reload
624
+ assert_equal utc_time, record[:written_on]
625
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record[:written_on].time_zone
626
+ assert_equal Time.utc(2007, 12, 31, 16), record[:written_on].time
627
+ end
628
+ end
629
+
630
+ def test_setting_time_zone_aware_attribute_with_string
631
+ utc_time = Time.utc(2008, 1, 1)
632
+ (-11..13).each do |timezone_offset|
633
+ time_string = utc_time.in_time_zone(timezone_offset).to_s
634
+ in_time_zone "Pacific Time (US & Canada)" do
635
+ record = @target.new
636
+ record.written_on = time_string
637
+ assert_equal Time.zone.parse(time_string), record.written_on
638
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
639
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
640
+ end
641
+ end
642
+ end
643
+
644
+ def test_time_zone_aware_attribute_saved
645
+ in_time_zone 1 do
646
+ record = @target.create(:written_on => '2012-02-20 10:00')
647
+
648
+ record.written_on = '2012-02-20 09:00'
649
+ record.save
650
+ assert_equal Time.zone.local(2012, 02, 20, 9), record.reload.written_on
651
+ end
652
+ end
653
+
654
+ def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
655
+ in_time_zone "Pacific Time (US & Canada)" do
656
+ record = @target.new
657
+ record.written_on = ' '
658
+ assert_nil record.written_on
659
+ assert_nil record[:written_on]
660
+ end
661
+ end
662
+
663
+ def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
664
+ time_string = 'Tue Jan 01 00:00:00 2008'
665
+ (-11..13).each do |timezone_offset|
666
+ in_time_zone timezone_offset do
667
+ record = @target.new
668
+ record.written_on = time_string
669
+ assert_equal Time.zone.parse(time_string), record.written_on
670
+ assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
671
+ assert_equal Time.utc(2008, 1, 1), record.written_on.time
672
+ end
673
+ end
674
+ end
675
+
676
+ def test_setting_time_zone_aware_datetime_in_current_time_zone
677
+ utc_time = Time.utc(2008, 1, 1)
678
+ in_time_zone "Pacific Time (US & Canada)" do
679
+ record = @target.new
680
+ record.written_on = utc_time.in_time_zone
681
+ assert_equal utc_time, record.written_on
682
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
683
+ assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
684
+ end
685
+ end
686
+
687
+ def test_yaml_dumping_record_with_time_zone_aware_attribute
688
+ in_time_zone "Pacific Time (US & Canada)" do
689
+ record = Topic.new(id: 1)
690
+ record.written_on = "Jan 01 00:00:00 2014"
691
+ assert_equal record, YAML.load(YAML.dump(record))
692
+ end
693
+ end
694
+
695
+ def test_setting_time_zone_aware_time_in_current_time_zone
696
+ in_time_zone "Pacific Time (US & Canada)" do
697
+ record = @target.new
698
+ time_string = "10:00:00"
699
+ expected_time = Time.zone.parse("2000-01-01 #{time_string}")
700
+
701
+ record.bonus_time = time_string
702
+ assert_equal expected_time, record.bonus_time
703
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.bonus_time.time_zone
704
+
705
+ record.bonus_time = ''
706
+ assert_nil record.bonus_time
707
+ end
708
+ end
709
+
710
+ def test_setting_time_zone_aware_time_with_dst
711
+ in_time_zone "Pacific Time (US & Canada)" do
712
+ current_time = Time.zone.local(2014, 06, 15, 10)
713
+ record = @target.new(bonus_time: current_time)
714
+ time_before_save = record.bonus_time
715
+
716
+ record.save
717
+ record.reload
718
+
719
+ assert_equal time_before_save, record.bonus_time
720
+ assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.bonus_time.time_zone
721
+ end
722
+ end
723
+
724
+ def test_removing_time_zone_aware_types
725
+ with_time_zone_aware_types(:datetime) do
726
+ in_time_zone "Pacific Time (US & Canada)" do
727
+ record = @target.new(bonus_time: "10:00:00")
728
+ expected_time = Time.utc(2000, 01, 01, 10)
729
+
730
+ assert_equal expected_time, record.bonus_time
731
+ assert record.bonus_time.utc?
732
+ end
733
+ end
734
+ end
735
+
736
+ def test_time_zone_aware_attributes_dont_recurse_infinitely_on_invalid_values
737
+ in_time_zone "Pacific Time (US & Canada)" do
738
+ record = @target.new(bonus_time: [])
739
+ assert_equal nil, record.bonus_time
740
+ end
741
+ end
742
+
743
+ def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
744
+ Topic.skip_time_zone_conversion_for_attributes = [:field_a]
745
+ Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
746
+
747
+ assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
748
+ assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
749
+ end
750
+
751
+ def test_read_attributes_respect_access_control
752
+ privatize("title")
753
+
754
+ topic = @target.new(:title => "The pros and cons of programming naked.")
755
+ assert !topic.respond_to?(:title)
756
+ exception = assert_raise(NoMethodError) { topic.title }
757
+ assert exception.message.include?("private method")
758
+ assert_equal "I'm private", topic.send(:title)
759
+ end
760
+
761
+ def test_write_attributes_respect_access_control
762
+ privatize("title=(value)")
763
+
764
+ topic = @target.new
765
+ assert !topic.respond_to?(:title=)
766
+ exception = assert_raise(NoMethodError) { topic.title = "Pants"}
767
+ assert exception.message.include?("private method")
768
+ topic.send(:title=, "Very large pants")
769
+ end
770
+
771
+ def test_question_attributes_respect_access_control
772
+ privatize("title?")
773
+
774
+ topic = @target.new(:title => "Isaac Newton's pants")
775
+ assert !topic.respond_to?(:title?)
776
+ exception = assert_raise(NoMethodError) { topic.title? }
777
+ assert exception.message.include?("private method")
778
+ assert topic.send(:title?)
779
+ end
780
+
781
+ def test_bulk_update_respects_access_control
782
+ privatize("title=(value)")
783
+
784
+ assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(:title => "Rants about pants") }
785
+ assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
786
+ end
787
+
788
+ def test_bulk_update_raise_unknown_attribute_error
789
+ error = assert_raises(ActiveRecord::UnknownAttributeError) {
790
+ Topic.new(hello: "world")
791
+ }
792
+ assert_instance_of Topic, error.record
793
+ assert_equal "hello", error.attribute
794
+ assert_equal "unknown attribute 'hello' for Topic.", error.message
795
+ end
796
+
797
+ def test_methods_override_in_multi_level_subclass
798
+ klass = Class.new(Developer) do
799
+ def name
800
+ "dev:#{read_attribute(:name)}"
801
+ end
802
+ end
803
+
804
+ 2.times { klass = Class.new klass }
805
+ dev = klass.new(name: 'arthurnn')
806
+ dev.save!
807
+ assert_equal 'dev:arthurnn', dev.reload.name
808
+ end
809
+
810
+ def test_global_methods_are_overwritten
811
+ klass = Class.new(ActiveRecord::Base) do
812
+ self.table_name = 'computers'
813
+ end
814
+
815
+ assert !klass.instance_method_already_implemented?(:system)
816
+ computer = klass.new
817
+ assert_nil computer.system
818
+ end
819
+
820
+ def test_global_methods_are_overwritten_when_subclassing
821
+ klass = Class.new(ActiveRecord::Base) { self.abstract_class = true }
822
+
823
+ subklass = Class.new(klass) do
824
+ self.table_name = 'computers'
825
+ end
826
+
827
+ assert !klass.instance_method_already_implemented?(:system)
828
+ assert !subklass.instance_method_already_implemented?(:system)
829
+ computer = subklass.new
830
+ assert_nil computer.system
831
+ end
832
+
833
+ def test_instance_method_should_be_defined_on_the_base_class
834
+ subklass = Class.new(Topic)
835
+
836
+ Topic.define_attribute_methods
837
+
838
+ instance = subklass.new
839
+ instance.id = 5
840
+ assert_equal 5, instance.id
841
+ assert subklass.method_defined?(:id), "subklass is missing id method"
842
+
843
+ Topic.undefine_attribute_methods
844
+
845
+ assert_equal 5, instance.id
846
+ assert subklass.method_defined?(:id), "subklass is missing id method"
847
+ end
848
+
849
+ def test_read_attribute_with_nil_should_not_asplode
850
+ assert_equal nil, Topic.new.read_attribute(nil)
851
+ end
852
+
853
+ # If B < A, and A defines an accessor for 'foo', we don't want to override
854
+ # that by defining a 'foo' method in the generated methods module for B.
855
+ # (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].)
856
+ def test_inherited_custom_accessors
857
+ klass = new_topic_like_ar_class do
858
+ self.abstract_class = true
859
+ def title; "omg"; end
860
+ def title=(val); self.author_name = val; end
861
+ end
862
+ subklass = Class.new(klass)
863
+ [klass, subklass].each(&:define_attribute_methods)
864
+
865
+ topic = subklass.find(1)
866
+ assert_equal "omg", topic.title
867
+
868
+ topic.title = "lol"
869
+ assert_equal "lol", topic.author_name
870
+ end
871
+
872
+ def test_inherited_custom_accessors_with_reserved_names
873
+ klass = Class.new(ActiveRecord::Base) do
874
+ self.table_name = 'computers'
875
+ self.abstract_class = true
876
+ def system; "omg"; end
877
+ def system=(val); self.developer = val; end
878
+ end
879
+
880
+ subklass = Class.new(klass)
881
+ [klass, subklass].each(&:define_attribute_methods)
882
+
883
+ computer = subklass.find(1)
884
+ assert_equal "omg", computer.system
885
+
886
+ computer.developer = 99
887
+ assert_equal 99, computer.developer
888
+ end
889
+
890
+ def test_on_the_fly_super_invokable_generated_attribute_methods_via_method_missing
891
+ klass = new_topic_like_ar_class do
892
+ def title
893
+ super + '!'
894
+ end
895
+ end
896
+
897
+ real_topic = topics(:first)
898
+ assert_equal real_topic.title + '!', klass.find(real_topic.id).title
899
+ end
900
+
901
+ def test_on_the_fly_super_invokable_generated_predicate_attribute_methods_via_method_missing
902
+ klass = new_topic_like_ar_class do
903
+ def title?
904
+ !super
905
+ end
906
+ end
907
+
908
+ real_topic = topics(:first)
909
+ assert_equal !real_topic.title?, klass.find(real_topic.id).title?
910
+ end
911
+
912
+ def test_calling_super_when_parent_does_not_define_method_raises_error
913
+ klass = new_topic_like_ar_class do
914
+ def some_method_that_is_not_on_super
915
+ super
916
+ end
917
+ end
918
+
919
+ assert_raise(NoMethodError) do
920
+ klass.new.some_method_that_is_not_on_super
921
+ end
922
+ end
923
+
924
+ def test_attribute_method?
925
+ assert @target.attribute_method?(:title)
926
+ assert @target.attribute_method?(:title=)
927
+ assert_not @target.attribute_method?(:wibble)
928
+ end
929
+
930
+ def test_attribute_method_returns_false_if_table_does_not_exist
931
+ @target.table_name = 'wibble'
932
+ assert_not @target.attribute_method?(:title)
933
+ end
934
+
935
+ def test_attribute_names_on_new_record
936
+ model = @target.new
937
+
938
+ assert_equal @target.column_names, model.attribute_names
939
+ end
940
+
941
+ def test_attribute_names_on_queried_record
942
+ model = @target.last!
943
+
944
+ assert_equal @target.column_names, model.attribute_names
945
+ end
946
+
947
+ def test_attribute_names_with_custom_select
948
+ model = @target.select('id').last!
949
+
950
+ assert_equal ['id'], model.attribute_names
951
+ # Sanity check, make sure other columns exist
952
+ assert_not_equal ['id'], @target.column_names
953
+ end
954
+
955
+ def test_came_from_user
956
+ model = @target.first
957
+
958
+ assert_not model.id_came_from_user?
959
+ model.id = "omg"
960
+ assert model.id_came_from_user?
961
+ end
962
+
963
+ def test_accessed_fields
964
+ model = @target.first
965
+
966
+ assert_equal [], model.accessed_fields
967
+
968
+ model.title
969
+
970
+ assert_equal ["title"], model.accessed_fields
971
+ end
972
+
973
+ private
974
+
975
+ def new_topic_like_ar_class(&block)
976
+ klass = Class.new(ActiveRecord::Base) do
977
+ self.table_name = 'topics'
978
+ class_eval(&block)
979
+ end
980
+
981
+ assert_empty klass.generated_attribute_methods.instance_methods(false)
982
+ klass
983
+ end
984
+
985
+ def with_time_zone_aware_types(*types)
986
+ old_types = ActiveRecord::Base.time_zone_aware_types
987
+ ActiveRecord::Base.time_zone_aware_types = types
988
+ yield
989
+ ensure
990
+ ActiveRecord::Base.time_zone_aware_types = old_types
991
+ end
992
+
993
+ def cached_columns
994
+ Topic.columns.map(&:name)
995
+ end
996
+
997
+ def time_related_columns_on_topic
998
+ Topic.columns.select { |c| [:time, :date, :datetime, :timestamp].include?(c.type) }
999
+ end
1000
+
1001
+ def privatize(method_signature)
1002
+ @target.class_eval(<<-private_method, __FILE__, __LINE__ + 1)
1003
+ private
1004
+ def #{method_signature}
1005
+ "I'm private"
1006
+ end
1007
+ private_method
1008
+ end
1009
+ end