ibm_db 3.0.0-x86-mingw32 → 3.0.1-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 (465) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +4 -0
  3. data/MANIFEST +14 -14
  4. data/README +225 -225
  5. data/ext/Makefile.nt32 +181 -181
  6. data/ext/Makefile.nt32.191 +212 -212
  7. data/ext/OLD/extconf.rb +264 -0
  8. data/ext/{extconf_MacOS.rb → OLD/extconf_MacOS.rb} +269 -269
  9. data/ext/extconf.rb +291 -264
  10. data/ext/ibm_db.c +2 -2
  11. data/ext/ruby_ibm_db.h +241 -241
  12. data/ext/ruby_ibm_db_cli.h +500 -500
  13. data/init.rb +41 -41
  14. data/lib/IBM_DB.rb +27 -27
  15. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +4 -4
  16. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +1 -1
  17. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  18. data/lib/mswin32/ibm_db.rb +115 -115
  19. data/test/active_record/connection_adapters/fake_adapter.rb +46 -0
  20. data/test/assets/example.log +1 -0
  21. data/test/assets/flowers.jpg +0 -0
  22. data/test/assets/test.txt +1 -0
  23. data/test/cases/adapter_test.rb +261 -207
  24. data/test/cases/aggregations_test.rb +158 -0
  25. data/test/cases/ar_schema_test.rb +161 -0
  26. data/test/cases/associations/association_scope_test.rb +21 -0
  27. data/test/cases/associations/belongs_to_associations_test.rb +1029 -711
  28. data/test/cases/associations/callbacks_test.rb +192 -0
  29. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -181
  30. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +26 -0
  31. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -0
  32. data/test/cases/associations/eager_load_nested_include_test.rb +128 -0
  33. data/test/cases/associations/eager_singularization_test.rb +148 -0
  34. data/test/cases/associations/eager_test.rb +1411 -0
  35. data/test/cases/associations/extension_test.rb +82 -0
  36. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +932 -851
  37. data/test/cases/associations/has_many_associations_test.rb +2162 -0
  38. data/test/cases/associations/has_many_through_associations_test.rb +1204 -0
  39. data/test/cases/associations/has_one_associations_test.rb +610 -0
  40. data/test/cases/associations/has_one_through_associations_test.rb +380 -0
  41. data/test/cases/associations/inner_join_association_test.rb +139 -0
  42. data/test/cases/associations/inverse_associations_test.rb +693 -0
  43. data/test/cases/associations/join_model_test.rb +754 -743
  44. data/test/cases/associations/nested_through_associations_test.rb +579 -0
  45. data/test/cases/associations/required_test.rb +82 -0
  46. data/test/cases/associations_test.rb +380 -0
  47. data/test/cases/attribute_decorators_test.rb +125 -0
  48. data/test/cases/attribute_methods/read_test.rb +60 -0
  49. data/test/cases/attribute_methods/serialization_test.rb +29 -0
  50. data/test/cases/attribute_methods_test.rb +952 -822
  51. data/test/cases/attribute_set_test.rb +200 -0
  52. data/test/cases/attribute_test.rb +180 -0
  53. data/test/cases/attributes_test.rb +136 -0
  54. data/test/cases/autosave_association_test.rb +1595 -0
  55. data/test/cases/base_test.rb +1638 -2133
  56. data/test/cases/batches_test.rb +212 -0
  57. data/test/cases/binary_test.rb +52 -0
  58. data/test/cases/bind_parameter_test.rb +100 -0
  59. data/test/cases/calculations_test.rb +646 -482
  60. data/test/cases/callbacks_test.rb +543 -0
  61. data/test/cases/clone_test.rb +40 -0
  62. data/test/cases/coders/yaml_column_test.rb +63 -0
  63. data/test/cases/column_alias_test.rb +17 -0
  64. data/test/cases/column_definition_test.rb +123 -0
  65. data/test/cases/connection_adapters/adapter_leasing_test.rb +54 -0
  66. data/test/cases/connection_adapters/connection_handler_test.rb +53 -0
  67. data/test/cases/connection_adapters/connection_specification_test.rb +12 -0
  68. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +293 -0
  69. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +65 -0
  70. data/test/cases/connection_adapters/quoting_test.rb +13 -0
  71. data/test/cases/connection_adapters/schema_cache_test.rb +56 -0
  72. data/test/cases/connection_adapters/type_lookup_test.rb +110 -0
  73. data/test/cases/connection_management_test.rb +122 -0
  74. data/test/cases/connection_pool_test.rb +346 -0
  75. data/test/cases/connection_specification/resolver_test.rb +116 -0
  76. data/test/cases/core_test.rb +112 -0
  77. data/test/cases/counter_cache_test.rb +209 -0
  78. data/test/cases/custom_locking_test.rb +17 -0
  79. data/test/cases/database_statements_test.rb +19 -0
  80. data/test/cases/date_time_test.rb +61 -0
  81. data/test/cases/defaults_test.rb +223 -0
  82. data/test/cases/dirty_test.rb +775 -0
  83. data/test/cases/disconnected_test.rb +28 -0
  84. data/test/cases/dup_test.rb +157 -0
  85. data/test/cases/enum_test.rb +290 -0
  86. data/test/cases/explain_subscriber_test.rb +64 -0
  87. data/test/cases/explain_test.rb +76 -0
  88. data/test/cases/finder_respond_to_test.rb +60 -0
  89. data/test/cases/finder_test.rb +1166 -0
  90. data/test/cases/fixture_set/file_test.rb +138 -0
  91. data/test/cases/fixtures_test.rb +897 -0
  92. data/test/cases/forbidden_attributes_protection_test.rb +99 -0
  93. data/test/cases/habtm_destroy_order_test.rb +61 -0
  94. data/test/cases/helper.rb +210 -0
  95. data/test/cases/hot_compatibility_test.rb +54 -0
  96. data/test/cases/i18n_test.rb +45 -0
  97. data/test/cases/inheritance_test.rb +375 -0
  98. data/test/cases/integration_test.rb +139 -0
  99. data/test/cases/invalid_connection_test.rb +22 -0
  100. data/test/cases/invalid_date_test.rb +32 -0
  101. data/test/cases/invertible_migration_test.rb +295 -0
  102. data/test/cases/json_serialization_test.rb +302 -0
  103. data/test/cases/locking_test.rb +477 -0
  104. data/test/cases/log_subscriber_test.rb +136 -0
  105. data/test/cases/migration/change_schema_test - Copy.rb +448 -0
  106. data/test/cases/migration/change_schema_test.rb +472 -0
  107. data/test/cases/migration/change_table_test.rb +224 -0
  108. data/test/cases/migration/column_attributes_test.rb +192 -0
  109. data/test/cases/migration/column_positioning_test.rb +56 -0
  110. data/test/cases/migration/columns_test.rb +304 -0
  111. data/test/cases/migration/command_recorder_test.rb +305 -0
  112. data/test/cases/migration/create_join_table_test.rb +148 -0
  113. data/test/cases/migration/foreign_key_test - Changed.rb +325 -0
  114. data/test/cases/migration/foreign_key_test.rb +360 -0
  115. data/test/cases/migration/helper.rb +39 -0
  116. data/test/cases/migration/index_test.rb +216 -0
  117. data/test/cases/migration/logger_test.rb +36 -0
  118. data/test/cases/migration/pending_migrations_test.rb +53 -0
  119. data/test/cases/migration/references_foreign_key_test.rb +214 -0
  120. data/test/cases/migration/references_index_test.rb +101 -0
  121. data/test/cases/migration/references_statements_test.rb +116 -0
  122. data/test/cases/migration/rename_table_test.rb +93 -0
  123. data/test/cases/migration/table_and_index_test.rb +24 -0
  124. data/test/cases/migration_test.rb +959 -2408
  125. data/test/cases/migrator_test.rb +388 -0
  126. data/test/cases/mixin_test.rb +70 -0
  127. data/test/cases/modules_test.rb +173 -0
  128. data/test/cases/multiparameter_attributes_test.rb +350 -0
  129. data/test/cases/multiple_db_test.rb +115 -0
  130. data/test/cases/nested_attributes_test.rb +1057 -0
  131. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -0
  132. data/test/cases/persistence_test.rb +909 -642
  133. data/test/cases/pooled_connections_test.rb +81 -0
  134. data/test/cases/primary_keys_test.rb +237 -0
  135. data/test/cases/query_cache_test.rb +326 -257
  136. data/test/cases/quoting_test.rb +156 -0
  137. data/test/cases/readonly_test.rb +118 -0
  138. data/test/cases/reaper_test.rb +85 -0
  139. data/test/cases/reflection_test.rb +454 -0
  140. data/test/cases/relation/delegation_test.rb +68 -0
  141. data/test/cases/relation/merging_test.rb +161 -0
  142. data/test/cases/relation/mutation_test.rb +165 -0
  143. data/test/cases/relation/predicate_builder_test.rb +14 -0
  144. data/test/cases/relation/where_chain_test.rb +181 -0
  145. data/test/cases/relation/where_test.rb +300 -0
  146. data/test/cases/relation/where_test2.rb +36 -0
  147. data/test/cases/relation_test.rb +297 -0
  148. data/test/cases/relations_test.rb +1815 -1182
  149. data/test/cases/reload_models_test.rb +22 -0
  150. data/test/cases/result_test.rb +80 -0
  151. data/test/cases/sanitize_test.rb +83 -0
  152. data/test/cases/schema_dumper_test.rb +463 -256
  153. data/test/cases/scoping/default_scoping_test.rb +454 -0
  154. data/test/cases/scoping/named_scoping_test.rb +524 -0
  155. data/test/cases/scoping/relation_scoping_test.rb +357 -0
  156. data/test/cases/serialization_test.rb +104 -0
  157. data/test/cases/serialized_attribute_test.rb +277 -0
  158. data/test/cases/statement_cache_test.rb +98 -0
  159. data/test/cases/store_test.rb +194 -0
  160. data/test/cases/tasks/database_tasks_test.rb +396 -0
  161. data/test/cases/tasks/mysql_rake_test.rb +311 -0
  162. data/test/cases/tasks/postgresql_rake_test.rb +245 -0
  163. data/test/cases/tasks/sqlite_rake_test.rb +193 -0
  164. data/test/cases/test_case.rb +123 -0
  165. data/test/cases/timestamp_test.rb +468 -0
  166. data/test/cases/transaction_callbacks_test.rb +452 -300
  167. data/test/cases/transaction_isolation_test.rb +106 -0
  168. data/test/cases/transactions_test.rb +817 -0
  169. data/test/cases/type/decimal_test.rb +51 -0
  170. data/test/cases/type/integer_test.rb +121 -0
  171. data/test/cases/type/string_test.rb +36 -0
  172. data/test/cases/type/type_map_test.rb +177 -0
  173. data/test/cases/type/unsigned_integer_test.rb +18 -0
  174. data/test/cases/types_test.rb +141 -0
  175. data/test/cases/unconnected_test.rb +33 -0
  176. data/test/cases/validations/association_validation_test.rb +86 -0
  177. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -0
  178. data/test/cases/validations/i18n_validation_test.rb +90 -0
  179. data/test/cases/validations/length_validation_test.rb +47 -0
  180. data/test/cases/validations/presence_validation_test.rb +68 -0
  181. data/test/cases/validations/uniqueness_validation_test.rb +434 -299
  182. data/test/cases/validations_repair_helper.rb +23 -0
  183. data/test/cases/validations_test.rb +165 -0
  184. data/test/cases/view_test.rb +113 -0
  185. data/test/cases/xml_serialization_test.rb +457 -408
  186. data/test/cases/yaml_serialization_test.rb +86 -0
  187. data/test/config.rb +5 -0
  188. data/test/config.yml +154 -154
  189. data/test/connections/native_ibm_db/connection.rb +43 -43
  190. data/test/fixtures/accounts.yml +29 -0
  191. data/test/fixtures/admin/accounts.yml +2 -0
  192. data/test/fixtures/admin/randomly_named_a9.yml +7 -0
  193. data/test/fixtures/admin/randomly_named_b0.yml +7 -0
  194. data/test/fixtures/admin/users.yml +10 -0
  195. data/test/fixtures/all/admin +1 -0
  196. data/test/fixtures/all/developers.yml +0 -0
  197. data/test/fixtures/all/people.yml +0 -0
  198. data/test/fixtures/all/tasks.yml +0 -0
  199. data/test/fixtures/author_addresses.yml +18 -0
  200. data/test/fixtures/author_favorites.yml +4 -0
  201. data/test/fixtures/authors.yml +23 -0
  202. data/test/fixtures/binaries.yml +133 -0
  203. data/test/fixtures/books.yml +11 -0
  204. data/test/fixtures/bulbs.yml +5 -0
  205. data/test/fixtures/cars.yml +9 -0
  206. data/test/fixtures/categories.yml +19 -0
  207. data/test/fixtures/categories/special_categories.yml +9 -0
  208. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -0
  209. data/test/fixtures/categories_ordered.yml +7 -0
  210. data/test/fixtures/categories_posts.yml +31 -0
  211. data/test/fixtures/categorizations.yml +23 -0
  212. data/test/fixtures/clubs.yml +8 -0
  213. data/test/fixtures/collections.yml +3 -0
  214. data/test/fixtures/colleges.yml +3 -0
  215. data/test/fixtures/comments.yml +65 -0
  216. data/test/fixtures/companies.yml +67 -0
  217. data/test/fixtures/computers.yml +10 -0
  218. data/test/fixtures/courses.yml +8 -0
  219. data/test/fixtures/customers.yml +26 -0
  220. data/test/fixtures/dashboards.yml +6 -0
  221. data/test/fixtures/developers.yml +22 -0
  222. data/test/fixtures/developers_projects.yml +17 -0
  223. data/test/fixtures/dog_lovers.yml +7 -0
  224. data/test/fixtures/dogs.yml +4 -0
  225. data/test/fixtures/doubloons.yml +3 -0
  226. data/test/fixtures/edges.yml +5 -0
  227. data/test/fixtures/entrants.yml +14 -0
  228. data/test/fixtures/essays.yml +6 -0
  229. data/test/fixtures/faces.yml +11 -0
  230. data/test/fixtures/fk_test_has_fk.yml +3 -0
  231. data/test/fixtures/fk_test_has_pk.yml +2 -0
  232. data/test/fixtures/friendships.yml +4 -0
  233. data/test/fixtures/funny_jokes.yml +10 -0
  234. data/test/fixtures/interests.yml +33 -0
  235. data/test/fixtures/items.yml +3 -0
  236. data/test/fixtures/jobs.yml +7 -0
  237. data/test/fixtures/legacy_things.yml +3 -0
  238. data/test/fixtures/mateys.yml +4 -0
  239. data/test/fixtures/member_details.yml +8 -0
  240. data/test/fixtures/member_types.yml +6 -0
  241. data/test/fixtures/members.yml +11 -0
  242. data/test/fixtures/memberships.yml +34 -0
  243. data/test/fixtures/men.yml +5 -0
  244. data/test/fixtures/minimalistics.yml +2 -0
  245. data/test/fixtures/minivans.yml +5 -0
  246. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  247. data/test/fixtures/mixins.yml +29 -0
  248. data/test/fixtures/movies.yml +7 -0
  249. data/test/fixtures/naked/csv/accounts.csv +1 -0
  250. data/test/fixtures/naked/yml/accounts.yml +1 -0
  251. data/test/fixtures/naked/yml/companies.yml +1 -0
  252. data/test/fixtures/naked/yml/courses.yml +1 -0
  253. data/test/fixtures/organizations.yml +5 -0
  254. data/test/fixtures/other_topics.yml +42 -0
  255. data/test/fixtures/owners.yml +9 -0
  256. data/test/fixtures/parrots.yml +27 -0
  257. data/test/fixtures/parrots_pirates.yml +7 -0
  258. data/test/fixtures/people.yml +24 -0
  259. data/test/fixtures/peoples_treasures.yml +3 -0
  260. data/test/fixtures/pets.yml +19 -0
  261. data/test/fixtures/pirates.yml +12 -0
  262. data/test/fixtures/posts.yml +80 -0
  263. data/test/fixtures/price_estimates.yml +7 -0
  264. data/test/fixtures/products.yml +4 -0
  265. data/test/fixtures/projects.yml +7 -0
  266. data/test/fixtures/randomly_named_a9.yml +7 -0
  267. data/test/fixtures/ratings.yml +14 -0
  268. data/test/fixtures/readers.yml +11 -0
  269. data/test/fixtures/references.yml +17 -0
  270. data/test/fixtures/reserved_words/distinct.yml +5 -0
  271. data/test/fixtures/reserved_words/distinct_select.yml +11 -0
  272. data/test/fixtures/reserved_words/group.yml +14 -0
  273. data/test/fixtures/reserved_words/select.yml +8 -0
  274. data/test/fixtures/reserved_words/values.yml +7 -0
  275. data/test/fixtures/ships.yml +6 -0
  276. data/test/fixtures/speedometers.yml +8 -0
  277. data/test/fixtures/sponsors.yml +12 -0
  278. data/test/fixtures/string_key_objects.yml +7 -0
  279. data/test/fixtures/subscribers.yml +11 -0
  280. data/test/fixtures/subscriptions.yml +12 -0
  281. data/test/fixtures/taggings.yml +78 -0
  282. data/test/fixtures/tags.yml +11 -0
  283. data/test/fixtures/tasks.yml +7 -0
  284. data/test/fixtures/teapots.yml +3 -0
  285. data/test/fixtures/to_be_linked/accounts.yml +2 -0
  286. data/test/fixtures/to_be_linked/users.yml +10 -0
  287. data/test/fixtures/topics.yml +49 -0
  288. data/test/fixtures/toys.yml +14 -0
  289. data/test/fixtures/traffic_lights.yml +10 -0
  290. data/test/fixtures/treasures.yml +10 -0
  291. data/test/fixtures/uuid_children.yml +3 -0
  292. data/test/fixtures/uuid_parents.yml +2 -0
  293. data/test/fixtures/variants.yml +4 -0
  294. data/test/fixtures/vegetables.yml +20 -0
  295. data/test/fixtures/vertices.yml +4 -0
  296. data/test/fixtures/warehouse_things.yml +3 -0
  297. data/test/fixtures/zines.yml +5 -0
  298. data/test/ibm_db_test.rb +24 -24
  299. data/test/migrations/10_urban/9_add_expressions.rb +11 -0
  300. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
  301. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -0
  302. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
  303. data/test/migrations/missing/1_people_have_last_names.rb +9 -0
  304. data/test/migrations/missing/3_we_need_reminders.rb +12 -0
  305. data/test/migrations/missing/4_innocent_jointable.rb +12 -0
  306. data/test/migrations/rename/1_we_need_things.rb +11 -0
  307. data/test/migrations/rename/2_rename_things.rb +9 -0
  308. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -0
  309. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -0
  310. data/test/migrations/to_copy2/1_create_articles.rb +7 -0
  311. data/test/migrations/to_copy2/2_create_comments.rb +7 -0
  312. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -0
  313. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -0
  314. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -0
  315. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -0
  316. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -0
  317. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -0
  318. data/test/migrations/valid/2_we_need_reminders.rb +12 -0
  319. data/test/migrations/valid/3_innocent_jointable.rb +12 -0
  320. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -0
  321. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -0
  322. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -0
  323. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -0
  324. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -0
  325. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -0
  326. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -0
  327. data/test/models/admin.rb +5 -0
  328. data/test/models/admin/account.rb +3 -0
  329. data/test/models/admin/randomly_named_c1.rb +3 -0
  330. data/test/models/admin/user.rb +40 -0
  331. data/test/models/aircraft.rb +4 -0
  332. data/test/models/arunit2_model.rb +3 -0
  333. data/test/models/author.rb +212 -0
  334. data/test/models/auto_id.rb +4 -0
  335. data/test/models/autoloadable/extra_firm.rb +2 -0
  336. data/test/models/binary.rb +2 -0
  337. data/test/models/bird.rb +12 -0
  338. data/test/models/book.rb +18 -0
  339. data/test/models/boolean.rb +2 -0
  340. data/test/models/bulb.rb +51 -0
  341. data/test/models/cake_designer.rb +3 -0
  342. data/test/models/car.rb +26 -0
  343. data/test/models/carrier.rb +2 -0
  344. data/test/models/categorization.rb +19 -0
  345. data/test/models/category.rb +35 -0
  346. data/test/models/chef.rb +3 -0
  347. data/test/models/citation.rb +3 -0
  348. data/test/models/club.rb +23 -0
  349. data/test/models/college.rb +10 -0
  350. data/test/models/column.rb +3 -0
  351. data/test/models/column_name.rb +3 -0
  352. data/test/models/comment.rb +64 -0
  353. data/test/models/company.rb +225 -0
  354. data/test/models/company_in_module.rb +98 -0
  355. data/test/models/computer.rb +3 -0
  356. data/test/models/contact.rb +41 -0
  357. data/test/models/contract.rb +20 -0
  358. data/test/models/country.rb +7 -0
  359. data/test/models/course.rb +6 -0
  360. data/test/models/customer.rb +77 -0
  361. data/test/models/customer_carrier.rb +14 -0
  362. data/test/models/dashboard.rb +3 -0
  363. data/test/models/default.rb +2 -0
  364. data/test/models/department.rb +4 -0
  365. data/test/models/developer.rb +252 -0
  366. data/test/models/dog.rb +5 -0
  367. data/test/models/dog_lover.rb +5 -0
  368. data/test/models/doubloon.rb +12 -0
  369. data/test/models/drink_designer.rb +3 -0
  370. data/test/models/edge.rb +5 -0
  371. data/test/models/electron.rb +5 -0
  372. data/test/models/engine.rb +4 -0
  373. data/test/models/entrant.rb +3 -0
  374. data/test/models/essay.rb +5 -0
  375. data/test/models/event.rb +3 -0
  376. data/test/models/eye.rb +37 -0
  377. data/test/models/face.rb +9 -0
  378. data/test/models/friendship.rb +6 -0
  379. data/test/models/guid.rb +2 -0
  380. data/test/models/hotel.rb +6 -0
  381. data/test/models/image.rb +3 -0
  382. data/test/models/interest.rb +5 -0
  383. data/test/models/invoice.rb +4 -0
  384. data/test/models/item.rb +7 -0
  385. data/test/models/job.rb +7 -0
  386. data/test/models/joke.rb +7 -0
  387. data/test/models/keyboard.rb +3 -0
  388. data/test/models/legacy_thing.rb +3 -0
  389. data/test/models/lesson.rb +11 -0
  390. data/test/models/line_item.rb +3 -0
  391. data/test/models/liquid.rb +4 -0
  392. data/test/models/man.rb +11 -0
  393. data/test/models/matey.rb +4 -0
  394. data/test/models/member.rb +41 -0
  395. data/test/models/member_detail.rb +7 -0
  396. data/test/models/member_type.rb +3 -0
  397. data/test/models/membership.rb +35 -0
  398. data/test/models/minimalistic.rb +2 -0
  399. data/test/models/minivan.rb +9 -0
  400. data/test/models/mixed_case_monkey.rb +3 -0
  401. data/test/models/molecule.rb +6 -0
  402. data/test/models/movie.rb +5 -0
  403. data/test/models/order.rb +4 -0
  404. data/test/models/organization.rb +14 -0
  405. data/test/models/owner.rb +34 -0
  406. data/test/models/parrot.rb +29 -0
  407. data/test/models/person.rb +143 -0
  408. data/test/models/personal_legacy_thing.rb +4 -0
  409. data/test/models/pet.rb +15 -0
  410. data/test/models/pirate.rb +92 -0
  411. data/test/models/possession.rb +3 -0
  412. data/test/models/post.rb +264 -0
  413. data/test/models/price_estimate.rb +4 -0
  414. data/test/models/professor.rb +5 -0
  415. data/test/models/project.rb +29 -0
  416. data/test/models/publisher.rb +2 -0
  417. data/test/models/publisher/article.rb +4 -0
  418. data/test/models/publisher/magazine.rb +3 -0
  419. data/test/models/randomly_named_c1.rb +3 -0
  420. data/test/models/rating.rb +4 -0
  421. data/test/models/reader.rb +23 -0
  422. data/test/models/record.rb +2 -0
  423. data/test/models/reference.rb +22 -0
  424. data/test/models/reply.rb +61 -0
  425. data/test/models/ship.rb +33 -0
  426. data/test/models/ship_part.rb +8 -0
  427. data/test/models/shop.rb +17 -0
  428. data/test/models/shop_account.rb +6 -0
  429. data/test/models/speedometer.rb +6 -0
  430. data/test/models/sponsor.rb +7 -0
  431. data/test/models/string_key_object.rb +3 -0
  432. data/test/models/student.rb +4 -0
  433. data/test/models/subject.rb +16 -0
  434. data/test/models/subscriber.rb +8 -0
  435. data/test/models/subscription.rb +4 -0
  436. data/test/models/tag.rb +7 -0
  437. data/test/models/tagging.rb +13 -0
  438. data/test/models/task.rb +5 -0
  439. data/test/models/topic.rb +124 -0
  440. data/test/models/toy.rb +6 -0
  441. data/test/models/traffic_light.rb +4 -0
  442. data/test/models/treasure.rb +14 -0
  443. data/test/models/treaty.rb +7 -0
  444. data/test/models/tyre.rb +11 -0
  445. data/test/models/uuid_child.rb +3 -0
  446. data/test/models/uuid_parent.rb +3 -0
  447. data/test/models/vegetables.rb +24 -0
  448. data/test/models/vehicle.rb +7 -0
  449. data/test/models/vertex.rb +9 -0
  450. data/test/models/warehouse_thing.rb +5 -5
  451. data/test/models/wheel.rb +3 -0
  452. data/test/models/without_table.rb +3 -0
  453. data/test/models/zine.rb +3 -0
  454. data/test/schema/mysql2_specific_schema.rb +58 -0
  455. data/test/schema/mysql_specific_schema.rb +70 -0
  456. data/test/schema/oracle_specific_schema.rb +43 -0
  457. data/test/schema/postgresql_specific_schema.rb +202 -0
  458. data/test/schema/schema.rb +938 -751
  459. data/test/schema/sqlite_specific_schema.rb +22 -0
  460. data/test/support/config.rb +43 -0
  461. data/test/support/connection.rb +22 -0
  462. data/test/support/connection_helper.rb +14 -0
  463. data/test/support/ddl_helper.rb +8 -0
  464. data/test/support/schema_dumping_helper.rb +20 -0
  465. metadata +444 -18
@@ -0,0 +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
@@ -0,0 +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
@@ -0,0 +1,29 @@
1
+ require "cases/helper"
2
+
3
+ module ActiveRecord
4
+ module AttributeMethods
5
+ class SerializationTest < ActiveSupport::TestCase
6
+ class FakeColumn < Struct.new(:name)
7
+ def type; :integer; end
8
+ def type_cast(s); "#{s}!"; end
9
+ end
10
+
11
+ class NullCoder
12
+ def load(v); v; end
13
+ end
14
+
15
+ def test_type_cast_serialized_value
16
+ value = Serialization::Attribute.new(NullCoder.new, "Hello world", :serialized)
17
+ type = Serialization::Type.new(FakeColumn.new)
18
+ assert_equal "Hello world!", type.type_cast(value)
19
+ end
20
+
21
+ def test_type_cast_unserialized_value
22
+ value = Serialization::Attribute.new(nil, "Hello world", :unserialized)
23
+ type = Serialization::Type.new(FakeColumn.new)
24
+ type.type_cast(value)
25
+ assert_equal "Hello world", type.type_cast(value)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,822 +1,952 @@
1
- require "cases/helper"
2
- require 'active_support/core_ext/object/inclusion'
3
- require 'models/minimalistic'
4
- require 'models/developer'
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
- fixtures :topics, :developers, :companies, :computers
17
-
18
- def setup
19
- @old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
20
- @target = Class.new(ActiveRecord::Base)
21
- @target.table_name = 'topics'
22
- end
23
-
24
- def teardown
25
- ActiveRecord::Base.send(:attribute_method_matchers).clear
26
- ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
27
- end
28
-
29
- def test_attribute_present
30
- t = Topic.new
31
- t.title = "hello there!"
32
- t.written_on = Time.now
33
- t.author_name = ""
34
- assert t.attribute_present?("title")
35
- assert t.attribute_present?("written_on")
36
- assert !t.attribute_present?("content")
37
- assert !t.attribute_present?("author_name")
38
-
39
- end
40
-
41
- def test_attribute_present_with_booleans
42
- b1 = Boolean.new
43
- b1.value = false
44
- assert b1.attribute_present?(:value)
45
-
46
- b2 = Boolean.new
47
- b2.value = true
48
- assert b2.attribute_present?(:value)
49
-
50
- b3 = Boolean.new
51
- assert !b3.attribute_present?(:value)
52
-
53
- b4 = Boolean.new
54
- b4.value = false
55
- b4.save!
56
- assert Boolean.find(b4.id).attribute_present?(:value)
57
- end
58
-
59
- def test_caching_nil_primary_key
60
- klass = Class.new(Minimalistic)
61
- klass.expects(:reset_primary_key).returns(nil).once
62
- 2.times { klass.primary_key }
63
- end
64
-
65
- def test_attribute_keys_on_new_instance
66
- t = Topic.new
67
- assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
68
- assert_raise(NoMethodError) { t.title2 }
69
- end
70
-
71
- def test_boolean_attributes
72
- assert ! Topic.find(1).approved?
73
- assert Topic.find(2).approved?
74
- end
75
-
76
- def test_set_attributes
77
- topic = Topic.find(1)
78
- topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
79
- topic.save
80
- assert_equal("Budget", topic.title)
81
- assert_equal("Jason", topic.author_name)
82
- assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
83
- end
84
-
85
- def test_set_attributes_without_hash
86
- topic = Topic.new
87
- assert_nothing_raised { topic.attributes = '' }
88
- end
89
-
90
- def test_integers_as_nil
91
- test = AutoId.create('value' => '')
92
- assert_nil AutoId.find(test.id).value
93
- end
94
-
95
- def test_set_attributes_with_block
96
- topic = Topic.new do |t|
97
- t.title = "Budget"
98
- t.author_name = "Jason"
99
- end
100
-
101
- assert_equal("Budget", topic.title)
102
- assert_equal("Jason", topic.author_name)
103
- end
104
-
105
- def test_respond_to?
106
- topic = Topic.find(1)
107
- assert_respond_to topic, "title"
108
- assert_respond_to topic, "_title"
109
- assert_respond_to topic, "title?"
110
- assert_respond_to topic, "title="
111
- assert_respond_to topic, :title
112
- assert_respond_to topic, :title?
113
- assert_respond_to topic, :title=
114
- assert_respond_to topic, "author_name"
115
- assert_respond_to topic, "attribute_names"
116
- assert !topic.respond_to?("nothingness")
117
- assert !topic.respond_to?(:nothingness)
118
- end
119
-
120
- def test_deprecated_underscore_method
121
- topic = Topic.find(1)
122
- assert_equal topic.title, assert_deprecated { topic._title }
123
- end
124
-
125
- def test_respond_to_with_custom_primary_key
126
- keyboard = Keyboard.create
127
- assert_not_nil keyboard.key_number
128
- assert_equal keyboard.key_number, keyboard.id
129
- assert keyboard.respond_to?('key_number')
130
- assert keyboard.respond_to?('_key_number')
131
- assert keyboard.respond_to?('id')
132
- assert keyboard.respond_to?('_id')
133
- end
134
-
135
- # Syck calls respond_to? before actually calling initialize
136
- def test_respond_to_with_allocated_object
137
- topic = Topic.allocate
138
- assert !topic.respond_to?("nothingness")
139
- assert !topic.respond_to?(:nothingness)
140
- assert_respond_to topic, "title"
141
- assert_respond_to topic, :title
142
- end
143
-
144
- # IRB inspects the return value of "MyModel.allocate"
145
- # by inspecting it.
146
- def test_allocated_object_can_be_inspected
147
- topic = Topic.allocate
148
- topic.instance_eval { @attributes = nil }
149
- assert_nothing_raised { topic.inspect }
150
- assert topic.inspect, "#<Topic not initialized>"
151
- end
152
-
153
- def test_array_content
154
- topic = Topic.new
155
- topic.content = %w( one two three )
156
- topic.save
157
-
158
- assert_equal(%w( one two three ), Topic.find(topic.id).content)
159
- end
160
-
161
- def test_read_attributes_before_type_cast
162
- category = Category.new({:name=>"Test categoty", :type => nil})
163
- category_attrs = {"name"=>"Test categoty", "id" => nil, "type" => nil, "categorizations_count" => nil}
164
- assert_equal category_attrs , category.attributes_before_type_cast
165
- end
166
-
167
- if current_adapter?(:MysqlAdapter)
168
- def test_read_attributes_before_type_cast_on_boolean
169
- bool = Boolean.create({ "value" => false })
170
- if RUBY_PLATFORM =~ /java/
171
- # JRuby will return the value before typecast as string
172
- assert_equal "0", bool.reload.attributes_before_type_cast["value"]
173
- else
174
- assert_equal 0, bool.reload.attributes_before_type_cast["value"]
175
- end
176
- end
177
- end
178
-
179
- def test_read_attributes_before_type_cast_on_datetime
180
- in_time_zone "Pacific Time (US & Canada)" do
181
- record = @target.new
182
-
183
- record.written_on = "345643456"
184
- assert_equal "345643456", record.written_on_before_type_cast
185
- assert_equal nil, record.written_on
186
-
187
- record.written_on = "2009-10-11 12:13:14"
188
- assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast
189
- assert_equal Time.zone.parse("2009-10-11 12:13:14"), record.written_on
190
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
191
- end
192
- end
193
-
194
- def test_read_attributes_after_type_cast_on_datetime
195
- tz = "Pacific Time (US & Canada)"
196
-
197
- in_time_zone tz do
198
- record = @target.new
199
-
200
- date_string = "2011-03-24"
201
- time = Time.zone.parse date_string
202
-
203
- record.written_on = date_string
204
- assert_equal date_string, record.written_on_before_type_cast
205
- assert_equal time, record.written_on
206
- assert_equal ActiveSupport::TimeZone[tz], record.written_on.time_zone
207
-
208
- record.save
209
- record.reload
210
-
211
- assert_equal time, record.written_on
212
- end
213
- end
214
-
215
- def test_hash_content
216
- topic = Topic.new
217
- topic.content = { "one" => 1, "two" => 2 }
218
- topic.save
219
-
220
- assert_equal 2, Topic.find(topic.id).content["two"]
221
-
222
- topic.content_will_change!
223
- topic.content["three"] = 3
224
- topic.save
225
-
226
- assert_equal 3, Topic.find(topic.id).content["three"]
227
- end
228
-
229
- def test_update_array_content
230
- topic = Topic.new
231
- topic.content = %w( one two three )
232
-
233
- topic.content.push "four"
234
- assert_equal(%w( one two three four ), topic.content)
235
-
236
- topic.save
237
-
238
- topic = Topic.find(topic.id)
239
- topic.content << "five"
240
- assert_equal(%w( one two three four five ), topic.content)
241
- end
242
-
243
- def test_case_sensitive_attributes_hash
244
- # DB2 is not case-sensitive
245
- return true if current_adapter?(:DB2Adapter,:IBM_DBAdapter)
246
-
247
- assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
248
- end
249
-
250
- def test_hashes_not_mangled
251
- new_topic = { :title => "New Topic" }
252
- new_topic_values = { :title => "AnotherTopic" }
253
-
254
- topic = Topic.new(new_topic)
255
- assert_equal new_topic[:title], topic.title
256
-
257
- topic.attributes= new_topic_values
258
- assert_equal new_topic_values[:title], topic.title
259
- end
260
-
261
- def test_create_through_factory
262
- topic = Topic.create("title" => "New Topic")
263
- topicReloaded = Topic.find(topic.id)
264
- assert_equal(topic, topicReloaded)
265
- end
266
-
267
- def test_write_attribute
268
- topic = Topic.new
269
- topic.send(:write_attribute, :title, "Still another topic")
270
- assert_equal "Still another topic", topic.title
271
-
272
- topic[:title] = "Still another topic: part 2"
273
- assert_equal "Still another topic: part 2", topic.title
274
-
275
- topic.send(:write_attribute, "title", "Still another topic: part 3")
276
- assert_equal "Still another topic: part 3", topic.title
277
-
278
- topic["title"] = "Still another topic: part 4"
279
- assert_equal "Still another topic: part 4", topic.title
280
- end
281
-
282
- def test_read_attribute
283
- topic = Topic.new
284
- topic.title = "Don't change the topic"
285
- assert_equal "Don't change the topic", topic.send(:read_attribute, "title")
286
- assert_equal "Don't change the topic", topic["title"]
287
-
288
- assert_equal "Don't change the topic", topic.send(:read_attribute, :title)
289
- assert_equal "Don't change the topic", topic[:title]
290
- end
291
-
292
- def test_read_attribute_when_false
293
- topic = topics(:first)
294
- topic.approved = false
295
- assert !topic.approved?, "approved should be false"
296
- topic.approved = "false"
297
- assert !topic.approved?, "approved should be false"
298
- end
299
-
300
- def test_read_attribute_when_true
301
- topic = topics(:first)
302
- topic.approved = true
303
- assert topic.approved?, "approved should be true"
304
- topic.approved = "true"
305
- assert topic.approved?, "approved should be true"
306
- end
307
-
308
- def test_read_write_boolean_attribute
309
- topic = Topic.new
310
- # puts ""
311
- # puts "New Topic"
312
- # puts topic.inspect
313
- topic.approved = "false"
314
- # puts "Expecting false"
315
- # puts topic.inspect
316
- assert !topic.approved?, "approved should be false"
317
- topic.approved = "false"
318
- # puts "Expecting false"
319
- # puts topic.inspect
320
- assert !topic.approved?, "approved should be false"
321
- topic.approved = "true"
322
- # puts "Expecting true"
323
- # puts topic.inspect
324
- assert topic.approved?, "approved should be true"
325
- topic.approved = "true"
326
- # puts "Expecting true"
327
- # puts topic.inspect
328
- assert topic.approved?, "approved should be true"
329
- # puts ""
330
- end
331
-
332
- def test_overridden_write_attribute
333
- topic = Topic.new
334
- def topic.write_attribute(attr_name, value)
335
- super(attr_name, value.downcase)
336
- end
337
-
338
- topic.send(:write_attribute, :title, "Yet another topic")
339
- assert_equal "yet another topic", topic.title
340
-
341
- topic[:title] = "Yet another topic: part 2"
342
- assert_equal "yet another topic: part 2", topic.title
343
-
344
- topic.send(:write_attribute, "title", "Yet another topic: part 3")
345
- assert_equal "yet another topic: part 3", topic.title
346
-
347
- topic["title"] = "Yet another topic: part 4"
348
- assert_equal "yet another topic: part 4", topic.title
349
- end
350
-
351
- def test_overridden_read_attribute
352
- topic = Topic.new
353
- topic.title = "Stop changing the topic"
354
- def topic.read_attribute(attr_name)
355
- super(attr_name).upcase
356
- end
357
-
358
- assert_equal "STOP CHANGING THE TOPIC", topic.send(:read_attribute, "title")
359
- assert_equal "STOP CHANGING THE TOPIC", topic["title"]
360
-
361
- assert_equal "STOP CHANGING THE TOPIC", topic.send(:read_attribute, :title)
362
- assert_equal "STOP CHANGING THE TOPIC", topic[:title]
363
- end
364
-
365
- def test_read_overridden_attribute
366
- topic = Topic.new(:title => 'a')
367
- def topic.title() 'b' end
368
- assert_equal 'a', topic[:title]
369
- end
370
-
371
- def test_query_attribute_string
372
- [nil, "", " "].each do |value|
373
- assert_equal false, Topic.new(:author_name => value).author_name?
374
- end
375
-
376
- assert_equal true, Topic.new(:author_name => "Name").author_name?
377
- end
378
-
379
- def test_query_attribute_number
380
- [nil, 0, "0"].each do |value|
381
- assert_equal false, Developer.new(:salary => value).salary?
382
- end
383
-
384
- assert_equal true, Developer.new(:salary => 1).salary?
385
- assert_equal true, Developer.new(:salary => "1").salary?
386
- end
387
-
388
- def test_query_attribute_boolean
389
- [nil, "", false, "false", "f", 0].each do |value|
390
- assert_equal false, Topic.new(:approved => value).approved?
391
- end
392
-
393
- [true, "true", "1", 1].each do |value|
394
- assert_equal true, Topic.new(:approved => value).approved?
395
- end
396
- end
397
-
398
- def test_query_attribute_with_custom_fields
399
- object = Company.find_by_sql(<<-SQL).first
400
- SELECT c1.*, c2.ruby_type as string_value, c2.rating as int_value
401
- FROM companies c1, companies c2
402
- WHERE c1.firm_id = c2.id
403
- AND c1.id = 2
404
- SQL
405
-
406
- assert_equal "Firm", object.string_value
407
- assert object.string_value?
408
-
409
- object.string_value = " "
410
- assert !object.string_value?
411
-
412
- assert_equal 1, object.int_value.to_i
413
- assert object.int_value?
414
-
415
- object.int_value = "0"
416
- assert !object.int_value?
417
- end
418
-
419
- def test_non_attribute_access_and_assignment
420
- topic = Topic.new
421
- assert !topic.respond_to?("mumbo")
422
- assert_raise(NoMethodError) { topic.mumbo }
423
- assert_raise(NoMethodError) { topic.mumbo = 5 }
424
- end
425
-
426
- def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing
427
- topic = @target.new(:title => 'Budget')
428
- assert topic.respond_to?('title')
429
- assert_equal 'Budget', topic.title
430
- assert !topic.respond_to?('title_hello_world')
431
- assert_raise(NoMethodError) { topic.title_hello_world }
432
- end
433
-
434
- def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing
435
- topic = @target.new(:title => 'Budget')
436
- %w(default_ title_).each do |prefix|
437
- @target.class_eval "def #{prefix}attribute(*args) args end"
438
- @target.attribute_method_prefix prefix
439
-
440
- meth = "#{prefix}title"
441
- assert topic.respond_to?(meth)
442
- assert_equal ['title'], topic.send(meth)
443
- assert_equal ['title', 'a'], topic.send(meth, 'a')
444
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
445
- end
446
- end
447
-
448
- def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing
449
- topic = @target.new(:title => 'Budget')
450
- %w(_default _title_default _it! _candidate= able?).each do |suffix|
451
- @target.class_eval "def attribute#{suffix}(*args) args end"
452
- @target.attribute_method_suffix suffix
453
-
454
- meth = "title#{suffix}"
455
- assert topic.respond_to?(meth)
456
- assert_equal ['title'], topic.send(meth)
457
- assert_equal ['title', 'a'], topic.send(meth, 'a')
458
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
459
- end
460
- end
461
-
462
- def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing
463
- topic = @target.new(:title => 'Budget')
464
- [['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix|
465
- @target.class_eval "def #{prefix}attribute#{suffix}(*args) args end"
466
- @target.attribute_method_affix({ :prefix => prefix, :suffix => suffix })
467
-
468
- meth = "#{prefix}title#{suffix}"
469
- assert topic.respond_to?(meth)
470
- assert_equal ['title'], topic.send(meth)
471
- assert_equal ['title', 'a'], topic.send(meth, 'a')
472
- assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
473
- end
474
- end
475
-
476
- def test_should_unserialize_attributes_for_frozen_records
477
- myobj = {:value1 => :value2}
478
- topic = Topic.create("content" => myobj)
479
- topic.freeze
480
- assert_equal myobj, topic.content
481
- end
482
-
483
- def test_typecast_attribute_from_select_to_false
484
- topic = Topic.create(:title => 'Budget')
485
- # Oracle and DB2 does not support boolean expressions in SELECT
486
- if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
487
- topic = Topic.find(:first, :select => "topics.*, 0 as is_test")
488
- else
489
- topic = Topic.find(:first, :select => "topics.*, 1=2 as is_test")
490
- end
491
- assert !topic.is_test?
492
- end
493
-
494
- def test_typecast_attribute_from_select_to_true
495
- topic = Topic.create(:title => 'Budget')
496
- # Oracle and DB2 does not support boolean expressions in SELECT
497
- if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
498
- topic = Topic.find(:first, :select => "topics.*, 1 as is_test")
499
- else
500
- topic = Topic.find(:first, :select => "topics.*, 2=2 as is_test")
501
- end
502
- assert topic.is_test?
503
- end
504
-
505
- def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
506
- %w(save create_or_update).each do |method|
507
- klass = Class.new ActiveRecord::Base
508
- klass.class_eval "def #{method}() 'defined #{method}' end"
509
- assert_raise ActiveRecord::DangerousAttributeError do
510
- klass.instance_method_already_implemented?(method)
511
- end
512
- end
513
- end
514
-
515
- def test_only_time_related_columns_are_meant_to_be_cached_by_default
516
- expected = %w(datetime timestamp time date).sort
517
- assert_equal expected, ActiveRecord::Base.attribute_types_cached_by_default.map(&:to_s).sort
518
- end
519
-
520
- def test_declaring_attributes_as_cached_adds_them_to_the_attributes_cached_by_default
521
- default_attributes = Topic.cached_attributes
522
- Topic.cache_attributes :replies_count
523
- expected = default_attributes + ["replies_count"]
524
- assert_equal expected.sort, Topic.cached_attributes.sort
525
- Topic.instance_variable_set "@cached_attributes", nil
526
- end
527
-
528
- def test_cacheable_columns_are_actually_cached
529
- assert_equal cached_columns.sort, Topic.cached_attributes.sort
530
- end
531
-
532
- def test_accessing_cached_attributes_caches_the_converted_values_and_nothing_else
533
- t = topics(:first)
534
- cache = t.instance_variable_get "@attributes_cache"
535
-
536
- assert_not_nil cache
537
- assert cache.empty?
538
-
539
- all_columns = Topic.columns.map(&:name)
540
- uncached_columns = all_columns - cached_columns
541
-
542
- all_columns.each do |attr_name|
543
- attribute_gets_cached = Topic.cache_attribute?(attr_name)
544
- val = t.send attr_name unless attr_name == "type"
545
- if attribute_gets_cached
546
- assert cached_columns.include?(attr_name)
547
- assert_equal val, cache[attr_name]
548
- else
549
- assert uncached_columns.include?(attr_name)
550
- assert !cache.include?(attr_name)
551
- end
552
- end
553
- end
554
-
555
- def test_write_nil_to_time_attributes
556
- in_time_zone "Pacific Time (US & Canada)" do
557
- record = @target.new
558
- record.written_on = nil
559
- assert_nil record.written_on
560
- end
561
- end
562
-
563
- def test_time_attributes_are_retrieved_in_current_time_zone
564
- in_time_zone "Pacific Time (US & Canada)" do
565
- utc_time = Time.utc(2008, 1, 1)
566
- record = @target.new
567
- record[:written_on] = utc_time
568
- assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
569
- assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
570
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
571
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
572
- end
573
- end
574
-
575
- def test_setting_time_zone_aware_attribute_to_utc
576
- in_time_zone "Pacific Time (US & Canada)" do
577
- utc_time = Time.utc(2008, 1, 1)
578
- record = @target.new
579
- record.written_on = utc_time
580
- assert_equal utc_time, record.written_on
581
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
582
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
583
- end
584
- end
585
-
586
- def test_setting_time_zone_aware_attribute_in_other_time_zone
587
- utc_time = Time.utc(2008, 1, 1)
588
- cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
589
- in_time_zone "Pacific Time (US & Canada)" do
590
- record = @target.new
591
- record.written_on = cst_time
592
- assert_equal utc_time, record.written_on
593
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
594
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
595
- end
596
- end
597
-
598
- def test_setting_time_zone_aware_read_attribute
599
- utc_time = Time.utc(2008, 1, 1)
600
- cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
601
- in_time_zone "Pacific Time (US & Canada)" do
602
- record = @target.create(:written_on => cst_time).reload
603
- assert_equal utc_time, record[:written_on]
604
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record[:written_on].time_zone
605
- assert_equal Time.utc(2007, 12, 31, 16), record[:written_on].time
606
- end
607
- end
608
-
609
- def test_setting_time_zone_aware_attribute_with_string
610
- utc_time = Time.utc(2008, 1, 1)
611
- (-11..13).each do |timezone_offset|
612
- time_string = utc_time.in_time_zone(timezone_offset).to_s
613
- in_time_zone "Pacific Time (US & Canada)" do
614
- record = @target.new
615
- record.written_on = time_string
616
- assert_equal Time.zone.parse(time_string), record.written_on
617
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
618
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
619
- end
620
- end
621
- end
622
-
623
- def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
624
- in_time_zone "Pacific Time (US & Canada)" do
625
- record = @target.new
626
- record.written_on = ' '
627
- assert_nil record.written_on
628
- assert_nil record[:written_on]
629
- end
630
- end
631
-
632
- def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
633
- time_string = 'Tue Jan 01 00:00:00 2008'
634
- (-11..13).each do |timezone_offset|
635
- in_time_zone timezone_offset do
636
- record = @target.new
637
- record.written_on = time_string
638
- assert_equal Time.zone.parse(time_string), record.written_on
639
- assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
640
- assert_equal Time.utc(2008, 1, 1), record.written_on.time
641
- end
642
- end
643
- end
644
-
645
- def test_setting_time_zone_aware_attribute_in_current_time_zone
646
- utc_time = Time.utc(2008, 1, 1)
647
- in_time_zone "Pacific Time (US & Canada)" do
648
- record = @target.new
649
- record.written_on = utc_time.in_time_zone
650
- assert_equal utc_time, record.written_on
651
- assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
652
- assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
653
- end
654
- end
655
-
656
- def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
657
- Topic.skip_time_zone_conversion_for_attributes = [:field_a]
658
- Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
659
-
660
- assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
661
- assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
662
- end
663
-
664
- def test_read_attributes_respect_access_control
665
- privatize("title")
666
-
667
- topic = @target.new(:title => "The pros and cons of programming naked.")
668
- assert !topic.respond_to?(:title)
669
- exception = assert_raise(NoMethodError) { topic.title }
670
- assert exception.message.include?("private method")
671
- assert_equal "I'm private", topic.send(:title)
672
- end
673
-
674
- def test_write_attributes_respect_access_control
675
- privatize("title=(value)")
676
-
677
- topic = @target.new
678
- assert !topic.respond_to?(:title=)
679
- exception = assert_raise(NoMethodError) { topic.title = "Pants"}
680
- assert exception.message.include?("private method")
681
- topic.send(:title=, "Very large pants")
682
- end
683
-
684
- def test_question_attributes_respect_access_control
685
- privatize("title?")
686
-
687
- topic = @target.new(:title => "Isaac Newton's pants")
688
- assert !topic.respond_to?(:title?)
689
- exception = assert_raise(NoMethodError) { topic.title? }
690
- assert exception.message.include?("private method")
691
- assert topic.send(:title?)
692
- end
693
-
694
- def test_bulk_update_respects_access_control
695
- privatize("title=(value)")
696
-
697
- assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(:title => "Rants about pants") }
698
- assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
699
- end
700
-
701
- def test_read_attribute_overwrites_private_method_not_considered_implemented
702
- # simulate a model with a db column that shares its name an inherited
703
- # private method (e.g. Object#system)
704
- #
705
- Object.class_eval do
706
- private
707
- def title; "private!"; end
708
- end
709
- assert !@target.instance_method_already_implemented?(:title)
710
- topic = @target.new
711
- assert_nil topic.title
712
-
713
- Object.send(:undef_method, :title) # remove test method from object
714
- end
715
-
716
- def test_list_of_serialized_attributes
717
- assert_equal %w(content), Topic.serialized_attributes.keys
718
- assert_equal %w(preferences), Contact.serialized_attributes.keys
719
- end
720
-
721
- def test_instance_method_should_be_defined_on_the_base_class
722
- subklass = Class.new(Topic)
723
-
724
- Topic.define_attribute_methods
725
-
726
- instance = subklass.new
727
- instance.id = 5
728
- assert_equal 5, instance.id
729
- assert subklass.method_defined?(:id), "subklass is missing id method"
730
-
731
- Topic.undefine_attribute_methods
732
-
733
- assert_equal 5, instance.id
734
- assert subklass.method_defined?(:id), "subklass is missing id method"
735
- end
736
-
737
- def test_dispatching_column_attributes_through_method_missing_deprecated
738
- Topic.define_attribute_methods
739
-
740
- topic = Topic.new(:id => 5)
741
- topic.id = 5
742
-
743
- topic.method(:id).owner.send(:undef_method, :id)
744
-
745
- assert_deprecated do
746
- assert_equal 5, topic.id
747
- end
748
- ensure
749
- Topic.undefine_attribute_methods
750
- end
751
-
752
- def test_read_attribute_with_nil_should_not_asplode
753
- assert_equal nil, Topic.new.read_attribute(nil)
754
- end
755
-
756
- # If B < A, and A defines an accessor for 'foo', we don't want to override
757
- # that by defining a 'foo' method in the generated methods module for B.
758
- # (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].)
759
- def test_inherited_custom_accessors
760
- klass = Class.new(ActiveRecord::Base) do
761
- self.table_name = "topics"
762
- self.abstract_class = true
763
- def title; "omg"; end
764
- def title=(val); self.author_name = val; end
765
- end
766
- subklass = Class.new(klass)
767
- [klass, subklass].each(&:define_attribute_methods)
768
-
769
- topic = subklass.find(1)
770
- assert_equal "omg", topic.title
771
-
772
- topic.title = "lol"
773
- assert_equal "lol", topic.author_name
774
- end
775
-
776
- def test_inherited_hook_removed
777
- parent = Class.new(ActiveRecord::Base)
778
- parent.table_name = "posts"
779
- def parent.inherited(k)
780
- end
781
-
782
- klass = Class.new(parent)
783
- assert_deprecated { klass.define_attribute_methods }
784
- end
785
-
786
- def test_setting_new_attributes_deprecated
787
- t = Topic.new
788
- assert_deprecated { t[:foo] = "bar" }
789
- assert_equal "bar", t.foo
790
- assert_equal "bar", t[:foo]
791
- end
792
-
793
- private
794
- def cached_columns
795
- @cached_columns ||= time_related_columns_on_topic.map(&:name)
796
- end
797
-
798
- def time_related_columns_on_topic
799
- Topic.columns.select { |c| c.type.in?([:time, :date, :datetime, :timestamp]) }
800
- end
801
-
802
- def in_time_zone(zone)
803
- old_zone = Time.zone
804
- old_tz = ActiveRecord::Base.time_zone_aware_attributes
805
-
806
- Time.zone = zone ? ActiveSupport::TimeZone[zone] : nil
807
- ActiveRecord::Base.time_zone_aware_attributes = !zone.nil?
808
- yield
809
- ensure
810
- Time.zone = old_zone
811
- ActiveRecord::Base.time_zone_aware_attributes = old_tz
812
- end
813
-
814
- def privatize(method_signature)
815
- @target.class_eval <<-private_method
816
- private
817
- def #{method_signature}
818
- "I'm private"
819
- end
820
- private_method
821
- end
822
- end
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