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
@@ -1,2133 +1,1638 @@
1
- require "cases/helper"
2
- require 'models/post'
3
- require 'models/author'
4
- require 'models/topic'
5
- require 'models/reply'
6
- require 'models/category'
7
- require 'models/company'
8
- require 'models/customer'
9
- require 'models/developer'
10
- require 'models/project'
11
- require 'models/default'
12
- require 'models/auto_id'
13
- require 'models/boolean'
14
- require 'models/column_name'
15
- require 'models/subscriber'
16
- require 'models/keyboard'
17
- require 'models/comment'
18
- require 'models/minimalistic'
19
- require 'models/warehouse_thing'
20
- require 'models/parrot'
21
- require 'models/person'
22
- require 'models/edge'
23
- require 'models/joke'
24
- require 'models/bulb'
25
- require 'models/bird'
26
- require 'rexml/document'
27
- require 'active_support/core_ext/exception'
28
- require 'bcrypt'
29
-
30
- class FirstAbstractClass < ActiveRecord::Base
31
- self.abstract_class = true
32
- end
33
- class SecondAbstractClass < FirstAbstractClass
34
- self.abstract_class = true
35
- end
36
- class Photo < SecondAbstractClass; end
37
- class Category < ActiveRecord::Base; end
38
- class Categorization < ActiveRecord::Base; end
39
- class Smarts < ActiveRecord::Base; end
40
- class CreditCard < ActiveRecord::Base
41
- class PinNumber < ActiveRecord::Base
42
- class CvvCode < ActiveRecord::Base; end
43
- class SubCvvCode < CvvCode; end
44
- end
45
- class SubPinNumber < PinNumber; end
46
- class Brand < Category; end
47
- end
48
- class MasterCreditCard < ActiveRecord::Base; end
49
- class Post < ActiveRecord::Base; end
50
- class Computer < ActiveRecord::Base; end
51
- class NonExistentTable < ActiveRecord::Base; end
52
- class TestOracleDefault < ActiveRecord::Base; end
53
-
54
- class ReadonlyTitlePost < Post
55
- attr_readonly :title
56
- end
57
-
58
- class ProtectedTitlePost < Post
59
- attr_protected :title
60
- end
61
-
62
- class Weird < ActiveRecord::Base; end
63
-
64
- class Boolean < ActiveRecord::Base; end
65
-
66
- class LintTest < ActiveRecord::TestCase
67
- include ActiveModel::Lint::Tests
68
-
69
- class LintModel < ActiveRecord::Base; end
70
-
71
- def setup
72
- @model = LintModel.new
73
- end
74
- end
75
-
76
- class BasicsTest < ActiveRecord::TestCase
77
- fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse_things', :authors, :categorizations, :categories, :posts
78
-
79
- def test_generated_methods_modules
80
- modules = Computer.ancestors
81
- assert modules.include?(Computer::GeneratedFeatureMethods)
82
- assert_equal(Computer::GeneratedFeatureMethods, Computer.generated_feature_methods)
83
- assert(modules.index(Computer.generated_attribute_methods) > modules.index(Computer.generated_feature_methods),
84
- "generated_attribute_methods must be higher in inheritance hierarchy than generated_feature_methods")
85
- assert_not_equal Computer.generated_feature_methods, Post.generated_feature_methods
86
- end
87
-
88
- def test_column_names_are_escaped
89
- conn = ActiveRecord::Base.connection
90
- classname = conn.class.name[/[^:]*$/]
91
- badchar = {
92
- 'SQLite3Adapter' => '"',
93
- 'MysqlAdapter' => '`',
94
- 'Mysql2Adapter' => '`',
95
- 'PostgreSQLAdapter' => '"',
96
- 'OracleAdapter' => '"',
97
- 'IBM_DBAdapter' => '"'
98
- }.fetch(classname) {
99
- raise "need a bad char for #{classname}"
100
- }
101
-
102
- quoted = conn.quote_column_name "foo#{badchar}bar"
103
- if current_adapter?(:OracleAdapter)
104
- # Oracle does not allow double quotes in table and column names at all
105
- # therefore quoting removes them
106
- assert_equal("#{badchar}foobar#{badchar}", quoted)
107
- elsif current_adapter?(:IBM_DBAdapter)
108
- assert_equal("foo#{badchar}bar", quoted)
109
- else
110
- assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted)
111
- end
112
- end
113
-
114
- def test_columns_should_obey_set_primary_key
115
- pk = Subscriber.columns.find { |x| x.name == 'nick' }
116
- assert pk.primary, 'nick should be primary key'
117
- end
118
-
119
- def test_primary_key_with_no_id
120
- assert_nil Edge.primary_key
121
- end
122
-
123
- unless current_adapter?(:PostgreSQLAdapter,:OracleAdapter,:SQLServerAdapter, :IBM_DBAdapter)
124
- def test_limit_with_comma
125
- assert_nothing_raised do
126
- Topic.limit("1,2").all
127
- end
128
- end
129
- end
130
-
131
- def test_limit_without_comma
132
- assert_nothing_raised do
133
- assert_equal 1, Topic.limit("1").all.length
134
- end
135
-
136
- assert_nothing_raised do
137
- assert_equal 1, Topic.limit(1).all.length
138
- end
139
- end
140
-
141
- def test_invalid_limit
142
- assert_raises(ArgumentError) do
143
- Topic.limit("asdfadf").all
144
- end
145
- end
146
-
147
- def test_limit_should_sanitize_sql_injection_for_limit_without_comas
148
- assert_raises(ArgumentError) do
149
- Topic.limit("1 select * from schema").all
150
- end
151
- end
152
-
153
- def test_limit_should_sanitize_sql_injection_for_limit_with_comas
154
- assert_raises(ArgumentError) do
155
- Topic.limit("1, 7 procedure help()").all
156
- end
157
- end
158
-
159
- unless current_adapter?(:MysqlAdapter) || current_adapter?(:Mysql2Adapter) || current_adapter?(:IBM_DBAdapter)
160
- def test_limit_should_allow_sql_literal
161
- assert_equal 1, Topic.limit(Arel.sql('2-1')).all.length
162
- end
163
- end
164
-
165
- def test_select_symbol
166
- topic_ids = Topic.select(:id).map(&:id).sort
167
- assert_equal Topic.all.map(&:id).sort, topic_ids
168
- end
169
-
170
- def test_table_exists
171
- assert !NonExistentTable.table_exists?
172
- assert Topic.table_exists?
173
- end
174
-
175
- def test_preserving_date_objects
176
- if current_adapter?(:SybaseAdapter)
177
- # Sybase ctlib does not (yet?) support the date type; use datetime instead.
178
- assert_kind_of(
179
- Time, Topic.find(1).last_read,
180
- "The last_read attribute should be of the Time class"
181
- )
182
- else
183
- # Oracle enhanced adapter allows to define Date attributes in model class (see topic.rb)
184
- assert_kind_of(
185
- Date, Topic.find(1).last_read,
186
- "The last_read attribute should be of the Date class"
187
- )
188
- end
189
- end
190
-
191
- def test_preserving_time_objects
192
- assert_kind_of(
193
- Time, Topic.find(1).bonus_time,
194
- "The bonus_time attribute should be of the Time class"
195
- )
196
-
197
- assert_kind_of(
198
- Time, Topic.find(1).written_on,
199
- "The written_on attribute should be of the Time class"
200
- )
201
-
202
- # For adapters which support microsecond resolution.
203
- if current_adapter?(:PostgreSQLAdapter) || current_adapter?(:SQLiteAdapter)
204
- assert_equal 11, Topic.find(1).written_on.sec
205
- assert_equal 223300, Topic.find(1).written_on.usec
206
- assert_equal 9900, Topic.find(2).written_on.usec
207
- end
208
- end
209
-
210
- def test_preserving_time_objects_with_local_time_conversion_to_default_timezone_utc
211
- with_env_tz 'America/New_York' do
212
- with_active_record_default_timezone :utc do
213
- time = Time.local(2000)
214
- topic = Topic.create('written_on' => time)
215
- saved_time = Topic.find(topic.id).reload.written_on
216
- assert_equal time, saved_time
217
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "EST"], time.to_a
218
- assert_equal [0, 0, 5, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
219
- end
220
- end
221
- end
222
-
223
- def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_utc
224
- with_env_tz 'America/New_York' do
225
- with_active_record_default_timezone :utc do
226
- Time.use_zone 'Central Time (US & Canada)' do
227
- time = Time.zone.local(2000)
228
- topic = Topic.create('written_on' => time)
229
- saved_time = Topic.find(topic.id).reload.written_on
230
- assert_equal time, saved_time
231
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
232
- assert_equal [0, 0, 6, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
233
- end
234
- end
235
- end
236
- end
237
-
238
- def test_preserving_time_objects_with_utc_time_conversion_to_default_timezone_local
239
- with_env_tz 'America/New_York' do
240
- time = Time.utc(2000)
241
- topic = Topic.create('written_on' => time)
242
- saved_time = Topic.find(topic.id).reload.written_on
243
- assert_equal time, saved_time
244
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], time.to_a
245
- assert_equal [0, 0, 19, 31, 12, 1999, 5, 365, false, "EST"], saved_time.to_a
246
- end
247
- end
248
-
249
- def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_local
250
- with_env_tz 'America/New_York' do
251
- with_active_record_default_timezone :local do
252
- Time.use_zone 'Central Time (US & Canada)' do
253
- time = Time.zone.local(2000)
254
- topic = Topic.create('written_on' => time)
255
- saved_time = Topic.find(topic.id).reload.written_on
256
- assert_equal time, saved_time
257
- assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
258
- assert_equal [0, 0, 1, 1, 1, 2000, 6, 1, false, "EST"], saved_time.to_a
259
- end
260
- end
261
- end
262
- end
263
-
264
- def test_custom_mutator
265
- topic = Topic.find(1)
266
- # This mutator is protected in the class definition
267
- topic.send(:approved=, true)
268
- assert topic.instance_variable_get("@custom_approved")
269
- end
270
-
271
- def test_initialize_with_attributes
272
- topic = Topic.new({
273
- "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23"
274
- })
275
-
276
- assert_equal("initialized from attributes", topic.title)
277
- end
278
-
279
- def test_initialize_with_invalid_attribute
280
- begin
281
- Topic.new({ "title" => "test",
282
- "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
283
- rescue ActiveRecord::MultiparameterAssignmentErrors => ex
284
- assert_equal(1, ex.errors.size)
285
- assert_equal("last_read", ex.errors[0].attribute)
286
- end
287
- end
288
-
289
- def test_create_after_initialize_without_block
290
- cb = CustomBulb.create(:name => 'Dude')
291
- assert_equal('Dude', cb.name)
292
- assert_equal(true, cb.frickinawesome)
293
- end
294
-
295
- def test_create_after_initialize_with_block
296
- cb = CustomBulb.create {|c| c.name = 'Dude' }
297
- assert_equal('Dude', cb.name)
298
- assert_equal(true, cb.frickinawesome)
299
- end
300
-
301
- def test_first_or_create
302
- parrot = Bird.first_or_create(:color => 'green', :name => 'parrot')
303
- assert parrot.persisted?
304
- the_same_parrot = Bird.first_or_create(:color => 'yellow', :name => 'macaw')
305
- assert_equal parrot, the_same_parrot
306
- end
307
-
308
- def test_first_or_create_bang
309
- assert_raises(ActiveRecord::RecordInvalid) { Bird.first_or_create! }
310
- parrot = Bird.first_or_create!(:color => 'green', :name => 'parrot')
311
- assert parrot.persisted?
312
- the_same_parrot = Bird.first_or_create!(:color => 'yellow', :name => 'macaw')
313
- assert_equal parrot, the_same_parrot
314
- end
315
-
316
- def test_first_or_initialize
317
- parrot = Bird.first_or_initialize(:color => 'green', :name => 'parrot')
318
- assert_kind_of Bird, parrot
319
- assert !parrot.persisted?
320
- assert parrot.new_record?
321
- assert parrot.valid?
322
- end
323
-
324
- def test_load
325
- topics = Topic.find(:all, :order => 'id')
326
- assert_equal(4, topics.size)
327
- assert_equal(topics(:first).title, topics.first.title)
328
- end
329
-
330
- def test_load_with_condition
331
- topics = Topic.find(:all, :conditions => "author_name = 'Mary'")
332
-
333
- assert_equal(1, topics.size)
334
- assert_equal(topics(:second).title, topics.first.title)
335
- end
336
-
337
- GUESSED_CLASSES = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]
338
-
339
- def test_table_name_guesses
340
- assert_equal "topics", Topic.table_name
341
-
342
- assert_equal "categories", Category.table_name
343
- assert_equal "smarts", Smarts.table_name
344
- assert_equal "credit_cards", CreditCard.table_name
345
- assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
346
- assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
347
- assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
348
- assert_equal "categories", CreditCard::Brand.table_name
349
- assert_equal "master_credit_cards", MasterCreditCard.table_name
350
- ensure
351
- GUESSED_CLASSES.each(&:reset_table_name)
352
- end
353
-
354
- def test_singular_table_name_guesses
355
- ActiveRecord::Base.pluralize_table_names = false
356
- GUESSED_CLASSES.each(&:reset_table_name)
357
-
358
- assert_equal "category", Category.table_name
359
- assert_equal "smarts", Smarts.table_name
360
- assert_equal "credit_card", CreditCard.table_name
361
- assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
362
- assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
363
- assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
364
- assert_equal "category", CreditCard::Brand.table_name
365
- assert_equal "master_credit_card", MasterCreditCard.table_name
366
- ensure
367
- ActiveRecord::Base.pluralize_table_names = true
368
- GUESSED_CLASSES.each(&:reset_table_name)
369
- end
370
-
371
- def test_table_name_guesses_with_prefixes_and_suffixes
372
- ActiveRecord::Base.table_name_prefix = "test_"
373
- Category.reset_table_name
374
- assert_equal "test_categories", Category.table_name
375
- ActiveRecord::Base.table_name_suffix = "_test"
376
- Category.reset_table_name
377
- assert_equal "test_categories_test", Category.table_name
378
- ActiveRecord::Base.table_name_prefix = ""
379
- Category.reset_table_name
380
- assert_equal "categories_test", Category.table_name
381
- ActiveRecord::Base.table_name_suffix = ""
382
- Category.reset_table_name
383
- assert_equal "categories", Category.table_name
384
- ensure
385
- ActiveRecord::Base.table_name_prefix = ""
386
- ActiveRecord::Base.table_name_suffix = ""
387
- GUESSED_CLASSES.each(&:reset_table_name)
388
- end
389
-
390
- def test_singular_table_name_guesses_with_prefixes_and_suffixes
391
- ActiveRecord::Base.pluralize_table_names = false
392
-
393
- ActiveRecord::Base.table_name_prefix = "test_"
394
- Category.reset_table_name
395
- assert_equal "test_category", Category.table_name
396
- ActiveRecord::Base.table_name_suffix = "_test"
397
- Category.reset_table_name
398
- assert_equal "test_category_test", Category.table_name
399
- ActiveRecord::Base.table_name_prefix = ""
400
- Category.reset_table_name
401
- assert_equal "category_test", Category.table_name
402
- ActiveRecord::Base.table_name_suffix = ""
403
- Category.reset_table_name
404
- assert_equal "category", Category.table_name
405
- ensure
406
- ActiveRecord::Base.pluralize_table_names = true
407
- ActiveRecord::Base.table_name_prefix = ""
408
- ActiveRecord::Base.table_name_suffix = ""
409
- GUESSED_CLASSES.each(&:reset_table_name)
410
- end
411
-
412
- def test_table_name_guesses_with_inherited_prefixes_and_suffixes
413
- GUESSED_CLASSES.each(&:reset_table_name)
414
-
415
- CreditCard.table_name_prefix = "test_"
416
- CreditCard.reset_table_name
417
- Category.reset_table_name
418
- assert_equal "test_credit_cards", CreditCard.table_name
419
- assert_equal "categories", Category.table_name
420
- CreditCard.table_name_suffix = "_test"
421
- CreditCard.reset_table_name
422
- Category.reset_table_name
423
- assert_equal "test_credit_cards_test", CreditCard.table_name
424
- assert_equal "categories", Category.table_name
425
- CreditCard.table_name_prefix = ""
426
- CreditCard.reset_table_name
427
- Category.reset_table_name
428
- assert_equal "credit_cards_test", CreditCard.table_name
429
- assert_equal "categories", Category.table_name
430
- CreditCard.table_name_suffix = ""
431
- CreditCard.reset_table_name
432
- Category.reset_table_name
433
- assert_equal "credit_cards", CreditCard.table_name
434
- assert_equal "categories", Category.table_name
435
- ensure
436
- CreditCard.table_name_prefix = ""
437
- CreditCard.table_name_suffix = ""
438
- GUESSED_CLASSES.each(&:reset_table_name)
439
- end
440
-
441
- def test_singular_table_name_guesses_for_individual_table
442
- CreditCard.pluralize_table_names = false
443
- CreditCard.reset_table_name
444
- assert_equal "credit_card", CreditCard.table_name
445
- assert_equal "categories", Category.table_name
446
- ensure
447
- CreditCard.pluralize_table_names = true
448
- CreditCard.reset_table_name
449
- end
450
-
451
- if current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter)
452
- def test_update_all_with_order_and_limit
453
- assert_equal 1, Topic.update_all("content = 'bulk updated!'", nil, :limit => 1, :order => 'id DESC')
454
- end
455
- end
456
-
457
- def test_null_fields
458
- assert_nil Topic.find(1).parent_id
459
- assert_nil Topic.create("title" => "Hey you").parent_id
460
- end
461
-
462
- def test_default_values
463
- topic = Topic.new
464
- assert topic.approved?
465
- assert_nil topic.written_on
466
- assert_nil topic.bonus_time
467
- assert_nil topic.last_read
468
-
469
- topic.save
470
-
471
- topic = Topic.find(topic.id)
472
- assert topic.approved?
473
- assert_nil topic.last_read
474
-
475
- # Oracle has some funky default handling, so it requires a bit of
476
- # extra testing. See ticket #2788.
477
- if current_adapter?(:OracleAdapter)
478
- test = TestOracleDefault.new
479
- assert_equal "X", test.test_char
480
- assert_equal "hello", test.test_string
481
- assert_equal 3, test.test_int
482
- end
483
- end
484
-
485
- # Oracle, and Sybase do not have a TIME datatype.
486
- unless current_adapter?(:OracleAdapter, :SybaseAdapter)
487
- def test_utc_as_time_zone
488
- Topic.default_timezone = :utc
489
- attributes = { "bonus_time" => "5:42:00AM" }
490
- topic = Topic.find(1)
491
- topic.attributes = attributes
492
- assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
493
- Topic.default_timezone = :local
494
- end
495
-
496
- def test_utc_as_time_zone_and_new
497
- Topic.default_timezone = :utc
498
- attributes = { "bonus_time(1i)"=>"2000",
499
- "bonus_time(2i)"=>"1",
500
- "bonus_time(3i)"=>"1",
501
- "bonus_time(4i)"=>"10",
502
- "bonus_time(5i)"=>"35",
503
- "bonus_time(6i)"=>"50" }
504
- topic = Topic.new(attributes)
505
- assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
506
- Topic.default_timezone = :local
507
- end
508
- end
509
-
510
- def test_default_values_on_empty_strings
511
- topic = Topic.new
512
- topic.approved = nil
513
- topic.last_read = nil
514
-
515
- topic.save
516
-
517
- topic = Topic.find(topic.id)
518
- assert_nil topic.last_read
519
-
520
- # Sybase adapter does not allow nulls in boolean columns
521
- if current_adapter?(:SybaseAdapter)
522
- assert topic.approved == false
523
- else
524
- assert_nil topic.approved
525
- end
526
- end
527
-
528
- def test_equality
529
- assert_equal Topic.find(1), Topic.find(2).topic
530
- end
531
-
532
- def test_find_by_slug
533
- assert_equal Topic.find('1-meowmeow'), Topic.find(1)
534
- end
535
-
536
- def test_equality_of_new_records
537
- assert_not_equal Topic.new, Topic.new
538
- end
539
-
540
- def test_equality_of_destroyed_records
541
- topic_1 = Topic.new(:title => 'test_1')
542
- topic_1.save
543
- topic_2 = Topic.find(topic_1.id)
544
- topic_1.destroy
545
- assert_equal topic_1, topic_2
546
- assert_equal topic_2, topic_1
547
- end
548
-
549
- def test_hashing
550
- assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
551
- end
552
-
553
- def test_comparison
554
- topic_1 = Topic.create!
555
- topic_2 = Topic.create!
556
-
557
- assert_equal [topic_2, topic_1].sort, [topic_1, topic_2]
558
- end
559
-
560
- def test_comparison_with_different_objects
561
- topic = Topic.create
562
- category = Category.create(:name => "comparison")
563
- assert_nil topic <=> category
564
- end
565
-
566
- def test_readonly_attributes
567
- assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes
568
-
569
- post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable")
570
- post.reload
571
- assert_equal "cannot change this", post.title
572
-
573
- post.update_attributes(:title => "try to change", :body => "changed")
574
- post.reload
575
- assert_equal "cannot change this", post.title
576
- assert_equal "changed", post.body
577
- end
578
-
579
- def test_non_valid_identifier_column_name
580
- weird = Weird.create('a$b' => 'value')
581
- weird.reload
582
- assert_equal 'value', weird.send('a$b')
583
- assert_equal 'value', weird.read_attribute('a$b')
584
-
585
- weird.update_column('a$b', 'value2')
586
- weird.reload
587
- assert_equal 'value2', weird.send('a$b')
588
- assert_equal 'value2', weird.read_attribute('a$b')
589
- end
590
-
591
- def test_multiparameter_attributes_on_date
592
- attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" }
593
- topic = Topic.find(1)
594
- topic.attributes = attributes
595
- # note that extra #to_date call allows test to pass for Oracle, which
596
- # treats dates/times the same
597
- assert_date_from_db Date.new(2004, 6, 24), topic.last_read.to_date
598
- end
599
-
600
- def test_multiparameter_attributes_on_date_with_empty_year
601
- attributes = { "last_read(1i)" => "", "last_read(2i)" => "6", "last_read(3i)" => "24" }
602
- topic = Topic.find(1)
603
- topic.attributes = attributes
604
- # note that extra #to_date call allows test to pass for Oracle, which
605
- # treats dates/times the same
606
- assert_nil topic.last_read
607
- end
608
-
609
- def test_multiparameter_attributes_on_date_with_empty_month
610
- attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "", "last_read(3i)" => "24" }
611
- topic = Topic.find(1)
612
- topic.attributes = attributes
613
- # note that extra #to_date call allows test to pass for Oracle, which
614
- # treats dates/times the same
615
- assert_nil topic.last_read
616
- end
617
-
618
- def test_multiparameter_attributes_on_date_with_empty_day
619
- attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "" }
620
- topic = Topic.find(1)
621
- topic.attributes = attributes
622
- # note that extra #to_date call allows test to pass for Oracle, which
623
- # treats dates/times the same
624
- assert_nil topic.last_read
625
- end
626
-
627
- def test_multiparameter_attributes_on_date_with_empty_day_and_year
628
- attributes = { "last_read(1i)" => "", "last_read(2i)" => "6", "last_read(3i)" => "" }
629
- topic = Topic.find(1)
630
- topic.attributes = attributes
631
- # note that extra #to_date call allows test to pass for Oracle, which
632
- # treats dates/times the same
633
- assert_nil topic.last_read
634
- end
635
-
636
- def test_multiparameter_attributes_on_date_with_empty_day_and_month
637
- attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "", "last_read(3i)" => "" }
638
- topic = Topic.find(1)
639
- topic.attributes = attributes
640
- # note that extra #to_date call allows test to pass for Oracle, which
641
- # treats dates/times the same
642
- assert_nil topic.last_read
643
- end
644
-
645
- def test_multiparameter_attributes_on_date_with_empty_year_and_month
646
- attributes = { "last_read(1i)" => "", "last_read(2i)" => "", "last_read(3i)" => "24" }
647
- topic = Topic.find(1)
648
- topic.attributes = attributes
649
- # note that extra #to_date call allows test to pass for Oracle, which
650
- # treats dates/times the same
651
- assert_nil topic.last_read
652
- end
653
-
654
- def test_multiparameter_attributes_on_date_with_all_empty
655
- attributes = { "last_read(1i)" => "", "last_read(2i)" => "", "last_read(3i)" => "" }
656
- topic = Topic.find(1)
657
- topic.attributes = attributes
658
- assert_nil topic.last_read
659
- end
660
-
661
- def test_multiparameter_attributes_on_time
662
- attributes = {
663
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
664
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
665
- }
666
- topic = Topic.find(1)
667
- topic.attributes = attributes
668
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
669
- end
670
-
671
- def test_multiparameter_attributes_on_time_with_no_date
672
- ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
673
- attributes = {
674
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
675
- }
676
- topic = Topic.find(1)
677
- topic.attributes = attributes
678
- end
679
- assert_equal("written_on", ex.errors[0].attribute)
680
- end
681
-
682
- def test_multiparameter_attributes_on_time_with_invalid_time_params
683
- ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
684
- attributes = {
685
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
686
- "written_on(4i)" => "2004", "written_on(5i)" => "36", "written_on(6i)" => "64",
687
- }
688
- topic = Topic.find(1)
689
- topic.attributes = attributes
690
- end
691
- assert_equal("written_on", ex.errors[0].attribute)
692
- end
693
-
694
- def test_multiparameter_attributes_on_time_with_old_date
695
- attributes = {
696
- "written_on(1i)" => "1850", "written_on(2i)" => "6", "written_on(3i)" => "24",
697
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
698
- }
699
- topic = Topic.find(1)
700
- topic.attributes = attributes
701
- # testing against to_s(:db) representation because either a Time or a DateTime might be returned, depending on platform
702
- assert_equal "1850-06-24 16:24:00", topic.written_on.to_s(:db)
703
- end
704
-
705
- def test_multiparameter_attributes_on_time_will_raise_on_big_time_if_missing_date_parts
706
- ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
707
- attributes = {
708
- "written_on(4i)" => "16", "written_on(5i)" => "24"
709
- }
710
- topic = Topic.find(1)
711
- topic.attributes = attributes
712
- end
713
- assert_equal("written_on", ex.errors[0].attribute)
714
- end
715
-
716
- def test_multiparameter_attributes_on_time_with_raise_on_small_time_if_missing_date_parts
717
- ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
718
- attributes = {
719
- "written_on(4i)" => "16", "written_on(5i)" => "12", "written_on(6i)" => "02"
720
- }
721
- topic = Topic.find(1)
722
- topic.attributes = attributes
723
- end
724
- assert_equal("written_on", ex.errors[0].attribute)
725
- end
726
-
727
- def test_multiparameter_attributes_on_time_will_ignore_hour_if_missing
728
- attributes = {
729
- "written_on(1i)" => "2004", "written_on(2i)" => "12", "written_on(3i)" => "12",
730
- "written_on(5i)" => "12", "written_on(6i)" => "02"
731
- }
732
- topic = Topic.find(1)
733
- topic.attributes = attributes
734
- assert_equal Time.local(2004, 12, 12, 0, 12, 2), topic.written_on
735
- end
736
-
737
- def test_multiparameter_attributes_on_time_will_ignore_hour_if_blank
738
- attributes = {
739
- "written_on(1i)" => "", "written_on(2i)" => "", "written_on(3i)" => "",
740
- "written_on(4i)" => "", "written_on(5i)" => "12", "written_on(6i)" => "02"
741
- }
742
- topic = Topic.find(1)
743
- topic.attributes = attributes
744
- assert_nil topic.written_on
745
- end
746
-
747
- def test_multiparameter_attributes_on_time_will_ignore_date_if_empty
748
- attributes = {
749
- "written_on(1i)" => "", "written_on(2i)" => "", "written_on(3i)" => "",
750
- "written_on(4i)" => "16", "written_on(5i)" => "24"
751
- }
752
- topic = Topic.find(1)
753
- topic.attributes = attributes
754
- assert_nil topic.written_on
755
- end
756
- def test_multiparameter_attributes_on_time_with_seconds_will_ignore_date_if_empty
757
- attributes = {
758
- "written_on(1i)" => "", "written_on(2i)" => "", "written_on(3i)" => "",
759
- "written_on(4i)" => "16", "written_on(5i)" => "12", "written_on(6i)" => "02"
760
- }
761
- topic = Topic.find(1)
762
- topic.attributes = attributes
763
- assert_nil topic.written_on
764
- end
765
-
766
- def test_multiparameter_attributes_on_time_with_utc
767
- ActiveRecord::Base.default_timezone = :utc
768
- attributes = {
769
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
770
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
771
- }
772
- topic = Topic.find(1)
773
- topic.attributes = attributes
774
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
775
- ensure
776
- ActiveRecord::Base.default_timezone = :local
777
- end
778
-
779
- def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes
780
- ActiveRecord::Base.time_zone_aware_attributes = true
781
- ActiveRecord::Base.default_timezone = :utc
782
- Time.zone = ActiveSupport::TimeZone[-28800]
783
- attributes = {
784
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
785
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
786
- }
787
- topic = Topic.find(1)
788
- topic.attributes = attributes
789
- assert_equal Time.utc(2004, 6, 24, 23, 24, 0), topic.written_on
790
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on.time
791
- assert_equal Time.zone, topic.written_on.time_zone
792
- ensure
793
- ActiveRecord::Base.time_zone_aware_attributes = false
794
- ActiveRecord::Base.default_timezone = :local
795
- Time.zone = nil
796
- end
797
-
798
- def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes_false
799
- ActiveRecord::Base.time_zone_aware_attributes = false
800
- Time.zone = ActiveSupport::TimeZone[-28800]
801
- attributes = {
802
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
803
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
804
- }
805
- topic = Topic.find(1)
806
- topic.attributes = attributes
807
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
808
- assert_equal false, topic.written_on.respond_to?(:time_zone)
809
- ensure
810
- Time.zone = nil
811
- end
812
-
813
- def test_multiparameter_attributes_on_time_with_skip_time_zone_conversion_for_attributes
814
- ActiveRecord::Base.time_zone_aware_attributes = true
815
- ActiveRecord::Base.default_timezone = :utc
816
- Time.zone = ActiveSupport::TimeZone[-28800]
817
- Topic.skip_time_zone_conversion_for_attributes = [:written_on]
818
- attributes = {
819
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
820
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
821
- }
822
- topic = Topic.find(1)
823
- topic.attributes = attributes
824
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
825
- assert_equal false, topic.written_on.respond_to?(:time_zone)
826
- ensure
827
- ActiveRecord::Base.time_zone_aware_attributes = false
828
- ActiveRecord::Base.default_timezone = :local
829
- Time.zone = nil
830
- Topic.skip_time_zone_conversion_for_attributes = []
831
- end
832
-
833
- # Oracle, and Sybase do not have a TIME datatype.
834
- unless current_adapter?(:OracleAdapter, :SybaseAdapter)
835
- def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion
836
- ActiveRecord::Base.time_zone_aware_attributes = true
837
- ActiveRecord::Base.default_timezone = :utc
838
- Time.zone = ActiveSupport::TimeZone[-28800]
839
- attributes = {
840
- "bonus_time(1i)" => "2000", "bonus_time(2i)" => "1", "bonus_time(3i)" => "1",
841
- "bonus_time(4i)" => "16", "bonus_time(5i)" => "24"
842
- }
843
- topic = Topic.find(1)
844
- topic.attributes = attributes
845
- assert_equal Time.utc(2000, 1, 1, 16, 24, 0), topic.bonus_time
846
- assert topic.bonus_time.utc?
847
- ensure
848
- ActiveRecord::Base.time_zone_aware_attributes = false
849
- ActiveRecord::Base.default_timezone = :local
850
- Time.zone = nil
851
- end
852
- end
853
-
854
- def test_multiparameter_attributes_on_time_with_empty_seconds
855
- attributes = {
856
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
857
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => ""
858
- }
859
- topic = Topic.find(1)
860
- topic.attributes = attributes
861
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
862
- end
863
-
864
- def test_multiparameter_assignment_of_aggregation
865
- customer = Customer.new
866
- address = Address.new("The Street", "The City", "The Country")
867
- attributes = { "address(1)" => address.street, "address(2)" => address.city, "address(3)" => address.country }
868
- customer.attributes = attributes
869
- assert_equal address, customer.address
870
- end
871
-
872
- def test_multiparameter_assignment_of_aggregation_out_of_order
873
- customer = Customer.new
874
- address = Address.new("The Street", "The City", "The Country")
875
- attributes = { "address(3)" => address.country, "address(2)" => address.city, "address(1)" => address.street }
876
- customer.attributes = attributes
877
- assert_equal address, customer.address
878
- end
879
-
880
- def test_multiparameter_assignment_of_aggregation_with_missing_values
881
- ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
882
- customer = Customer.new
883
- address = Address.new("The Street", "The City", "The Country")
884
- attributes = { "address(2)" => address.city, "address(3)" => address.country }
885
- customer.attributes = attributes
886
- end
887
- assert_equal("address", ex.errors[0].attribute)
888
- end
889
-
890
- def test_multiparameter_assignment_of_aggregation_with_blank_values
891
- customer = Customer.new
892
- address = Address.new("The Street", "The City", "The Country")
893
- attributes = { "address(1)" => "", "address(2)" => address.city, "address(3)" => address.country }
894
- customer.attributes = attributes
895
- assert_equal Address.new(nil, "The City", "The Country"), customer.address
896
- end
897
-
898
- def test_multiparameter_assignment_of_aggregation_with_large_index
899
- ex = assert_raise(ActiveRecord::MultiparameterAssignmentErrors) do
900
- customer = Customer.new
901
- address = Address.new("The Street", "The City", "The Country")
902
- attributes = { "address(1)" => "The Street", "address(2)" => address.city, "address(3000)" => address.country }
903
- customer.attributes = attributes
904
- end
905
- assert_equal("address", ex.errors[0].attribute)
906
- end
907
-
908
- def test_attributes_on_dummy_time
909
- # Oracle, and Sybase do not have a TIME datatype.
910
- return true if current_adapter?(:OracleAdapter, :SybaseAdapter)
911
-
912
- attributes = {
913
- "bonus_time" => "5:42:00AM"
914
- }
915
- topic = Topic.find(1)
916
- topic.attributes = attributes
917
- assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
918
- end
919
-
920
- def test_boolean
921
- b_nil = Boolean.create({ "value" => nil })
922
- nil_id = b_nil.id
923
- b_false = Boolean.create({ "value" => false })
924
- false_id = b_false.id
925
- b_true = Boolean.create({ "value" => true })
926
- true_id = b_true.id
927
-
928
- b_nil = Boolean.find(nil_id)
929
- assert_nil b_nil.value
930
- b_false = Boolean.find(false_id)
931
- assert !b_false.value?
932
- b_true = Boolean.find(true_id)
933
- assert b_true.value?
934
- end
935
-
936
- def test_boolean_cast_from_string
937
- b_blank = Boolean.create({ "value" => "" })
938
- blank_id = b_blank.id
939
- b_false = Boolean.create({ "value" => "0" })
940
- false_id = b_false.id
941
- b_true = Boolean.create({ "value" => "1" })
942
- true_id = b_true.id
943
-
944
- b_blank = Boolean.find(blank_id)
945
- assert_nil b_blank.value
946
- b_false = Boolean.find(false_id)
947
- assert !b_false.value?
948
- b_true = Boolean.find(true_id)
949
- assert b_true.value?
950
- end
951
-
952
- def test_new_record_returns_boolean
953
- assert_equal false, Topic.new.persisted?
954
- assert_equal true, Topic.find(1).persisted?
955
- end
956
-
957
- def test_dup
958
- topic = Topic.find(1)
959
- duped_topic = nil
960
- assert_nothing_raised { duped_topic = topic.dup }
961
- assert_equal topic.title, duped_topic.title
962
- assert !duped_topic.persisted?
963
-
964
- # test if the attributes have been duped
965
- topic.title = "a"
966
- duped_topic.title = "b"
967
- assert_equal "a", topic.title
968
- assert_equal "b", duped_topic.title
969
-
970
- # test if the attribute values have been duped
971
- topic.title = {"a" => "b"}
972
- duped_topic = topic.dup
973
- duped_topic.title["a"] = "c"
974
- assert_equal "b", topic.title["a"]
975
-
976
- # test if attributes set as part of after_initialize are duped correctly
977
- assert_equal topic.author_email_address, duped_topic.author_email_address
978
-
979
- # test if saved clone object differs from original
980
- duped_topic.save
981
- assert duped_topic.persisted?
982
- assert_not_equal duped_topic.id, topic.id
983
-
984
- duped_topic.reload
985
- # FIXME: I think this is poor behavior, and will fix it with #5686
986
- assert_equal({'a' => 'c'}.to_yaml, duped_topic.title)
987
- end
988
-
989
- def test_dup_with_aggregate_of_same_name_as_attribute
990
- dev = DeveloperWithAggregate.find(1)
991
- assert_kind_of DeveloperSalary, dev.salary
992
-
993
- dup = nil
994
- assert_nothing_raised { dup = dev.dup }
995
- assert_kind_of DeveloperSalary, dup.salary
996
- assert_equal dev.salary.amount, dup.salary.amount
997
- assert !dup.persisted?
998
-
999
- # test if the attributes have been dupd
1000
- original_amount = dup.salary.amount
1001
- dev.salary.amount = 1
1002
- assert_equal original_amount, dup.salary.amount
1003
-
1004
- assert dup.save
1005
- assert dup.persisted?
1006
- assert_not_equal dup.id, dev.id
1007
- end
1008
-
1009
- def test_dup_does_not_copy_associations
1010
- author = authors(:david)
1011
- assert_not_equal [], author.posts
1012
- author.send(:clear_association_cache)
1013
-
1014
- author_dup = author.dup
1015
- assert_equal [], author_dup.posts
1016
- end
1017
-
1018
- def test_clone_preserves_subtype
1019
- clone = nil
1020
- assert_nothing_raised { clone = Company.find(3).clone }
1021
- assert_kind_of Client, clone
1022
- end
1023
-
1024
- def test_clone_of_new_object_with_defaults
1025
- developer = Developer.new
1026
- assert !developer.name_changed?
1027
- assert !developer.salary_changed?
1028
-
1029
- cloned_developer = developer.clone
1030
- assert !cloned_developer.name_changed?
1031
- assert !cloned_developer.salary_changed?
1032
- end
1033
-
1034
- def test_clone_of_new_object_marks_attributes_as_dirty
1035
- developer = Developer.new :name => 'Bjorn', :salary => 100000
1036
- assert developer.name_changed?
1037
- assert developer.salary_changed?
1038
-
1039
- cloned_developer = developer.clone
1040
- assert cloned_developer.name_changed?
1041
- assert cloned_developer.salary_changed?
1042
- end
1043
-
1044
- def test_clone_of_new_object_marks_as_dirty_only_changed_attributes
1045
- developer = Developer.new :name => 'Bjorn'
1046
- assert developer.name_changed? # obviously
1047
- assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed
1048
-
1049
- cloned_developer = developer.clone
1050
- assert cloned_developer.name_changed?
1051
- assert !cloned_developer.salary_changed? # ... and cloned instance should behave same
1052
- end
1053
-
1054
- def test_dup_of_saved_object_marks_attributes_as_dirty
1055
- developer = Developer.create! :name => 'Bjorn', :salary => 100000
1056
- assert !developer.name_changed?
1057
- assert !developer.salary_changed?
1058
-
1059
- cloned_developer = developer.dup
1060
- assert cloned_developer.name_changed? # both attributes differ from defaults
1061
- assert cloned_developer.salary_changed?
1062
- end
1063
-
1064
- def test_dup_of_saved_object_marks_as_dirty_only_changed_attributes
1065
- developer = Developer.create! :name => 'Bjorn'
1066
- assert !developer.name_changed? # both attributes of saved object should be treated as not changed
1067
- assert !developer.salary_changed?
1068
-
1069
- cloned_developer = developer.dup
1070
- assert cloned_developer.name_changed? # ... but on cloned object should be
1071
- assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be treated as not changed on cloned instance
1072
- end
1073
-
1074
- def test_bignum
1075
- company = Company.find(1)
1076
- company.rating = 2147483647
1077
- company.save
1078
- company = Company.find(1)
1079
- assert_equal 2147483647, company.rating
1080
- end
1081
-
1082
- # TODO: extend defaults tests to other databases!
1083
- if current_adapter?(:PostgreSQLAdapter)
1084
- def test_default
1085
- default = Default.new
1086
-
1087
- # fixed dates / times
1088
- assert_equal Date.new(2004, 1, 1), default.fixed_date
1089
- assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
1090
-
1091
- # char types
1092
- assert_equal 'Y', default.char1
1093
- assert_equal 'a varchar field', default.char2
1094
- assert_equal 'a text field', default.char3
1095
- end
1096
-
1097
- class Geometric < ActiveRecord::Base; end
1098
- def test_geometric_content
1099
-
1100
- # accepted format notes:
1101
- # ()'s aren't required
1102
- # values can be a mix of float or integer
1103
-
1104
- g = Geometric.new(
1105
- :a_point => '(5.0, 6.1)',
1106
- #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
1107
- :a_line_segment => '(2.0, 3), (5.5, 7.0)',
1108
- :a_box => '2.0, 3, 5.5, 7.0',
1109
- :a_path => '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]', # [ ] is an open path
1110
- :a_polygon => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))',
1111
- :a_circle => '<(5.3, 10.4), 2>'
1112
- )
1113
-
1114
- assert g.save
1115
-
1116
- # Reload and check that we have all the geometric attributes.
1117
- h = ActiveRecord::IdentityMap.without { Geometric.find(g.id) }
1118
-
1119
- assert_equal '(5,6.1)', h.a_point
1120
- assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
1121
- assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
1122
- assert_equal '[(2,3),(5.5,7),(8.5,11)]', h.a_path
1123
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
1124
- assert_equal '<(5.3,10.4),2>', h.a_circle
1125
-
1126
- # use a geometric function to test for an open path
1127
- objs = Geometric.find_by_sql ["select isopen(a_path) from geometrics where id = ?", g.id]
1128
- assert_equal objs[0].isopen, 't'
1129
-
1130
- # test alternate formats when defining the geometric types
1131
-
1132
- g = Geometric.new(
1133
- :a_point => '5.0, 6.1',
1134
- #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
1135
- :a_line_segment => '((2.0, 3), (5.5, 7.0))',
1136
- :a_box => '(2.0, 3), (5.5, 7.0)',
1137
- :a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', # ( ) is a closed path
1138
- :a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
1139
- :a_circle => '((5.3, 10.4), 2)'
1140
- )
1141
-
1142
- assert g.save
1143
-
1144
- # Reload and check that we have all the geometric attributes.
1145
- h = ActiveRecord::IdentityMap.without { Geometric.find(g.id) }
1146
-
1147
- assert_equal '(5,6.1)', h.a_point
1148
- assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
1149
- assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
1150
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
1151
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
1152
- assert_equal '<(5.3,10.4),2>', h.a_circle
1153
-
1154
- # use a geometric function to test for an closed path
1155
- objs = Geometric.find_by_sql ["select isclosed(a_path) from geometrics where id = ?", g.id]
1156
- assert_equal objs[0].isclosed, 't'
1157
- end
1158
- end
1159
-
1160
- class NumericData < ActiveRecord::Base
1161
- self.table_name = 'numeric_data'
1162
- end
1163
-
1164
- def test_big_decimal_conditions
1165
- m = NumericData.new(
1166
- :bank_balance => 1586.43,
1167
- :big_bank_balance => BigDecimal("1000234000567.95"),
1168
- :world_population => 6000000000,
1169
- :my_house_population => 3
1170
- )
1171
- assert m.save
1172
- assert_equal 0, NumericData.where("bank_balance > ?", 2000.0).count
1173
- end
1174
-
1175
- def test_numeric_fields
1176
- m = NumericData.new(
1177
- :bank_balance => 1586.43,
1178
- :big_bank_balance => BigDecimal("1000234000567.95"),
1179
- :world_population => 6000000000,
1180
- :my_house_population => 3
1181
- )
1182
- assert m.save
1183
-
1184
- m1 = NumericData.find(m.id)
1185
- assert_not_nil m1
1186
-
1187
- # As with migration_test.rb, we should make world_population >= 2**62
1188
- # to cover 64-bit platforms and test it is a Bignum, but the main thing
1189
- # is that it's an Integer.
1190
- unless current_adapter?(:IBM_DBAdapter)
1191
- assert_kind_of Integer, m1.world_population
1192
- else
1193
- assert_kind_of BigDecimal, m1.world_population
1194
- end
1195
- assert_equal 6000000000, m1.world_population
1196
-
1197
- unless current_adapter?(:IBM_DBAdapter)
1198
- assert_kind_of Fixnum, m1.my_house_population
1199
- else
1200
- assert_kind_of BigDecimal, m1.my_house_population
1201
- end
1202
- assert_equal 3, m1.my_house_population
1203
-
1204
- assert_kind_of BigDecimal, m1.bank_balance
1205
- assert_equal BigDecimal("1586.43"), m1.bank_balance
1206
-
1207
- assert_kind_of BigDecimal, m1.big_bank_balance
1208
- assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
1209
- end
1210
-
1211
- def test_auto_id
1212
- auto = AutoId.new
1213
- auto.save
1214
- assert(auto.id > 0)
1215
- end
1216
-
1217
- def test_sql_injection_via_find
1218
- assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
1219
- Topic.find("123456 OR id > 0")
1220
- end
1221
- end
1222
-
1223
- def test_column_name_properly_quoted
1224
- col_record = ColumnName.new
1225
- col_record.references = 40
1226
- assert col_record.save
1227
- col_record.references = 41
1228
- assert col_record.save
1229
- assert_not_nil c2 = ColumnName.find(col_record.id)
1230
- assert_equal(41, c2.references)
1231
- end
1232
-
1233
- def test_quoting_arrays
1234
- replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
1235
- assert_equal topics(:first).replies.size, replies.size
1236
-
1237
- replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
1238
- assert_equal 0, replies.size
1239
- end
1240
-
1241
- MyObject = Struct.new :attribute1, :attribute2
1242
-
1243
- def test_serialized_attribute
1244
- Topic.serialize("content", MyObject)
1245
-
1246
- myobj = MyObject.new('value1', 'value2')
1247
- topic = Topic.create("content" => myobj)
1248
- assert_equal(myobj, topic.content)
1249
-
1250
- topic.reload
1251
- assert_equal(myobj, topic.content)
1252
- end
1253
-
1254
- def test_serialized_attribute_in_base_class
1255
- Topic.serialize("content", Hash)
1256
-
1257
- hash = { 'content1' => 'value1', 'content2' => 'value2' }
1258
- important_topic = ImportantTopic.create("content" => hash)
1259
- assert_equal(hash, important_topic.content)
1260
-
1261
- important_topic.reload
1262
- assert_equal(hash, important_topic.content)
1263
- end
1264
-
1265
- # This test was added to fix GH #4004. Obviously the value returned
1266
- # is not really the value 'before type cast' so we should maybe think
1267
- # about changing that in the future.
1268
- def test_serialized_attribute_before_type_cast_returns_unserialized_value
1269
- klass = Class.new(ActiveRecord::Base)
1270
- klass.table_name = "topics"
1271
- klass.serialize :content, Hash
1272
-
1273
- t = klass.new(:content => { :foo => :bar })
1274
- assert_equal({ :foo => :bar }, t.content_before_type_cast)
1275
- t.save!
1276
- t.reload
1277
- assert_equal({ :foo => :bar }, t.content_before_type_cast)
1278
- end
1279
-
1280
- def test_serialized_attribute_declared_in_subclass
1281
- hash = { 'important1' => 'value1', 'important2' => 'value2' }
1282
- important_topic = ImportantTopic.create("important" => hash)
1283
- assert_equal(hash, important_topic.important)
1284
-
1285
- important_topic.reload
1286
- assert_equal(hash, important_topic.important)
1287
- assert_equal(hash, important_topic.read_attribute(:important))
1288
- end
1289
-
1290
- def test_serialized_time_attribute
1291
- myobj = Time.local(2008,1,1,1,0)
1292
- topic = Topic.create("content" => myobj).reload
1293
- assert_equal(myobj, topic.content)
1294
- end
1295
-
1296
- def test_serialized_string_attribute
1297
- myobj = "Yes"
1298
- topic = Topic.create("content" => myobj).reload
1299
- assert_equal(myobj, topic.content)
1300
- end
1301
-
1302
- def test_nil_serialized_attribute_with_class_constraint
1303
- topic = Topic.new
1304
- assert_nil topic.content
1305
- end
1306
-
1307
- def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
1308
- myobj = MyObject.new('value1', 'value2')
1309
- topic = Topic.new(:content => myobj)
1310
- assert topic.save
1311
- Topic.serialize(:content, Hash)
1312
- assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).reload.content }
1313
- ensure
1314
- Topic.serialize(:content)
1315
- end
1316
-
1317
- def test_serialized_attribute_with_class_constraint
1318
- settings = { "color" => "blue" }
1319
- Topic.serialize(:content, Hash)
1320
- topic = Topic.new(:content => settings)
1321
- assert topic.save
1322
- assert_equal(settings, Topic.find(topic.id).content)
1323
- ensure
1324
- Topic.serialize(:content)
1325
- end
1326
-
1327
- def test_serialized_default_class
1328
- Topic.serialize(:content, Hash)
1329
- topic = Topic.new
1330
- assert_equal Hash, topic.content.class
1331
- assert_equal Hash, topic.read_attribute(:content).class
1332
- topic.content["beer"] = "MadridRb"
1333
- assert topic.save
1334
- topic.reload
1335
- assert_equal Hash, topic.content.class
1336
- assert_equal "MadridRb", topic.content["beer"]
1337
- ensure
1338
- Topic.serialize(:content)
1339
- end
1340
-
1341
- def test_serialized_no_default_class_for_object
1342
- topic = Topic.new
1343
- assert_nil topic.content
1344
- end
1345
-
1346
- def test_serialized_boolean_value_true
1347
- Topic.serialize(:content)
1348
- topic = Topic.new(:content => true)
1349
- assert topic.save
1350
- topic = topic.reload
1351
- assert_equal topic.content, true
1352
- end
1353
-
1354
- def test_serialized_boolean_value_false
1355
- Topic.serialize(:content)
1356
- topic = Topic.new(:content => false)
1357
- assert topic.save
1358
- topic = topic.reload
1359
- assert_equal topic.content, false
1360
- end
1361
-
1362
- def test_serialize_with_coder
1363
- coder = Class.new {
1364
- # Identity
1365
- def load(thing)
1366
- thing
1367
- end
1368
-
1369
- # base 64
1370
- def dump(thing)
1371
- [thing].pack('m')
1372
- end
1373
- }.new
1374
-
1375
- Topic.serialize(:content, coder)
1376
- s = 'hello world'
1377
- topic = Topic.new(:content => s)
1378
- assert topic.save
1379
- topic = topic.reload
1380
- assert_equal [s].pack('m'), topic.content
1381
- ensure
1382
- Topic.serialize(:content)
1383
- end
1384
-
1385
- def test_serialize_with_bcrypt_coder
1386
- crypt_coder = Class.new {
1387
- def load(thing)
1388
- return unless thing
1389
- BCrypt::Password.new thing
1390
- end
1391
-
1392
- def dump(thing)
1393
- BCrypt::Password.create(thing).to_s
1394
- end
1395
- }.new
1396
-
1397
- Topic.serialize(:content, crypt_coder)
1398
- password = 'password'
1399
- topic = Topic.new(:content => password)
1400
- assert topic.save
1401
- topic = topic.reload
1402
- assert_kind_of BCrypt::Password, topic.content
1403
- assert_equal(true, topic.content == password, 'password should equal')
1404
- ensure
1405
- Topic.serialize(:content)
1406
- end
1407
-
1408
- def test_quote
1409
- author_name = "\\ \001 ' \n \\n \""
1410
- topic = Topic.create('author_name' => author_name)
1411
- assert_equal author_name, Topic.find(topic.id).author_name
1412
- end
1413
-
1414
- if RUBY_VERSION < '1.9'
1415
- def test_quote_chars
1416
- with_kcode('UTF8') do
1417
- str = 'The Narrator'
1418
- topic = Topic.create(:author_name => str)
1419
- assert_equal str, topic.author_name
1420
-
1421
- assert_kind_of ActiveSupport::Multibyte.proxy_class, str.mb_chars
1422
- topic = Topic.find_by_author_name(str.mb_chars)
1423
-
1424
- assert_kind_of Topic, topic
1425
- assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
1426
- end
1427
- end
1428
- end
1429
-
1430
- def test_toggle_attribute
1431
- assert !topics(:first).approved?
1432
- topics(:first).toggle!(:approved)
1433
- assert topics(:first).approved?
1434
- topic = topics(:first)
1435
- topic.toggle(:approved)
1436
- assert !topic.approved?
1437
- topic.reload
1438
- assert topic.approved?
1439
- end
1440
-
1441
- def test_reload
1442
- t1 = Topic.find(1)
1443
- t2 = Topic.find(1)
1444
- t1.title = "something else"
1445
- t1.save
1446
- t2.reload
1447
- assert_equal t1.title, t2.title
1448
- end
1449
-
1450
- def test_reload_with_exclusive_scope
1451
- dev = DeveloperCalledDavid.first
1452
- dev.update_attributes!( :name => "NotDavid" )
1453
- assert_equal dev, dev.reload
1454
- end
1455
-
1456
- def test_set_table_name_with_value
1457
- k = Class.new( ActiveRecord::Base )
1458
- k.table_name = "foo"
1459
- assert_equal "foo", k.table_name
1460
-
1461
- assert_deprecated do
1462
- k.set_table_name "bar"
1463
- end
1464
- assert_equal "bar", k.table_name
1465
- end
1466
-
1467
- def test_switching_between_table_name
1468
- assert_difference("GoodJoke.count") do
1469
- Joke.table_name = "cold_jokes"
1470
- Joke.create
1471
-
1472
- Joke.table_name = "funny_jokes"
1473
- Joke.create
1474
- end
1475
- end
1476
-
1477
- def test_set_table_name_symbol_converted_to_string
1478
- Joke.table_name = :cold_jokes
1479
- assert_equal 'cold_jokes', Joke.table_name
1480
- end
1481
-
1482
- def test_quoted_table_name_after_set_table_name
1483
- klass = Class.new(ActiveRecord::Base)
1484
-
1485
- klass.table_name = "foo"
1486
- assert_equal "foo", klass.table_name
1487
- assert_equal klass.connection.quote_table_name("foo"), klass.quoted_table_name
1488
-
1489
- klass.table_name = "bar"
1490
- assert_equal "bar", klass.table_name
1491
- assert_equal klass.connection.quote_table_name("bar"), klass.quoted_table_name
1492
- end
1493
-
1494
- def test_set_table_name_with_block
1495
- k = Class.new( ActiveRecord::Base )
1496
- assert_deprecated do
1497
- k.set_table_name "foo"
1498
- k.set_table_name do
1499
- ActiveSupport::Deprecation.silence { original_table_name } + "ks"
1500
- end
1501
- end
1502
- assert_equal "fooks", k.table_name
1503
- end
1504
-
1505
- def test_set_table_name_with_inheritance
1506
- k = Class.new( ActiveRecord::Base )
1507
- def k.name; "Foo"; end
1508
- def k.table_name; super + "ks"; end
1509
- assert_equal "foosks", k.table_name
1510
- end
1511
-
1512
- def test_original_table_name
1513
- k = Class.new(ActiveRecord::Base)
1514
- def k.name; "Foo"; end
1515
- k.table_name = "bar"
1516
-
1517
- assert_deprecated do
1518
- assert_equal "foos", k.original_table_name
1519
- end
1520
-
1521
- k = Class.new(ActiveRecord::Base)
1522
- k.table_name = "omg"
1523
- k.table_name = "wtf"
1524
-
1525
- assert_deprecated do
1526
- assert_equal "omg", k.original_table_name
1527
- end
1528
- end
1529
-
1530
- def test_set_primary_key_with_value
1531
- k = Class.new( ActiveRecord::Base )
1532
- k.primary_key = "foo"
1533
- assert_equal "foo", k.primary_key
1534
-
1535
- assert_deprecated do
1536
- k.set_primary_key "bar"
1537
- end
1538
- assert_equal "bar", k.primary_key
1539
- end
1540
-
1541
- def test_set_primary_key_with_block
1542
- k = Class.new( ActiveRecord::Base )
1543
- k.primary_key = 'id'
1544
-
1545
- assert_deprecated do
1546
- k.set_primary_key do
1547
- "sys_" + ActiveSupport::Deprecation.silence { original_primary_key }
1548
- end
1549
- end
1550
- assert_equal "sys_id", k.primary_key
1551
- end
1552
-
1553
- def test_original_primary_key
1554
- k = Class.new(ActiveRecord::Base)
1555
- def k.name; "Foo"; end
1556
- k.table_name = "posts"
1557
- k.primary_key = "bar"
1558
-
1559
- assert_deprecated do
1560
- assert_equal "id", k.original_primary_key
1561
- end
1562
-
1563
- k = Class.new(ActiveRecord::Base)
1564
- k.primary_key = "omg"
1565
- k.primary_key = "wtf"
1566
-
1567
- assert_deprecated do
1568
- assert_equal "omg", k.original_primary_key
1569
- end
1570
- end
1571
-
1572
- def test_set_inheritance_column_with_value
1573
- k = Class.new( ActiveRecord::Base )
1574
- k.inheritance_column = "foo"
1575
- assert_equal "foo", k.inheritance_column
1576
-
1577
- assert_deprecated do
1578
- k.set_inheritance_column "bar"
1579
- end
1580
- assert_equal "bar", k.inheritance_column
1581
- end
1582
-
1583
- def test_set_inheritance_column_with_block
1584
- k = Class.new( ActiveRecord::Base )
1585
- assert_deprecated do
1586
- k.set_inheritance_column do
1587
- ActiveSupport::Deprecation.silence { original_inheritance_column } + "_id"
1588
- end
1589
- end
1590
- assert_equal "type_id", k.inheritance_column
1591
- end
1592
-
1593
- def test_original_inheritance_column
1594
- k = Class.new(ActiveRecord::Base)
1595
- def k.name; "Foo"; end
1596
- k.inheritance_column = "omg"
1597
-
1598
- assert_deprecated do
1599
- assert_equal "type", k.original_inheritance_column
1600
- end
1601
- end
1602
-
1603
- def test_set_sequence_name_with_value
1604
- k = Class.new( ActiveRecord::Base )
1605
- k.sequence_name = "foo"
1606
- assert_equal "foo", k.sequence_name
1607
-
1608
- assert_deprecated do
1609
- k.set_sequence_name "bar"
1610
- end
1611
- assert_equal "bar", k.sequence_name
1612
- end
1613
-
1614
- def test_set_sequence_name_with_block
1615
- k = Class.new( ActiveRecord::Base )
1616
- k.table_name = "projects"
1617
- orig_name = k.sequence_name
1618
- return skip "sequences not supported by db" unless orig_name
1619
-
1620
- assert_deprecated do
1621
- k.set_sequence_name do
1622
- ActiveSupport::Deprecation.silence { original_sequence_name } + "_lol"
1623
- end
1624
- end
1625
- assert_equal orig_name + "_lol", k.sequence_name
1626
- end
1627
-
1628
- def test_original_sequence_name
1629
- k = Class.new(ActiveRecord::Base)
1630
- k.table_name = "projects"
1631
- orig_name = k.sequence_name
1632
- return skip "sequences not supported by db" unless orig_name
1633
-
1634
- k = Class.new(ActiveRecord::Base)
1635
- k.table_name = "projects"
1636
- k.sequence_name = "omg"
1637
-
1638
- assert_deprecated do
1639
- assert_equal orig_name, k.original_sequence_name
1640
- end
1641
-
1642
- k = Class.new(ActiveRecord::Base)
1643
- k.table_name = "projects"
1644
- k.sequence_name = "omg"
1645
- k.sequence_name = "wtf"
1646
- assert_deprecated do
1647
- assert_equal "omg", k.original_sequence_name
1648
- end
1649
- end
1650
-
1651
- def test_sequence_name_with_abstract_class
1652
- ak = Class.new(ActiveRecord::Base)
1653
- ak.abstract_class = true
1654
- k = Class.new(ak)
1655
- k.table_name = "projects"
1656
- orig_name = k.sequence_name
1657
- return skip "sequences not supported by db" unless orig_name
1658
- assert_equal k.reset_sequence_name, orig_name
1659
- end
1660
-
1661
- def test_count_with_join
1662
- res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
1663
-
1664
- res2 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'", :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
1665
- assert_equal res, res2
1666
-
1667
- res3 = nil
1668
- assert_nothing_raised do
1669
- res3 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'",
1670
- :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
1671
- end
1672
- assert_equal res, res3
1673
-
1674
- res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
1675
- res5 = nil
1676
- assert_nothing_raised do
1677
- res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
1678
- :joins => "p, comments co",
1679
- :select => "p.id")
1680
- end
1681
-
1682
- assert_equal res4, res5
1683
-
1684
- res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
1685
- res7 = nil
1686
- assert_nothing_raised do
1687
- res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
1688
- :joins => "p, comments co",
1689
- :select => "p.id",
1690
- :distinct => true)
1691
- end
1692
- assert_equal res6, res7
1693
- end
1694
-
1695
- def test_scoped_find_conditions
1696
- scoped_developers = Developer.send(:with_scope, :find => { :conditions => 'salary > 90000' }) do
1697
- Developer.find(:all, :conditions => 'id < 5')
1698
- end
1699
- assert !scoped_developers.include?(developers(:david)) # David's salary is less than 90,000
1700
- assert_equal 3, scoped_developers.size
1701
- end
1702
-
1703
- def test_no_limit_offset
1704
- assert_nothing_raised do
1705
- Developer.find(:all, :offset => 2)
1706
- end
1707
- end
1708
-
1709
- def test_scoped_find_limit_offset
1710
- scoped_developers = Developer.send(:with_scope, :find => { :limit => 3, :offset => 2 }) do
1711
- Developer.find(:all, :order => 'id')
1712
- end
1713
- assert !scoped_developers.include?(developers(:david))
1714
- assert !scoped_developers.include?(developers(:jamis))
1715
- assert_equal 3, scoped_developers.size
1716
-
1717
- # Test without scoped find conditions to ensure we get the whole thing
1718
- developers = Developer.find(:all, :order => 'id')
1719
- assert_equal Developer.count, developers.size
1720
- end
1721
-
1722
- def test_scoped_find_order
1723
- # Test order in scope
1724
- scoped_developers = Developer.send(:with_scope, :find => { :limit => 1, :order => 'salary DESC' }) do
1725
- Developer.find(:all)
1726
- end
1727
- assert_equal 'Jamis', scoped_developers.first.name
1728
- assert scoped_developers.include?(developers(:jamis))
1729
- # Test scope without order and order in find
1730
- scoped_developers = Developer.send(:with_scope, :find => { :limit => 1 }) do
1731
- Developer.find(:all, :order => 'salary DESC')
1732
- end
1733
- # Test scope order + find order, order has priority
1734
- scoped_developers = Developer.send(:with_scope, :find => { :limit => 3, :order => 'id DESC' }) do
1735
- Developer.find(:all, :order => 'salary ASC')
1736
- end
1737
- assert scoped_developers.include?(developers(:poor_jamis))
1738
- assert ! scoped_developers.include?(developers(:david))
1739
- assert ! scoped_developers.include?(developers(:jamis))
1740
- assert_equal 3, scoped_developers.size
1741
-
1742
- # Test without scoped find conditions to ensure we get the right thing
1743
- assert ! scoped_developers.include?(Developer.find(1))
1744
- assert scoped_developers.include?(Developer.find(11))
1745
- end
1746
-
1747
- def test_scoped_find_limit_offset_including_has_many_association
1748
- topics = Topic.send(:with_scope, :find => {:limit => 1, :offset => 1, :include => :replies}) do
1749
- Topic.find(:all, :order => "topics.id")
1750
- end
1751
- assert_equal 1, topics.size
1752
- assert_equal 2, topics.first.id
1753
- end
1754
-
1755
- def test_scoped_find_order_including_has_many_association
1756
- developers = Developer.send(:with_scope, :find => { :order => 'developers.salary DESC', :include => :projects }) do
1757
- Developer.find(:all)
1758
- end
1759
- assert developers.size >= 2
1760
- for i in 1...developers.size
1761
- assert developers[i-1].salary >= developers[i].salary
1762
- end
1763
- end
1764
-
1765
- def test_scoped_find_with_group_and_having
1766
- developers = Developer.send(:with_scope, :find => { :group => 'developers.salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do
1767
- Developer.find(:all)
1768
- end
1769
- assert_equal 3, developers.size
1770
- end
1771
-
1772
- def test_find_last
1773
- last = Developer.find :last
1774
- assert_equal last, Developer.find(:first, :order => 'id desc')
1775
- end
1776
-
1777
- def test_last
1778
- assert_equal Developer.find(:first, :order => 'id desc'), Developer.last
1779
- end
1780
-
1781
- def test_all
1782
- developers = Developer.all
1783
- assert_kind_of Array, developers
1784
- assert_equal Developer.find(:all), developers
1785
- end
1786
-
1787
- def test_all_with_conditions
1788
- assert_equal Developer.find(:all, :order => 'id desc'), Developer.order('id desc').all
1789
- end
1790
-
1791
- def test_find_ordered_last
1792
- last = Developer.find :last, :order => 'developers.salary ASC'
1793
- assert_equal last, Developer.find(:all, :order => 'developers.salary ASC').last
1794
- end
1795
-
1796
- def test_find_reverse_ordered_last
1797
- last = Developer.find :last, :order => 'developers.salary DESC'
1798
- assert_equal last, Developer.find(:all, :order => 'developers.salary DESC').last
1799
- end
1800
-
1801
- def test_find_multiple_ordered_last
1802
- last = Developer.find :last, :order => 'developers.name, developers.salary DESC'
1803
- assert_equal last, Developer.find(:all, :order => 'developers.name, developers.salary DESC').last
1804
- end
1805
-
1806
- def test_find_keeps_multiple_order_values
1807
- combined = Developer.find(:all, :order => 'developers.name, developers.salary')
1808
- assert_equal combined, Developer.find(:all, :order => ['developers.name', 'developers.salary'])
1809
- end
1810
-
1811
- def test_find_keeps_multiple_group_values
1812
- combined = Developer.find(:all, :group => 'developers.name, developers.salary, developers.id, developers.created_at, developers.updated_at')
1813
- assert_equal combined, Developer.find(:all, :group => ['developers.name', 'developers.salary', 'developers.id', 'developers.created_at', 'developers.updated_at'])
1814
- end
1815
-
1816
- def test_find_symbol_ordered_last
1817
- last = Developer.find :last, :order => :salary
1818
- assert_equal last, Developer.find(:all, :order => :salary).last
1819
- end
1820
-
1821
- def test_find_scoped_ordered_last
1822
- last_developer = Developer.send(:with_scope, :find => { :order => 'developers.salary ASC' }) do
1823
- Developer.find(:last)
1824
- end
1825
- assert_equal last_developer, Developer.find(:all, :order => 'developers.salary ASC').last
1826
- end
1827
-
1828
- def test_abstract_class
1829
- assert !ActiveRecord::Base.abstract_class?
1830
- assert LoosePerson.abstract_class?
1831
- assert !LooseDescendant.abstract_class?
1832
- end
1833
-
1834
- def test_abstract_class_table_name
1835
- assert_nil AbstractCompany.table_name
1836
- end
1837
-
1838
- def test_base_class
1839
- assert_equal LoosePerson, LoosePerson.base_class
1840
- assert_equal LooseDescendant, LooseDescendant.base_class
1841
- assert_equal TightPerson, TightPerson.base_class
1842
- assert_equal TightPerson, TightDescendant.base_class
1843
-
1844
- assert_equal Post, Post.base_class
1845
- assert_equal Post, SpecialPost.base_class
1846
- assert_equal Post, StiPost.base_class
1847
- assert_equal SubStiPost, SubStiPost.base_class
1848
- end
1849
-
1850
- def test_descends_from_active_record
1851
- # Tries to call Object.abstract_class?
1852
- assert_raise(NoMethodError) do
1853
- ActiveRecord::Base.descends_from_active_record?
1854
- end
1855
-
1856
- # Abstract subclass of AR::Base.
1857
- assert LoosePerson.descends_from_active_record?
1858
-
1859
- # Concrete subclass of an abstract class.
1860
- assert LooseDescendant.descends_from_active_record?
1861
-
1862
- # Concrete subclass of AR::Base.
1863
- assert TightPerson.descends_from_active_record?
1864
-
1865
- # Concrete subclass of a concrete class but has no type column.
1866
- assert TightDescendant.descends_from_active_record?
1867
-
1868
- # Concrete subclass of AR::Base.
1869
- assert Post.descends_from_active_record?
1870
-
1871
- # Abstract subclass of a concrete class which has a type column.
1872
- # This is pathological, as you'll never have Sub < Abstract < Concrete.
1873
- assert !StiPost.descends_from_active_record?
1874
-
1875
- # Concrete subclasses an abstract class which has a type column.
1876
- assert !SubStiPost.descends_from_active_record?
1877
- end
1878
-
1879
- def test_find_on_abstract_base_class_doesnt_use_type_condition
1880
- old_class = LooseDescendant
1881
- Object.send :remove_const, :LooseDescendant
1882
-
1883
- descendant = old_class.create! :first_name => 'bob'
1884
- assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
1885
- ensure
1886
- unless Object.const_defined?(:LooseDescendant)
1887
- Object.const_set :LooseDescendant, old_class
1888
- end
1889
- end
1890
-
1891
- def test_assert_queries
1892
- query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
1893
- assert_queries(2) { 2.times { query.call } }
1894
- assert_queries 1, &query
1895
- assert_no_queries { assert true }
1896
- end
1897
-
1898
- def test_to_param_should_return_string
1899
- assert_kind_of String, Client.find(:first).to_param
1900
- end
1901
-
1902
- def test_inspect_class
1903
- assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect
1904
- assert_equal 'LoosePerson(abstract)', LoosePerson.inspect
1905
- assert_match(/^Topic\(id: integer, title: string/, Topic.inspect)
1906
- end
1907
-
1908
- def test_inspect_instance
1909
- topic = topics(:first)
1910
- assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", important: nil, approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil, created_at: "#{topic.created_at.to_s(:db)}", updated_at: "#{topic.updated_at.to_s(:db)}">), topic.inspect
1911
- end
1912
-
1913
- def test_inspect_new_instance
1914
- assert_match(/Topic id: nil/, Topic.new.inspect)
1915
- end
1916
-
1917
- def test_inspect_limited_select_instance
1918
- assert_equal %(#<Topic id: 1>), Topic.find(:first, :select => 'id', :conditions => 'id = 1').inspect
1919
- assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.find(:first, :select => 'id, title', :conditions => 'id = 1').inspect
1920
- end
1921
-
1922
- def test_inspect_class_without_table
1923
- assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect
1924
- end
1925
-
1926
- def test_attribute_for_inspect
1927
- t = topics(:first)
1928
- t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
1929
-
1930
- assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
1931
- assert_equal '"The First Topic Now Has A Title With\nNewlines And M..."', t.attribute_for_inspect(:title)
1932
- end
1933
-
1934
- def test_becomes
1935
- assert_kind_of Reply, topics(:first).becomes(Reply)
1936
- assert_equal "The First Topic", topics(:first).becomes(Reply).title
1937
- end
1938
-
1939
- def test_becomes_includes_errors
1940
- company = Company.new(:name => nil)
1941
- assert !company.valid?
1942
- original_errors = company.errors
1943
- client = company.becomes(Client)
1944
- assert_equal original_errors, client.errors
1945
- end
1946
-
1947
- def test_silence_sets_log_level_to_error_in_block
1948
- original_logger = ActiveRecord::Base.logger
1949
- log = StringIO.new
1950
- ActiveRecord::Base.logger = Logger.new(log)
1951
- ActiveRecord::Base.logger.level = Logger::DEBUG
1952
- ActiveRecord::Base.silence do
1953
- ActiveRecord::Base.logger.warn "warn"
1954
- ActiveRecord::Base.logger.error "error"
1955
- end
1956
- assert_equal "error\n", log.string
1957
- ensure
1958
- ActiveRecord::Base.logger = original_logger
1959
- end
1960
-
1961
- def test_silence_sets_log_level_back_to_level_before_yield
1962
- original_logger = ActiveRecord::Base.logger
1963
- log = StringIO.new
1964
- ActiveRecord::Base.logger = Logger.new(log)
1965
- ActiveRecord::Base.logger.level = Logger::WARN
1966
- ActiveRecord::Base.silence do
1967
- end
1968
- assert_equal Logger::WARN, ActiveRecord::Base.logger.level
1969
- ensure
1970
- ActiveRecord::Base.logger = original_logger
1971
- end
1972
-
1973
- def test_benchmark_with_log_level
1974
- original_logger = ActiveRecord::Base.logger
1975
- log = StringIO.new
1976
- ActiveRecord::Base.logger = Logger.new(log)
1977
- ActiveRecord::Base.logger.level = Logger::WARN
1978
- ActiveRecord::Base.benchmark("Debug Topic Count", :level => :debug) { Topic.count }
1979
- ActiveRecord::Base.benchmark("Warn Topic Count", :level => :warn) { Topic.count }
1980
- ActiveRecord::Base.benchmark("Error Topic Count", :level => :error) { Topic.count }
1981
- assert_no_match(/Debug Topic Count/, log.string)
1982
- assert_match(/Warn Topic Count/, log.string)
1983
- assert_match(/Error Topic Count/, log.string)
1984
- ensure
1985
- ActiveRecord::Base.logger = original_logger
1986
- end
1987
-
1988
- def test_benchmark_with_use_silence
1989
- original_logger = ActiveRecord::Base.logger
1990
- log = StringIO.new
1991
- ActiveRecord::Base.logger = Logger.new(log)
1992
- assert_deprecated do
1993
- ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => true) { ActiveRecord::Base.logger.debug "Loud" }
1994
- end
1995
- ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" }
1996
- assert_no_match(/Loud/, log.string)
1997
- assert_match(/Quiet/, log.string)
1998
- ensure
1999
- ActiveRecord::Base.logger = original_logger
2000
- end
2001
-
2002
- def test_compute_type_success
2003
- assert_equal Author, ActiveRecord::Base.send(:compute_type, 'Author')
2004
- end
2005
-
2006
- def test_compute_type_nonexistent_constant
2007
- assert_raises NameError do
2008
- ActiveRecord::Base.send :compute_type, 'NonexistentModel'
2009
- end
2010
- end
2011
-
2012
- def test_compute_type_no_method_error
2013
- ActiveSupport::Dependencies.stubs(:constantize).raises(NoMethodError)
2014
- assert_raises NoMethodError do
2015
- ActiveRecord::Base.send :compute_type, 'InvalidModel'
2016
- end
2017
- end
2018
-
2019
- def test_compute_type_argument_error
2020
- ActiveSupport::Dependencies.stubs(:constantize).raises(ArgumentError)
2021
- assert_raises ArgumentError do
2022
- ActiveRecord::Base.send :compute_type, 'InvalidModel'
2023
- end
2024
- end
2025
-
2026
- def test_clear_cache!
2027
- # preheat cache
2028
- c1 = Post.connection.schema_cache.columns['posts']
2029
- ActiveRecord::Base.clear_cache!
2030
- c2 = Post.connection.schema_cache.columns['posts']
2031
- assert_not_equal c1, c2
2032
- end
2033
-
2034
- def test_current_scope_is_reset
2035
- Object.const_set :UnloadablePost, Class.new(ActiveRecord::Base)
2036
- UnloadablePost.send(:current_scope=, UnloadablePost.scoped)
2037
-
2038
- UnloadablePost.unloadable
2039
- assert_not_nil Thread.current[:UnloadablePost_current_scope]
2040
- ActiveSupport::Dependencies.remove_unloadable_constants!
2041
- assert_nil Thread.current[:UnloadablePost_current_scope]
2042
- ensure
2043
- Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
2044
- end
2045
-
2046
- def test_marshal_round_trip
2047
- if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
2048
- return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
2049
- "to be a Ruby bug.")
2050
- end
2051
-
2052
- expected = posts(:welcome)
2053
- marshalled = Marshal.dump(expected)
2054
- actual = Marshal.load(marshalled)
2055
-
2056
- assert_equal expected.attributes, actual.attributes
2057
- end
2058
-
2059
- def test_marshal_new_record_round_trip
2060
- if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
2061
- return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
2062
- "to be a Ruby bug.")
2063
- end
2064
-
2065
- marshalled = Marshal.dump(Post.new)
2066
- post = Marshal.load(marshalled)
2067
-
2068
- assert post.new_record?, "should be a new record"
2069
- end
2070
-
2071
- def test_marshalling_with_associations
2072
- if ENV['TRAVIS'] && RUBY_VERSION == "1.8.7"
2073
- return skip("Marshalling tests disabled for Ruby 1.8.7 on Travis CI due to what appears " \
2074
- "to be a Ruby bug.")
2075
- end
2076
-
2077
- post = Post.new
2078
- post.comments.build
2079
-
2080
- marshalled = Marshal.dump(post)
2081
- post = Marshal.load(marshalled)
2082
-
2083
- assert_equal 1, post.comments.length
2084
- end
2085
-
2086
- def test_attribute_names
2087
- assert_equal ["id", "type", "ruby_type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id"],
2088
- Company.attribute_names
2089
- end
2090
-
2091
- def test_attribute_names_on_table_not_exists
2092
- assert_equal [], NonExistentTable.attribute_names
2093
- end
2094
-
2095
- def test_attribtue_names_on_abstract_class
2096
- assert_equal [], AbstractCompany.attribute_names
2097
- end
2098
-
2099
- def test_cache_key_for_existing_record_is_not_timezone_dependent
2100
- ActiveRecord::Base.time_zone_aware_attributes = true
2101
-
2102
- Time.zone = "UTC"
2103
- utc_key = Developer.first.cache_key
2104
-
2105
- Time.zone = "EST"
2106
- est_key = Developer.first.cache_key
2107
-
2108
- assert_equal utc_key, est_key
2109
- ensure
2110
- ActiveRecord::Base.time_zone_aware_attributes = false
2111
- end
2112
-
2113
- def test_cache_key_format_for_existing_record_with_updated_at
2114
- dev = Developer.first
2115
- assert_equal "developers/#{dev.id}-#{dev.updated_at.utc.to_s(:number)}", dev.cache_key
2116
- end
2117
-
2118
- def test_cache_key_format_for_existing_record_with_nil_updated_at
2119
- dev = Developer.first
2120
- dev.update_attribute(:updated_at, nil)
2121
- assert_match(/\/#{dev.id}$/, dev.cache_key)
2122
- end
2123
-
2124
- def test_uniq_delegates_to_scoped
2125
- scope = stub
2126
- Bird.stubs(:scoped).returns(mock(:uniq => scope))
2127
- assert_equal scope, Bird.uniq
2128
- end
2129
-
2130
- def test_table_name_with_2_abstract_subclasses
2131
- assert_equal "photos", Photo.table_name
2132
- end
2133
- end
1
+ # encoding: utf-8
2
+
3
+ require "cases/helper"
4
+ require 'active_support/concurrency/latch'
5
+ require 'models/post'
6
+ require 'models/author'
7
+ require 'models/topic'
8
+ require 'models/reply'
9
+ require 'models/category'
10
+ require 'models/company'
11
+ require 'models/customer'
12
+ require 'models/developer'
13
+ require 'models/computer'
14
+ require 'models/project'
15
+ require 'models/default'
16
+ require 'models/auto_id'
17
+ require 'models/boolean'
18
+ require 'models/column_name'
19
+ require 'models/subscriber'
20
+ require 'models/keyboard'
21
+ require 'models/comment'
22
+ require 'models/minimalistic'
23
+ require 'models/warehouse_thing'
24
+ require 'models/parrot'
25
+ require 'models/person'
26
+ require 'models/edge'
27
+ require 'models/joke'
28
+ require 'models/bird'
29
+ require 'models/car'
30
+ require 'models/bulb'
31
+ require 'rexml/document'
32
+
33
+ class FirstAbstractClass < ActiveRecord::Base
34
+ self.abstract_class = true
35
+ end
36
+ class SecondAbstractClass < FirstAbstractClass
37
+ self.abstract_class = true
38
+ end
39
+ class Photo < SecondAbstractClass; end
40
+ class Category < ActiveRecord::Base; end
41
+ class Categorization < ActiveRecord::Base; end
42
+ class Smarts < ActiveRecord::Base; end
43
+ class CreditCard < ActiveRecord::Base
44
+ class PinNumber < ActiveRecord::Base
45
+ class CvvCode < ActiveRecord::Base; end
46
+ class SubCvvCode < CvvCode; end
47
+ end
48
+ class SubPinNumber < PinNumber; end
49
+ class Brand < Category; end
50
+ end
51
+ class MasterCreditCard < ActiveRecord::Base; end
52
+ class Post < ActiveRecord::Base; end
53
+ class Computer < ActiveRecord::Base; end
54
+ class NonExistentTable < ActiveRecord::Base; end
55
+ class TestOracleDefault < ActiveRecord::Base; end
56
+
57
+ class ReadonlyTitlePost < Post
58
+ attr_readonly :title
59
+ end
60
+
61
+ class Weird < ActiveRecord::Base; end
62
+
63
+ class Boolean < ActiveRecord::Base
64
+ def has_fun
65
+ super
66
+ end
67
+ end
68
+
69
+ class LintTest < ActiveRecord::TestCase
70
+ include ActiveModel::Lint::Tests
71
+
72
+ class LintModel < ActiveRecord::Base; end
73
+
74
+ def setup
75
+ @model = LintModel.new
76
+ end
77
+ end
78
+
79
+ class BasicsTest < ActiveRecord::TestCase
80
+ fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse_things', :authors, :categorizations, :categories, :posts, :author_addresses
81
+
82
+ def test_column_names_are_escaped
83
+ conn = ActiveRecord::Base.connection
84
+ classname = conn.class.name[/[^:]*$/]
85
+ badchar = {
86
+ 'SQLite3Adapter' => '"',
87
+ 'MysqlAdapter' => '`',
88
+ 'Mysql2Adapter' => '`',
89
+ 'PostgreSQLAdapter' => '"',
90
+ 'OracleAdapter' => '"',
91
+ 'IBM_DBAdapter' => '"',
92
+ }.fetch(classname) {
93
+ raise "need a bad char for #{classname}"
94
+ }
95
+
96
+ quoted = conn.quote_column_name "foo#{badchar}bar"
97
+ if current_adapter?(:OracleAdapter)
98
+ # Oracle does not allow double quotes in table and column names at all
99
+ # therefore quoting removes them
100
+ assert_equal("#{badchar}foobar#{badchar}", quoted)
101
+ elsif current_adapter?(:IBM_DBAdapter)
102
+ assert_equal("foo#{badchar}bar", quoted)
103
+ else
104
+ assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted)
105
+ end
106
+ end
107
+
108
+ def test_columns_should_obey_set_primary_key
109
+ pk = Subscriber.columns_hash[Subscriber.primary_key]
110
+ assert_equal 'nick', pk.name, 'nick should be primary key'
111
+ end
112
+
113
+ def test_primary_key_with_no_id
114
+ assert_nil Edge.primary_key
115
+ end
116
+
117
+ unless current_adapter?(:PostgreSQLAdapter, :OracleAdapter, :SQLServerAdapter, :IBM_DBAdapter)
118
+ def test_limit_with_comma
119
+ assert Topic.limit("1,2").to_a
120
+ end
121
+ end
122
+
123
+ def test_limit_without_comma
124
+ assert_equal 1, Topic.limit("1").to_a.length
125
+ assert_equal 1, Topic.limit(1).to_a.length
126
+ end
127
+
128
+ def test_limit_should_take_value_from_latest_limit
129
+ assert_equal 1, Topic.limit(2).limit(1).to_a.length
130
+ end
131
+
132
+ def test_invalid_limit
133
+ assert_raises(ArgumentError) do
134
+ Topic.limit("asdfadf").to_a
135
+ end
136
+ end
137
+
138
+ def test_limit_should_sanitize_sql_injection_for_limit_without_commas
139
+ assert_raises(ArgumentError) do
140
+ Topic.limit("1 select * from schema").to_a
141
+ end
142
+ end
143
+
144
+ def test_limit_should_sanitize_sql_injection_for_limit_with_commas
145
+ assert_raises(ArgumentError) do
146
+ Topic.limit("1, 7 procedure help()").to_a
147
+ end
148
+ end
149
+
150
+ unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :IBM_DBAdapter)
151
+ def test_limit_should_allow_sql_literal
152
+ assert_equal 1, Topic.limit(Arel.sql('2-1')).to_a.length
153
+ end
154
+ end
155
+
156
+ def test_select_symbol
157
+ topic_ids = Topic.select(:id).map(&:id).sort
158
+ assert_equal Topic.pluck(:id).sort, topic_ids
159
+ end
160
+
161
+ def test_table_exists
162
+ assert !NonExistentTable.table_exists?
163
+ assert Topic.table_exists?
164
+ end
165
+
166
+ def test_preserving_date_objects
167
+ # Oracle enhanced adapter allows to define Date attributes in model class (see topic.rb)
168
+ assert_kind_of(
169
+ Date, Topic.find(1).last_read,
170
+ "The last_read attribute should be of the Date class"
171
+ )
172
+ end
173
+
174
+ def test_previously_changed
175
+ topic = Topic.first
176
+ topic.title = '<3<3<3'
177
+ assert_equal({}, topic.previous_changes)
178
+
179
+ topic.save!
180
+ expected = ["The First Topic", "<3<3<3"]
181
+ assert_equal(expected, topic.previous_changes['title'])
182
+ end
183
+
184
+ def test_previously_changed_dup
185
+ topic = Topic.first
186
+ topic.title = '<3<3<3'
187
+ topic.save!
188
+
189
+ t2 = topic.dup
190
+
191
+ assert_equal(topic.previous_changes, t2.previous_changes)
192
+
193
+ topic.title = "lolwut"
194
+ topic.save!
195
+
196
+ assert_not_equal(topic.previous_changes, t2.previous_changes)
197
+ end
198
+
199
+ def test_preserving_time_objects
200
+ assert_kind_of(
201
+ Time, Topic.find(1).bonus_time,
202
+ "The bonus_time attribute should be of the Time class"
203
+ )
204
+
205
+ assert_kind_of(
206
+ Time, Topic.find(1).written_on,
207
+ "The written_on attribute should be of the Time class"
208
+ )
209
+
210
+ # For adapters which support microsecond resolution.
211
+ if current_adapter?(:PostgreSQLAdapter, :SQLite3Adapter) || mysql_56?
212
+ assert_equal 11, Topic.find(1).written_on.sec
213
+ assert_equal 223300, Topic.find(1).written_on.usec
214
+ assert_equal 9900, Topic.find(2).written_on.usec
215
+ assert_equal 129346, Topic.find(3).written_on.usec
216
+ end
217
+ end
218
+
219
+ def test_preserving_time_objects_with_local_time_conversion_to_default_timezone_utc
220
+ with_env_tz 'America/New_York' do
221
+ with_timezone_config default: :utc do
222
+ time = Time.local(2000)
223
+ topic = Topic.create('written_on' => time)
224
+ saved_time = Topic.find(topic.id).reload.written_on
225
+ assert_equal time, saved_time
226
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "EST"], time.to_a
227
+ assert_equal [0, 0, 5, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
228
+ end
229
+ end
230
+ end
231
+
232
+ def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_utc
233
+ with_env_tz 'America/New_York' do
234
+ with_timezone_config default: :utc do
235
+ Time.use_zone 'Central Time (US & Canada)' do
236
+ time = Time.zone.local(2000)
237
+ topic = Topic.create('written_on' => time)
238
+ saved_time = Topic.find(topic.id).reload.written_on
239
+ assert_equal time, saved_time
240
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
241
+ assert_equal [0, 0, 6, 1, 1, 2000, 6, 1, false, "UTC"], saved_time.to_a
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ def test_preserving_time_objects_with_utc_time_conversion_to_default_timezone_local
248
+ with_env_tz 'America/New_York' do
249
+ with_timezone_config default: :local do
250
+ time = Time.utc(2000)
251
+ topic = Topic.create('written_on' => time)
252
+ saved_time = Topic.find(topic.id).reload.written_on
253
+ assert_equal time, saved_time
254
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "UTC"], time.to_a
255
+ assert_equal [0, 0, 19, 31, 12, 1999, 5, 365, false, "EST"], saved_time.to_a
256
+ end
257
+ end
258
+ end
259
+
260
+ def test_preserving_time_objects_with_time_with_zone_conversion_to_default_timezone_local
261
+ with_env_tz 'America/New_York' do
262
+ with_timezone_config default: :local do
263
+ Time.use_zone 'Central Time (US & Canada)' do
264
+ time = Time.zone.local(2000)
265
+ topic = Topic.create('written_on' => time)
266
+ saved_time = Topic.find(topic.id).reload.written_on
267
+ assert_equal time, saved_time
268
+ assert_equal [0, 0, 0, 1, 1, 2000, 6, 1, false, "CST"], time.to_a
269
+ assert_equal [0, 0, 1, 1, 1, 2000, 6, 1, false, "EST"], saved_time.to_a
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ def test_custom_mutator
276
+ topic = Topic.find(1)
277
+ # This mutator is protected in the class definition
278
+ topic.send(:approved=, true)
279
+ assert topic.instance_variable_get("@custom_approved")
280
+ end
281
+
282
+ def test_initialize_with_attributes
283
+ topic = Topic.new({
284
+ "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23"
285
+ })
286
+
287
+ assert_equal("initialized from attributes", topic.title)
288
+ end
289
+
290
+ def test_initialize_with_invalid_attribute
291
+ Topic.new({ "title" => "test",
292
+ "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
293
+ rescue ActiveRecord::MultiparameterAssignmentErrors => ex
294
+ assert_equal(1, ex.errors.size)
295
+ assert_equal("last_read", ex.errors[0].attribute)
296
+ end
297
+
298
+ def test_create_after_initialize_without_block
299
+ cb = CustomBulb.create(:name => 'Dude')
300
+ assert_equal('Dude', cb.name)
301
+ assert_equal(true, cb.frickinawesome)
302
+ end
303
+
304
+ def test_create_after_initialize_with_block
305
+ cb = CustomBulb.create {|c| c.name = 'Dude' }
306
+ assert_equal('Dude', cb.name)
307
+ assert_equal(true, cb.frickinawesome)
308
+ end
309
+
310
+ def test_create_after_initialize_with_array_param
311
+ cbs = CustomBulb.create([{ name: 'Dude' }, { name: 'Bob' }])
312
+ assert_equal 'Dude', cbs[0].name
313
+ assert_equal 'Bob', cbs[1].name
314
+ assert cbs[0].frickinawesome
315
+ assert !cbs[1].frickinawesome
316
+ end
317
+
318
+ def test_load
319
+ topics = Topic.all.merge!(:order => 'id').to_a
320
+ assert_equal(5, topics.size)
321
+ assert_equal(topics(:first).title, topics.first.title)
322
+ end
323
+
324
+ def test_load_with_condition
325
+ topics = Topic.all.merge!(:where => "author_name = 'Mary'").to_a
326
+
327
+ assert_equal(1, topics.size)
328
+ assert_equal(topics(:second).title, topics.first.title)
329
+ end
330
+
331
+ GUESSED_CLASSES = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]
332
+
333
+ def test_table_name_guesses
334
+ assert_equal "topics", Topic.table_name
335
+
336
+ assert_equal "categories", Category.table_name
337
+ assert_equal "smarts", Smarts.table_name
338
+ assert_equal "credit_cards", CreditCard.table_name
339
+ assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
340
+ assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
341
+ assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
342
+ assert_equal "categories", CreditCard::Brand.table_name
343
+ assert_equal "master_credit_cards", MasterCreditCard.table_name
344
+ ensure
345
+ GUESSED_CLASSES.each(&:reset_table_name)
346
+ end
347
+
348
+ def test_singular_table_name_guesses
349
+ ActiveRecord::Base.pluralize_table_names = false
350
+ GUESSED_CLASSES.each(&:reset_table_name)
351
+
352
+ assert_equal "category", Category.table_name
353
+ assert_equal "smarts", Smarts.table_name
354
+ assert_equal "credit_card", CreditCard.table_name
355
+ assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
356
+ assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
357
+ assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
358
+ assert_equal "category", CreditCard::Brand.table_name
359
+ assert_equal "master_credit_card", MasterCreditCard.table_name
360
+ ensure
361
+ ActiveRecord::Base.pluralize_table_names = true
362
+ GUESSED_CLASSES.each(&:reset_table_name)
363
+ end
364
+
365
+ def test_table_name_guesses_with_prefixes_and_suffixes
366
+ ActiveRecord::Base.table_name_prefix = "test_"
367
+ Category.reset_table_name
368
+ assert_equal "test_categories", Category.table_name
369
+ ActiveRecord::Base.table_name_suffix = "_test"
370
+ Category.reset_table_name
371
+ assert_equal "test_categories_test", Category.table_name
372
+ ActiveRecord::Base.table_name_prefix = ""
373
+ Category.reset_table_name
374
+ assert_equal "categories_test", Category.table_name
375
+ ActiveRecord::Base.table_name_suffix = ""
376
+ Category.reset_table_name
377
+ assert_equal "categories", Category.table_name
378
+ ensure
379
+ ActiveRecord::Base.table_name_prefix = ""
380
+ ActiveRecord::Base.table_name_suffix = ""
381
+ GUESSED_CLASSES.each(&:reset_table_name)
382
+ end
383
+
384
+ def test_singular_table_name_guesses_with_prefixes_and_suffixes
385
+ ActiveRecord::Base.pluralize_table_names = false
386
+
387
+ ActiveRecord::Base.table_name_prefix = "test_"
388
+ Category.reset_table_name
389
+ assert_equal "test_category", Category.table_name
390
+ ActiveRecord::Base.table_name_suffix = "_test"
391
+ Category.reset_table_name
392
+ assert_equal "test_category_test", Category.table_name
393
+ ActiveRecord::Base.table_name_prefix = ""
394
+ Category.reset_table_name
395
+ assert_equal "category_test", Category.table_name
396
+ ActiveRecord::Base.table_name_suffix = ""
397
+ Category.reset_table_name
398
+ assert_equal "category", Category.table_name
399
+ ensure
400
+ ActiveRecord::Base.pluralize_table_names = true
401
+ ActiveRecord::Base.table_name_prefix = ""
402
+ ActiveRecord::Base.table_name_suffix = ""
403
+ GUESSED_CLASSES.each(&:reset_table_name)
404
+ end
405
+
406
+ def test_table_name_guesses_with_inherited_prefixes_and_suffixes
407
+ GUESSED_CLASSES.each(&:reset_table_name)
408
+
409
+ CreditCard.table_name_prefix = "test_"
410
+ CreditCard.reset_table_name
411
+ Category.reset_table_name
412
+ assert_equal "test_credit_cards", CreditCard.table_name
413
+ assert_equal "categories", Category.table_name
414
+ CreditCard.table_name_suffix = "_test"
415
+ CreditCard.reset_table_name
416
+ Category.reset_table_name
417
+ assert_equal "test_credit_cards_test", CreditCard.table_name
418
+ assert_equal "categories", Category.table_name
419
+ CreditCard.table_name_prefix = ""
420
+ CreditCard.reset_table_name
421
+ Category.reset_table_name
422
+ assert_equal "credit_cards_test", CreditCard.table_name
423
+ assert_equal "categories", Category.table_name
424
+ CreditCard.table_name_suffix = ""
425
+ CreditCard.reset_table_name
426
+ Category.reset_table_name
427
+ assert_equal "credit_cards", CreditCard.table_name
428
+ assert_equal "categories", Category.table_name
429
+ ensure
430
+ CreditCard.table_name_prefix = ""
431
+ CreditCard.table_name_suffix = ""
432
+ GUESSED_CLASSES.each(&:reset_table_name)
433
+ end
434
+
435
+ def test_singular_table_name_guesses_for_individual_table
436
+ Post.pluralize_table_names = false
437
+ Post.reset_table_name
438
+ assert_equal "post", Post.table_name
439
+ assert_equal "categories", Category.table_name
440
+ ensure
441
+ Post.pluralize_table_names = true
442
+ Post.reset_table_name
443
+ end
444
+
445
+ if current_adapter?(:MysqlAdapter, :Mysql2Adapter)
446
+ def test_update_all_with_order_and_limit
447
+ assert_equal 1, Topic.limit(1).order('id DESC').update_all(:content => 'bulk updated!')
448
+ end
449
+ end
450
+
451
+ def test_null_fields
452
+ assert_nil Topic.find(1).parent_id
453
+ assert_nil Topic.create("title" => "Hey you").parent_id
454
+ end
455
+
456
+ def test_default_values
457
+ topic = Topic.new
458
+ assert topic.approved?
459
+ assert_nil topic.written_on
460
+ assert_nil topic.bonus_time
461
+ assert_nil topic.last_read
462
+
463
+ topic.save
464
+
465
+ topic = Topic.find(topic.id)
466
+ assert topic.approved?
467
+ assert_nil topic.last_read
468
+
469
+ # Oracle has some funky default handling, so it requires a bit of
470
+ # extra testing. See ticket #2788.
471
+ if current_adapter?(:OracleAdapter)
472
+ test = TestOracleDefault.new
473
+ assert_equal "X", test.test_char
474
+ assert_equal "hello", test.test_string
475
+ assert_equal 3, test.test_int
476
+ end
477
+ end
478
+
479
+ # Oracle does not have a TIME datatype.
480
+ unless current_adapter?(:OracleAdapter)
481
+ def test_utc_as_time_zone
482
+ with_timezone_config default: :utc do
483
+ attributes = { "bonus_time" => "5:42:00AM" }
484
+ topic = Topic.find(1)
485
+ topic.attributes = attributes
486
+ assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
487
+ end
488
+ end
489
+
490
+ def test_utc_as_time_zone_and_new
491
+ with_timezone_config default: :utc do
492
+ attributes = { "bonus_time(1i)"=>"2000",
493
+ "bonus_time(2i)"=>"1",
494
+ "bonus_time(3i)"=>"1",
495
+ "bonus_time(4i)"=>"10",
496
+ "bonus_time(5i)"=>"35",
497
+ "bonus_time(6i)"=>"50" }
498
+ topic = Topic.new(attributes)
499
+ assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
500
+ end
501
+ end
502
+ end
503
+
504
+ def test_default_values_on_empty_strings
505
+ topic = Topic.new
506
+ topic.approved = nil
507
+ topic.last_read = nil
508
+
509
+ topic.save
510
+
511
+ topic = Topic.find(topic.id)
512
+ assert_nil topic.last_read
513
+
514
+ assert_nil topic.approved
515
+ end
516
+
517
+ def test_equality
518
+ assert_equal Topic.find(1), Topic.find(2).topic
519
+ end
520
+
521
+ def test_find_by_slug
522
+ assert_equal Topic.find('1-meowmeow'), Topic.find(1)
523
+ end
524
+
525
+ def test_find_by_slug_with_array
526
+ assert_equal Topic.find(['1-meowmeow', '2-hello']), Topic.find([1, 2])
527
+ end
528
+
529
+ def test_find_by_slug_with_range
530
+ assert_equal Topic.where(id: '1-meowmeow'..'2-hello'), Topic.where(id: 1..2)
531
+ end
532
+
533
+ def test_equality_of_new_records
534
+ assert_not_equal Topic.new, Topic.new
535
+ assert_equal false, Topic.new == Topic.new
536
+ end
537
+
538
+ def test_equality_of_destroyed_records
539
+ topic_1 = Topic.new(:title => 'test_1')
540
+ topic_1.save
541
+ topic_2 = Topic.find(topic_1.id)
542
+ topic_1.destroy
543
+ assert_equal topic_1, topic_2
544
+ assert_equal topic_2, topic_1
545
+ end
546
+
547
+ def test_equality_with_blank_ids
548
+ one = Subscriber.new(:id => '')
549
+ two = Subscriber.new(:id => '')
550
+ assert_equal one, two
551
+ end
552
+
553
+ def test_equality_of_relation_and_collection_proxy
554
+ car = Car.create!
555
+ car.bulbs.build
556
+ car.save
557
+
558
+ assert car.bulbs == Bulb.where(car_id: car.id), 'CollectionProxy should be comparable with Relation'
559
+ assert Bulb.where(car_id: car.id) == car.bulbs, 'Relation should be comparable with CollectionProxy'
560
+ end
561
+
562
+ def test_equality_of_relation_and_array
563
+ car = Car.create!
564
+ car.bulbs.build
565
+ car.save
566
+
567
+ assert Bulb.where(car_id: car.id) == car.bulbs.to_a, 'Relation should be comparable with Array'
568
+ end
569
+
570
+ def test_equality_of_relation_and_association_relation
571
+ car = Car.create!
572
+ car.bulbs.build
573
+ car.save
574
+
575
+ assert_equal Bulb.where(car_id: car.id), car.bulbs.includes(:car), 'Relation should be comparable with AssociationRelation'
576
+ assert_equal car.bulbs.includes(:car), Bulb.where(car_id: car.id), 'AssociationRelation should be comparable with Relation'
577
+ end
578
+
579
+ def test_equality_of_collection_proxy_and_association_relation
580
+ car = Car.create!
581
+ car.bulbs.build
582
+ car.save
583
+
584
+ assert_equal car.bulbs, car.bulbs.includes(:car), 'CollectionProxy should be comparable with AssociationRelation'
585
+ assert_equal car.bulbs.includes(:car), car.bulbs, 'AssociationRelation should be comparable with CollectionProxy'
586
+ end
587
+
588
+ def test_hashing
589
+ assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
590
+ end
591
+
592
+ def test_successful_comparison_of_like_class_records
593
+ topic_1 = Topic.create!
594
+ topic_2 = Topic.create!
595
+
596
+ assert_equal [topic_2, topic_1].sort, [topic_1, topic_2]
597
+ end
598
+
599
+ def test_failed_comparison_of_unlike_class_records
600
+ assert_raises ArgumentError do
601
+ [ topics(:first), posts(:welcome) ].sort
602
+ end
603
+ end
604
+
605
+ def test_create_without_prepared_statement
606
+ topic = Topic.connection.unprepared_statement do
607
+ Topic.create(:title => 'foo')
608
+ end
609
+
610
+ assert_equal topic, Topic.find(topic.id)
611
+ end
612
+
613
+ def test_destroy_without_prepared_statement
614
+ topic = Topic.create(title: 'foo')
615
+ Topic.connection.unprepared_statement do
616
+ Topic.find(topic.id).destroy
617
+ end
618
+
619
+ assert_equal nil, Topic.find_by_id(topic.id)
620
+ end
621
+
622
+ def test_comparison_with_different_objects
623
+ topic = Topic.create
624
+ category = Category.create(:name => "comparison")
625
+ assert_nil topic <=> category
626
+ end
627
+
628
+ def test_comparison_with_different_objects_in_array
629
+ topic = Topic.create
630
+ assert_raises(ArgumentError) do
631
+ [1, topic].sort
632
+ end
633
+ end
634
+
635
+ def test_readonly_attributes
636
+ assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes
637
+
638
+ post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable")
639
+ post.reload
640
+ assert_equal "cannot change this", post.title
641
+
642
+ post.update(title: "try to change", body: "changed")
643
+ post.reload
644
+ assert_equal "cannot change this", post.title
645
+ assert_equal "changed", post.body
646
+ end
647
+
648
+ def test_unicode_column_name
649
+ Weird.reset_column_information
650
+ weird = Weird.create(:なまえ => 'たこ焼き仮面')
651
+ assert_equal 'たこ焼き仮面', weird.なまえ
652
+ end
653
+
654
+ unless current_adapter?(:PostgreSQLAdapter)
655
+ def test_respect_internal_encoding
656
+ old_default_internal = Encoding.default_internal
657
+ silence_warnings { Encoding.default_internal = "EUC-JP" }
658
+
659
+ Weird.reset_column_information
660
+
661
+ assert_equal ["EUC-JP"], Weird.columns.map {|c| c.name.encoding.name }.uniq
662
+ ensure
663
+ silence_warnings { Encoding.default_internal = old_default_internal }
664
+ Weird.reset_column_information
665
+ end
666
+ end
667
+
668
+ def test_non_valid_identifier_column_name
669
+ weird = Weird.create('a$b' => 'value')
670
+ weird.reload
671
+ assert_equal 'value', weird.send('a$b')
672
+ assert_equal 'value', weird.read_attribute('a$b')
673
+
674
+ weird.update_columns('a$b' => 'value2')
675
+ weird.reload
676
+ assert_equal 'value2', weird.send('a$b')
677
+ assert_equal 'value2', weird.read_attribute('a$b')
678
+ end
679
+
680
+ def test_group_weirds_by_from
681
+ Weird.create('a$b' => 'value', :from => 'aaron')
682
+ count = Weird.group(Weird.arel_table[:from]).count
683
+ assert_equal 1, count['aaron']
684
+ end
685
+
686
+ def test_attributes_on_dummy_time
687
+ # Oracle does not have a TIME datatype.
688
+ return true if current_adapter?(:OracleAdapter)
689
+
690
+ with_timezone_config default: :local do
691
+ attributes = {
692
+ "bonus_time" => "5:42:00AM"
693
+ }
694
+ topic = Topic.find(1)
695
+ topic.attributes = attributes
696
+ assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
697
+ end
698
+ end
699
+
700
+ def test_attributes_on_dummy_time_with_invalid_time
701
+ # Oracle does not have a TIME datatype.
702
+ return true if current_adapter?(:OracleAdapter)
703
+
704
+ attributes = {
705
+ "bonus_time" => "not a time"
706
+ }
707
+ topic = Topic.find(1)
708
+ topic.attributes = attributes
709
+ assert_nil topic.bonus_time
710
+ end
711
+
712
+ def test_boolean
713
+ b_nil = Boolean.create({ "value" => nil })
714
+ nil_id = b_nil.id
715
+ b_false = Boolean.create({ "value" => false })
716
+ false_id = b_false.id
717
+ b_true = Boolean.create({ "value" => true })
718
+ true_id = b_true.id
719
+
720
+ b_nil = Boolean.find(nil_id)
721
+ assert_nil b_nil.value
722
+ b_false = Boolean.find(false_id)
723
+ assert !b_false.value?
724
+ b_true = Boolean.find(true_id)
725
+ assert b_true.value?
726
+ end
727
+
728
+ def test_boolean_without_questionmark
729
+ b_true = Boolean.create({ "value" => true })
730
+ true_id = b_true.id
731
+
732
+ subclass = Class.new(Boolean).find true_id
733
+ superclass = Boolean.find true_id
734
+
735
+ assert_equal superclass.read_attribute(:has_fun), subclass.read_attribute(:has_fun)
736
+ end
737
+
738
+ def test_boolean_cast_from_string
739
+ b_blank = Boolean.create({ "value" => "" })
740
+ blank_id = b_blank.id
741
+ b_false = Boolean.create({ "value" => "0" })
742
+ false_id = b_false.id
743
+ b_true = Boolean.create({ "value" => "1" })
744
+ true_id = b_true.id
745
+
746
+ b_blank = Boolean.find(blank_id)
747
+ assert_nil b_blank.value
748
+ b_false = Boolean.find(false_id)
749
+ assert !b_false.value?
750
+ b_true = Boolean.find(true_id)
751
+ assert b_true.value?
752
+ end
753
+
754
+ def test_new_record_returns_boolean
755
+ assert_equal false, Topic.new.persisted?
756
+ assert_equal true, Topic.find(1).persisted?
757
+ end
758
+
759
+ def test_dup
760
+ topic = Topic.find(1)
761
+ duped_topic = nil
762
+ assert_nothing_raised { duped_topic = topic.dup }
763
+ assert_equal topic.title, duped_topic.title
764
+ assert !duped_topic.persisted?
765
+
766
+ # test if the attributes have been duped
767
+ topic.title = "a"
768
+ duped_topic.title = "b"
769
+ assert_equal "a", topic.title
770
+ assert_equal "b", duped_topic.title
771
+
772
+ # test if the attribute values have been duped
773
+ duped_topic = topic.dup
774
+ duped_topic.title.replace "c"
775
+ assert_equal "a", topic.title
776
+
777
+ # test if attributes set as part of after_initialize are duped correctly
778
+ assert_equal topic.author_email_address, duped_topic.author_email_address
779
+
780
+ # test if saved clone object differs from original
781
+ duped_topic.save
782
+ assert duped_topic.persisted?
783
+ assert_not_equal duped_topic.id, topic.id
784
+
785
+ duped_topic.reload
786
+ assert_equal("c", duped_topic.title)
787
+ end
788
+
789
+ DeveloperSalary = Struct.new(:amount)
790
+ def test_dup_with_aggregate_of_same_name_as_attribute
791
+ developer_with_aggregate = Class.new(ActiveRecord::Base) do
792
+ self.table_name = 'developers'
793
+ composed_of :salary, :class_name => 'BasicsTest::DeveloperSalary', :mapping => [%w(salary amount)]
794
+ end
795
+
796
+ dev = developer_with_aggregate.find(1)
797
+ assert_kind_of DeveloperSalary, dev.salary
798
+
799
+ dup = nil
800
+ assert_nothing_raised { dup = dev.dup }
801
+ assert_kind_of DeveloperSalary, dup.salary
802
+ assert_equal dev.salary.amount, dup.salary.amount
803
+ assert !dup.persisted?
804
+
805
+ # test if the attributes have been dupd
806
+ original_amount = dup.salary.amount
807
+ dev.salary.amount = 1
808
+ assert_equal original_amount, dup.salary.amount
809
+
810
+ assert dup.save
811
+ assert dup.persisted?
812
+ assert_not_equal dup.id, dev.id
813
+ end
814
+
815
+ def test_dup_does_not_copy_associations
816
+ author = authors(:david)
817
+ assert_not_equal [], author.posts
818
+ author.send(:clear_association_cache)
819
+
820
+ author_dup = author.dup
821
+ assert_equal [], author_dup.posts
822
+ end
823
+
824
+ def test_clone_preserves_subtype
825
+ clone = nil
826
+ assert_nothing_raised { clone = Company.find(3).clone }
827
+ assert_kind_of Client, clone
828
+ end
829
+
830
+ def test_clone_of_new_object_with_defaults
831
+ developer = Developer.new
832
+ assert !developer.name_changed?
833
+ assert !developer.salary_changed?
834
+
835
+ cloned_developer = developer.clone
836
+ assert !cloned_developer.name_changed?
837
+ assert !cloned_developer.salary_changed?
838
+ end
839
+
840
+ def test_clone_of_new_object_marks_attributes_as_dirty
841
+ developer = Developer.new :name => 'Bjorn', :salary => 100000
842
+ assert developer.name_changed?
843
+ assert developer.salary_changed?
844
+
845
+ cloned_developer = developer.clone
846
+ assert cloned_developer.name_changed?
847
+ assert cloned_developer.salary_changed?
848
+ end
849
+
850
+ def test_clone_of_new_object_marks_as_dirty_only_changed_attributes
851
+ developer = Developer.new :name => 'Bjorn'
852
+ assert developer.name_changed? # obviously
853
+ assert !developer.salary_changed? # attribute has non-nil default value, so treated as not changed
854
+
855
+ cloned_developer = developer.clone
856
+ assert cloned_developer.name_changed?
857
+ assert !cloned_developer.salary_changed? # ... and cloned instance should behave same
858
+ end
859
+
860
+ def test_dup_of_saved_object_marks_attributes_as_dirty
861
+ developer = Developer.create! :name => 'Bjorn', :salary => 100000
862
+ assert !developer.name_changed?
863
+ assert !developer.salary_changed?
864
+
865
+ cloned_developer = developer.dup
866
+ assert cloned_developer.name_changed? # both attributes differ from defaults
867
+ assert cloned_developer.salary_changed?
868
+ end
869
+
870
+ def test_dup_of_saved_object_marks_as_dirty_only_changed_attributes
871
+ developer = Developer.create! :name => 'Bjorn'
872
+ assert !developer.name_changed? # both attributes of saved object should be treated as not changed
873
+ assert !developer.salary_changed?
874
+
875
+ cloned_developer = developer.dup
876
+ assert cloned_developer.name_changed? # ... but on cloned object should be
877
+ assert !cloned_developer.salary_changed? # ... BUT salary has non-nil default which should be treated as not changed on cloned instance
878
+ end
879
+
880
+ def test_bignum
881
+ company = Company.find(1)
882
+ company.rating = 2147483647
883
+ company.save
884
+ company = Company.find(1)
885
+ assert_equal 2147483647, company.rating
886
+ end
887
+
888
+ # TODO: extend defaults tests to other databases!
889
+ if current_adapter?(:PostgreSQLAdapter)
890
+ def test_default
891
+ with_timezone_config default: :local do
892
+ default = Default.new
893
+
894
+ # fixed dates / times
895
+ assert_equal Date.new(2004, 1, 1), default.fixed_date
896
+ assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
897
+
898
+ # char types
899
+ assert_equal 'Y', default.char1
900
+ assert_equal 'a varchar field', default.char2
901
+ assert_equal 'a text field', default.char3
902
+ end
903
+ end
904
+
905
+ class Geometric < ActiveRecord::Base; end
906
+ def test_geometric_content
907
+
908
+ # accepted format notes:
909
+ # ()'s aren't required
910
+ # values can be a mix of float or integer
911
+
912
+ g = Geometric.new(
913
+ :a_point => '(5.0, 6.1)',
914
+ #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
915
+ :a_line_segment => '(2.0, 3), (5.5, 7.0)',
916
+ :a_box => '2.0, 3, 5.5, 7.0',
917
+ :a_path => '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]', # [ ] is an open path
918
+ :a_polygon => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))',
919
+ :a_circle => '<(5.3, 10.4), 2>'
920
+ )
921
+
922
+ assert g.save
923
+
924
+ # Reload and check that we have all the geometric attributes.
925
+ h = Geometric.find(g.id)
926
+
927
+ assert_equal [5.0, 6.1], h.a_point
928
+ assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
929
+ assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
930
+ assert_equal '[(2,3),(5.5,7),(8.5,11)]', h.a_path
931
+ assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
932
+ assert_equal '<(5.3,10.4),2>', h.a_circle
933
+
934
+ # use a geometric function to test for an open path
935
+ objs = Geometric.find_by_sql ["select isopen(a_path) from geometrics where id = ?", g.id]
936
+
937
+ assert_equal true, objs[0].isopen
938
+
939
+ # test alternate formats when defining the geometric types
940
+
941
+ g = Geometric.new(
942
+ :a_point => '5.0, 6.1',
943
+ #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
944
+ :a_line_segment => '((2.0, 3), (5.5, 7.0))',
945
+ :a_box => '(2.0, 3), (5.5, 7.0)',
946
+ :a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', # ( ) is a closed path
947
+ :a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
948
+ :a_circle => '((5.3, 10.4), 2)'
949
+ )
950
+
951
+ assert g.save
952
+
953
+ # Reload and check that we have all the geometric attributes.
954
+ h = Geometric.find(g.id)
955
+
956
+ assert_equal [5.0, 6.1], h.a_point
957
+ assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
958
+ assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
959
+ assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
960
+ assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
961
+ assert_equal '<(5.3,10.4),2>', h.a_circle
962
+
963
+ # use a geometric function to test for an closed path
964
+ objs = Geometric.find_by_sql ["select isclosed(a_path) from geometrics where id = ?", g.id]
965
+
966
+ assert_equal true, objs[0].isclosed
967
+
968
+ # test native ruby formats when defining the geometric types
969
+ g = Geometric.new(
970
+ :a_point => [5.0, 6.1],
971
+ #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
972
+ :a_line_segment => '((2.0, 3), (5.5, 7.0))',
973
+ :a_box => '(2.0, 3), (5.5, 7.0)',
974
+ :a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', # ( ) is a closed path
975
+ :a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
976
+ :a_circle => '((5.3, 10.4), 2)'
977
+ )
978
+
979
+ assert g.save
980
+
981
+ # Reload and check that we have all the geometric attributes.
982
+ h = Geometric.find(g.id)
983
+
984
+ assert_equal [5.0, 6.1], h.a_point
985
+ assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
986
+ assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
987
+ assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
988
+ assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
989
+ assert_equal '<(5.3,10.4),2>', h.a_circle
990
+ end
991
+ end
992
+
993
+ class NumericData < ActiveRecord::Base
994
+ self.table_name = 'numeric_data'
995
+
996
+ attribute :my_house_population, Type::Integer.new
997
+ attribute :atoms_in_universe, Type::Integer.new
998
+ end
999
+
1000
+ def test_big_decimal_conditions
1001
+ m = NumericData.new(
1002
+ :bank_balance => 1586.43,
1003
+ :big_bank_balance => BigDecimal("1000234000567.95"),
1004
+ :world_population => 6000000000,
1005
+ :my_house_population => 3
1006
+ )
1007
+ assert m.save
1008
+ assert_equal 0, NumericData.where("bank_balance > ?", 2000.0).count
1009
+ end
1010
+
1011
+ def test_numeric_fields
1012
+ m = NumericData.new(
1013
+ :bank_balance => 1586.43,
1014
+ :big_bank_balance => BigDecimal("1000234000567.95"),
1015
+ :world_population => 6000000000,
1016
+ :my_house_population => 3
1017
+ )
1018
+ assert m.save
1019
+
1020
+ m1 = NumericData.find(m.id)
1021
+ assert_not_nil m1
1022
+
1023
+ # As with migration_test.rb, we should make world_population >= 2**62
1024
+ # to cover 64-bit platforms and test it is a Bignum, but the main thing
1025
+ # is that it's an Integer.
1026
+ unless current_adapter?(:IBM_DBAdapter)
1027
+ assert_kind_of Integer, m1.world_population
1028
+ else
1029
+ assert_kind_of BigDecimal, m1.world_population
1030
+ end
1031
+ assert_equal 6000000000, m1.world_population
1032
+
1033
+ unless current_adapter?(:IBM_DBAdapter)
1034
+ assert_kind_of Fixnum, m1.my_house_population
1035
+ else
1036
+ assert_kind_of BigDecimal, m1.my_house_population
1037
+ end
1038
+ assert_equal 3, m1.my_house_population
1039
+
1040
+ assert_kind_of BigDecimal, m1.bank_balance
1041
+ assert_equal BigDecimal("1586.43"), m1.bank_balance
1042
+
1043
+ assert_kind_of BigDecimal, m1.big_bank_balance
1044
+ assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
1045
+ end
1046
+
1047
+ def test_auto_id
1048
+ auto = AutoId.new
1049
+ auto.save
1050
+ assert(auto.id > 0)
1051
+ end
1052
+
1053
+ def test_sql_injection_via_find
1054
+ assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
1055
+ Topic.find("123456 OR id > 0")
1056
+ end
1057
+ end
1058
+
1059
+ def test_column_name_properly_quoted
1060
+ col_record = ColumnName.new
1061
+ col_record.references = 40
1062
+ assert col_record.save
1063
+ col_record.references = 41
1064
+ assert col_record.save
1065
+ assert_not_nil c2 = ColumnName.find(col_record.id)
1066
+ assert_equal(41, c2.references)
1067
+ end
1068
+
1069
+ def test_quoting_arrays
1070
+ replies = Reply.all.merge!(:where => [ "id IN (?)", topics(:first).replies.collect(&:id) ]).to_a
1071
+ assert_equal topics(:first).replies.size, replies.size
1072
+
1073
+ replies = Reply.all.merge!(:where => [ "id IN (?)", [] ]).to_a
1074
+ assert_equal 0, replies.size
1075
+ end
1076
+
1077
+ def test_quote
1078
+ author_name = "\\ \001 ' \n \\n \""
1079
+ topic = Topic.create('author_name' => author_name)
1080
+ assert_equal author_name, Topic.find(topic.id).author_name
1081
+ end
1082
+
1083
+ def test_toggle_attribute
1084
+ assert !topics(:first).approved?
1085
+ topics(:first).toggle!(:approved)
1086
+ assert topics(:first).approved?
1087
+ topic = topics(:first)
1088
+ topic.toggle(:approved)
1089
+ assert !topic.approved?
1090
+ topic.reload
1091
+ assert topic.approved?
1092
+ end
1093
+
1094
+ def test_reload
1095
+ t1 = Topic.find(1)
1096
+ t2 = Topic.find(1)
1097
+ t1.title = "something else"
1098
+ t1.save
1099
+ t2.reload
1100
+ assert_equal t1.title, t2.title
1101
+ end
1102
+
1103
+ def test_reload_with_exclusive_scope
1104
+ dev = DeveloperCalledDavid.first
1105
+ dev.update!(name: "NotDavid" )
1106
+ assert_equal dev, dev.reload
1107
+ end
1108
+
1109
+ def test_switching_between_table_name
1110
+ assert_difference("GoodJoke.count") do
1111
+ Joke.table_name = "cold_jokes"
1112
+ Joke.create
1113
+
1114
+ Joke.table_name = "funny_jokes"
1115
+ Joke.create
1116
+ end
1117
+ end
1118
+
1119
+ def test_clear_cash_when_setting_table_name
1120
+ Joke.table_name = "cold_jokes"
1121
+ before_columns = Joke.columns
1122
+ before_seq = Joke.sequence_name
1123
+
1124
+ Joke.table_name = "funny_jokes"
1125
+ after_columns = Joke.columns
1126
+ after_seq = Joke.sequence_name
1127
+
1128
+ assert_not_equal before_columns, after_columns
1129
+ assert_not_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
1130
+ end
1131
+
1132
+ def test_dont_clear_sequence_name_when_setting_explicitly
1133
+ Joke.sequence_name = "black_jokes_seq"
1134
+ Joke.table_name = "cold_jokes"
1135
+ before_seq = Joke.sequence_name
1136
+
1137
+ Joke.table_name = "funny_jokes"
1138
+ after_seq = Joke.sequence_name
1139
+
1140
+ assert_equal before_seq, after_seq unless before_seq.nil? && after_seq.nil?
1141
+ ensure
1142
+ Joke.reset_sequence_name
1143
+ end
1144
+
1145
+ def test_dont_clear_inheritance_column_when_setting_explicitly
1146
+ Joke.inheritance_column = "my_type"
1147
+ before_inherit = Joke.inheritance_column
1148
+
1149
+ Joke.reset_column_information
1150
+ after_inherit = Joke.inheritance_column
1151
+
1152
+ assert_equal before_inherit, after_inherit unless before_inherit.blank? && after_inherit.blank?
1153
+ end
1154
+
1155
+ def test_set_table_name_symbol_converted_to_string
1156
+ Joke.table_name = :cold_jokes
1157
+ assert_equal 'cold_jokes', Joke.table_name
1158
+ end
1159
+
1160
+ def test_quoted_table_name_after_set_table_name
1161
+ klass = Class.new(ActiveRecord::Base)
1162
+
1163
+ klass.table_name = "foo"
1164
+ assert_equal "foo", klass.table_name
1165
+ assert_equal klass.connection.quote_table_name("foo"), klass.quoted_table_name
1166
+
1167
+ klass.table_name = "bar"
1168
+ assert_equal "bar", klass.table_name
1169
+ assert_equal klass.connection.quote_table_name("bar"), klass.quoted_table_name
1170
+ end
1171
+
1172
+ def test_set_table_name_with_inheritance
1173
+ k = Class.new( ActiveRecord::Base )
1174
+ def k.name; "Foo"; end
1175
+ def k.table_name; super + "ks"; end
1176
+ assert_equal "foosks", k.table_name
1177
+ end
1178
+
1179
+ def test_sequence_name_with_abstract_class
1180
+ ak = Class.new(ActiveRecord::Base)
1181
+ ak.abstract_class = true
1182
+ k = Class.new(ak)
1183
+ k.table_name = "projects"
1184
+ orig_name = k.sequence_name
1185
+ skip "sequences not supported by db" unless orig_name
1186
+ assert_equal k.reset_sequence_name, orig_name
1187
+ end
1188
+
1189
+ def test_count_with_join
1190
+ res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
1191
+
1192
+ res2 = Post.where("posts.#{QUOTED_TYPE} = 'Post'").joins("LEFT JOIN comments ON posts.id=comments.post_id").count
1193
+ assert_equal res, res2
1194
+
1195
+ res3 = nil
1196
+ assert_nothing_raised do
1197
+ res3 = Post.where("posts.#{QUOTED_TYPE} = 'Post'").joins("LEFT JOIN comments ON posts.id=comments.post_id").count
1198
+ end
1199
+ assert_equal res, res3
1200
+
1201
+ res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
1202
+ res5 = nil
1203
+ assert_nothing_raised do
1204
+ res5 = Post.where("p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id").joins("p, comments co").select("p.id").count
1205
+ end
1206
+
1207
+ assert_equal res4, res5
1208
+
1209
+ res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
1210
+ res7 = nil
1211
+ assert_nothing_raised do
1212
+ res7 = Post.where("p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id").joins("p, comments co").select("p.id").distinct.count
1213
+ end
1214
+ assert_equal res6, res7
1215
+ end
1216
+
1217
+ def test_no_limit_offset
1218
+ assert_nothing_raised do
1219
+ Developer.all.merge!(:offset => 2).to_a
1220
+ end
1221
+ end
1222
+
1223
+ def test_find_last
1224
+ last = Developer.last
1225
+ assert_equal last, Developer.all.merge!(:order => 'id desc').first
1226
+ end
1227
+
1228
+ def test_last
1229
+ assert_equal Developer.all.merge!(:order => 'id desc').first, Developer.last
1230
+ end
1231
+
1232
+ def test_all
1233
+ developers = Developer.all
1234
+ assert_kind_of ActiveRecord::Relation, developers
1235
+ assert_equal Developer.all, developers
1236
+ end
1237
+
1238
+ def test_all_with_conditions
1239
+ assert_equal Developer.all.merge!(:order => 'id desc').to_a, Developer.order('id desc').to_a
1240
+ end
1241
+
1242
+ def test_find_ordered_last
1243
+ last = Developer.all.merge!(:order => 'developers.salary ASC').last
1244
+ assert_equal last, Developer.all.merge!(:order => 'developers.salary ASC').to_a.last
1245
+ end
1246
+
1247
+ def test_find_reverse_ordered_last
1248
+ last = Developer.all.merge!(:order => 'developers.salary DESC').last
1249
+ assert_equal last, Developer.all.merge!(:order => 'developers.salary DESC').to_a.last
1250
+ end
1251
+
1252
+ def test_find_multiple_ordered_last
1253
+ last = Developer.all.merge!(:order => 'developers.name, developers.salary DESC').last
1254
+ assert_equal last, Developer.all.merge!(:order => 'developers.name, developers.salary DESC').to_a.last
1255
+ end
1256
+
1257
+ def test_find_keeps_multiple_order_values
1258
+ combined = Developer.all.merge!(:order => 'developers.name, developers.salary').to_a
1259
+ assert_equal combined, Developer.all.merge!(:order => ['developers.name', 'developers.salary']).to_a
1260
+ end
1261
+
1262
+ def test_find_keeps_multiple_group_values
1263
+ combined = Developer.all.merge!(:group => 'developers.name, developers.salary, developers.id, developers.created_at, developers.updated_at, developers.created_on, developers.updated_on').to_a
1264
+ assert_equal combined, Developer.all.merge!(:group => ['developers.name', 'developers.salary', 'developers.id', 'developers.created_at', 'developers.updated_at', 'developers.created_on', 'developers.updated_on']).to_a
1265
+ end
1266
+
1267
+ def test_find_symbol_ordered_last
1268
+ last = Developer.all.merge!(:order => :salary).last
1269
+ assert_equal last, Developer.all.merge!(:order => :salary).to_a.last
1270
+ end
1271
+
1272
+ def test_abstract_class
1273
+ assert !ActiveRecord::Base.abstract_class?
1274
+ assert LoosePerson.abstract_class?
1275
+ assert !LooseDescendant.abstract_class?
1276
+ end
1277
+
1278
+ def test_abstract_class_table_name
1279
+ assert_nil AbstractCompany.table_name
1280
+ end
1281
+
1282
+ def test_descends_from_active_record
1283
+ assert !ActiveRecord::Base.descends_from_active_record?
1284
+
1285
+ # Abstract subclass of AR::Base.
1286
+ assert LoosePerson.descends_from_active_record?
1287
+
1288
+ # Concrete subclass of an abstract class.
1289
+ assert LooseDescendant.descends_from_active_record?
1290
+
1291
+ # Concrete subclass of AR::Base.
1292
+ assert TightPerson.descends_from_active_record?
1293
+
1294
+ # Concrete subclass of a concrete class but has no type column.
1295
+ assert TightDescendant.descends_from_active_record?
1296
+
1297
+ # Concrete subclass of AR::Base.
1298
+ assert Post.descends_from_active_record?
1299
+
1300
+ # Abstract subclass of a concrete class which has a type column.
1301
+ # This is pathological, as you'll never have Sub < Abstract < Concrete.
1302
+ assert !StiPost.descends_from_active_record?
1303
+
1304
+ # Concrete subclasses an abstract class which has a type column.
1305
+ assert !SubStiPost.descends_from_active_record?
1306
+ end
1307
+
1308
+ def test_find_on_abstract_base_class_doesnt_use_type_condition
1309
+ old_class = LooseDescendant
1310
+ Object.send :remove_const, :LooseDescendant
1311
+
1312
+ descendant = old_class.create! :first_name => 'bob'
1313
+ assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
1314
+ ensure
1315
+ unless Object.const_defined?(:LooseDescendant)
1316
+ Object.const_set :LooseDescendant, old_class
1317
+ end
1318
+ end
1319
+
1320
+ def test_assert_queries
1321
+ query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
1322
+ assert_queries(2) { 2.times { query.call } }
1323
+ assert_queries 1, &query
1324
+ assert_no_queries { assert true }
1325
+ end
1326
+
1327
+ def test_benchmark_with_log_level
1328
+ original_logger = ActiveRecord::Base.logger
1329
+ log = StringIO.new
1330
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
1331
+ ActiveRecord::Base.logger.level = Logger::WARN
1332
+ ActiveRecord::Base.benchmark("Debug Topic Count", :level => :debug) { Topic.count }
1333
+ ActiveRecord::Base.benchmark("Warn Topic Count", :level => :warn) { Topic.count }
1334
+ ActiveRecord::Base.benchmark("Error Topic Count", :level => :error) { Topic.count }
1335
+ assert_no_match(/Debug Topic Count/, log.string)
1336
+ assert_match(/Warn Topic Count/, log.string)
1337
+ assert_match(/Error Topic Count/, log.string)
1338
+ ensure
1339
+ ActiveRecord::Base.logger = original_logger
1340
+ end
1341
+
1342
+ def test_benchmark_with_use_silence
1343
+ original_logger = ActiveRecord::Base.logger
1344
+ log = StringIO.new
1345
+ ActiveRecord::Base.logger = ActiveSupport::Logger.new(log)
1346
+ ActiveRecord::Base.benchmark("Logging", :level => :debug, :silence => false) { ActiveRecord::Base.logger.debug "Quiet" }
1347
+ assert_match(/Quiet/, log.string)
1348
+ ensure
1349
+ ActiveRecord::Base.logger = original_logger
1350
+ end
1351
+
1352
+ def test_compute_type_success
1353
+ assert_equal Author, ActiveRecord::Base.send(:compute_type, 'Author')
1354
+ end
1355
+
1356
+ def test_compute_type_nonexistent_constant
1357
+ e = assert_raises NameError do
1358
+ ActiveRecord::Base.send :compute_type, 'NonexistentModel'
1359
+ end
1360
+ assert_equal 'uninitialized constant ActiveRecord::Base::NonexistentModel', e.message
1361
+ assert_equal 'ActiveRecord::Base::NonexistentModel', e.name
1362
+ end
1363
+
1364
+ def test_compute_type_no_method_error
1365
+ ActiveSupport::Dependencies.stubs(:safe_constantize).raises(NoMethodError)
1366
+ assert_raises NoMethodError do
1367
+ ActiveRecord::Base.send :compute_type, 'InvalidModel'
1368
+ end
1369
+ end
1370
+
1371
+ def test_compute_type_on_undefined_method
1372
+ error = nil
1373
+ begin
1374
+ Class.new(Author) do
1375
+ alias_method :foo, :bar
1376
+ end
1377
+ rescue => e
1378
+ error = e
1379
+ end
1380
+
1381
+ ActiveSupport::Dependencies.stubs(:safe_constantize).raises(e)
1382
+
1383
+ exception = assert_raises NameError do
1384
+ ActiveRecord::Base.send :compute_type, 'InvalidModel'
1385
+ end
1386
+ assert_equal error.message, exception.message
1387
+ end
1388
+
1389
+ def test_compute_type_argument_error
1390
+ ActiveSupport::Dependencies.stubs(:safe_constantize).raises(ArgumentError)
1391
+ assert_raises ArgumentError do
1392
+ ActiveRecord::Base.send :compute_type, 'InvalidModel'
1393
+ end
1394
+ end
1395
+
1396
+ def test_clear_cache!
1397
+ # preheat cache
1398
+ c1 = Post.connection.schema_cache.columns('posts')
1399
+ ActiveRecord::Base.clear_cache!
1400
+ c2 = Post.connection.schema_cache.columns('posts')
1401
+ c1.each_with_index do |v, i|
1402
+ assert_not_same v, c2[i]
1403
+ end
1404
+ assert_equal c1, c2
1405
+ end
1406
+
1407
+ def test_current_scope_is_reset
1408
+ Object.const_set :UnloadablePost, Class.new(ActiveRecord::Base)
1409
+ UnloadablePost.send(:current_scope=, UnloadablePost.all)
1410
+
1411
+ UnloadablePost.unloadable
1412
+ assert_not_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, "UnloadablePost")
1413
+ ActiveSupport::Dependencies.remove_unloadable_constants!
1414
+ assert_nil ActiveRecord::Scoping::ScopeRegistry.value_for(:current_scope, "UnloadablePost")
1415
+ ensure
1416
+ Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
1417
+ end
1418
+
1419
+ def test_marshal_round_trip
1420
+ expected = posts(:welcome)
1421
+ marshalled = Marshal.dump(expected)
1422
+ actual = Marshal.load(marshalled)
1423
+
1424
+ assert_equal expected.attributes, actual.attributes
1425
+ end
1426
+
1427
+ def test_marshal_new_record_round_trip
1428
+ marshalled = Marshal.dump(Post.new)
1429
+ post = Marshal.load(marshalled)
1430
+
1431
+ assert post.new_record?, "should be a new record"
1432
+ end
1433
+
1434
+ def test_marshalling_with_associations
1435
+ post = Post.new
1436
+ post.comments.build
1437
+
1438
+ marshalled = Marshal.dump(post)
1439
+ post = Marshal.load(marshalled)
1440
+
1441
+ assert_equal 1, post.comments.length
1442
+ end
1443
+
1444
+ if Process.respond_to?(:fork) && !in_memory_db?
1445
+ def test_marshal_between_processes
1446
+ # Define a new model to ensure there are no caches
1447
+ if self.class.const_defined?("Post", false)
1448
+ flunk "there should be no post constant"
1449
+ end
1450
+
1451
+ self.class.const_set("Post", Class.new(ActiveRecord::Base) {
1452
+ has_many :comments
1453
+ })
1454
+
1455
+ rd, wr = IO.pipe
1456
+ rd.binmode
1457
+ wr.binmode
1458
+
1459
+ ActiveRecord::Base.connection_handler.clear_all_connections!
1460
+
1461
+ fork do
1462
+ rd.close
1463
+ post = Post.new
1464
+ post.comments.build
1465
+ wr.write Marshal.dump(post)
1466
+ wr.close
1467
+ end
1468
+
1469
+ wr.close
1470
+ assert Marshal.load rd.read
1471
+ rd.close
1472
+ end
1473
+ end
1474
+
1475
+ def test_marshalling_new_record_round_trip_with_associations
1476
+ post = Post.new
1477
+ post.comments.build
1478
+
1479
+ post = Marshal.load(Marshal.dump(post))
1480
+
1481
+ assert post.new_record?, "should be a new record"
1482
+ end
1483
+
1484
+ def test_attribute_names
1485
+ assert_equal ["id", "type", "firm_id", "firm_name", "name", "client_of", "rating", "account_id", "description"],
1486
+ Company.attribute_names
1487
+ end
1488
+
1489
+ def test_attribute_names_on_table_not_exists
1490
+ assert_equal [], NonExistentTable.attribute_names
1491
+ end
1492
+
1493
+ def test_attribute_names_on_abstract_class
1494
+ assert_equal [], AbstractCompany.attribute_names
1495
+ end
1496
+
1497
+ def test_touch_should_raise_error_on_a_new_object
1498
+ company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals")
1499
+ assert_raises(ActiveRecord::ActiveRecordError) do
1500
+ company.touch :updated_at
1501
+ end
1502
+ end
1503
+
1504
+ def test_uniq_delegates_to_scoped
1505
+ scope = stub
1506
+ Bird.stubs(:all).returns(mock(:uniq => scope))
1507
+ assert_equal scope, Bird.uniq
1508
+ end
1509
+
1510
+ def test_distinct_delegates_to_scoped
1511
+ scope = stub
1512
+ Bird.stubs(:all).returns(mock(:distinct => scope))
1513
+ assert_equal scope, Bird.distinct
1514
+ end
1515
+
1516
+ def test_table_name_with_2_abstract_subclasses
1517
+ assert_equal "photos", Photo.table_name
1518
+ end
1519
+
1520
+ def test_column_types_typecast
1521
+ topic = Topic.first
1522
+ assert_not_equal 't.lo', topic.author_name
1523
+
1524
+ attrs = topic.attributes.dup
1525
+ attrs.delete 'id'
1526
+
1527
+ typecast = Class.new(ActiveRecord::Type::Value) {
1528
+ def type_cast value
1529
+ "t.lo"
1530
+ end
1531
+ }
1532
+
1533
+ types = { 'author_name' => typecast.new }
1534
+ topic = Topic.instantiate(attrs, types)
1535
+
1536
+ assert_equal 't.lo', topic.author_name
1537
+ end
1538
+
1539
+ def test_typecasting_aliases
1540
+ assert_equal 10, Topic.select('10 as tenderlove').first.tenderlove
1541
+ end
1542
+
1543
+ def test_slice
1544
+ company = Company.new(:rating => 1, :name => "37signals", :firm_name => "37signals")
1545
+ hash = company.slice(:name, :rating, "arbitrary_method")
1546
+ assert_equal hash[:name], company.name
1547
+ assert_equal hash['name'], company.name
1548
+ assert_equal hash[:rating], company.rating
1549
+ assert_equal hash['arbitrary_method'], company.arbitrary_method
1550
+ assert_equal hash[:arbitrary_method], company.arbitrary_method
1551
+ assert_nil hash[:firm_name]
1552
+ assert_nil hash['firm_name']
1553
+ end
1554
+
1555
+ def test_default_values_are_deeply_dupped
1556
+ company = Company.new
1557
+ company.description << "foo"
1558
+ assert_equal "", Company.new.description
1559
+ end
1560
+
1561
+ test "scoped can take a values hash" do
1562
+ klass = Class.new(ActiveRecord::Base)
1563
+ assert_equal ['foo'], klass.all.merge!(select: 'foo').select_values
1564
+ end
1565
+
1566
+ test "connection_handler can be overridden" do
1567
+ klass = Class.new(ActiveRecord::Base)
1568
+ orig_handler = klass.connection_handler
1569
+ new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
1570
+ thread_connection_handler = nil
1571
+
1572
+ t = Thread.new do
1573
+ klass.connection_handler = new_handler
1574
+ thread_connection_handler = klass.connection_handler
1575
+ end
1576
+ t.join
1577
+
1578
+ assert_equal klass.connection_handler, orig_handler
1579
+ assert_equal thread_connection_handler, new_handler
1580
+ end
1581
+
1582
+ test "new threads get default the default connection handler" do
1583
+ klass = Class.new(ActiveRecord::Base)
1584
+ orig_handler = klass.connection_handler
1585
+ handler = nil
1586
+
1587
+ t = Thread.new do
1588
+ handler = klass.connection_handler
1589
+ end
1590
+ t.join
1591
+
1592
+ assert_equal handler, orig_handler
1593
+ assert_equal klass.connection_handler, orig_handler
1594
+ assert_equal klass.default_connection_handler, orig_handler
1595
+ end
1596
+
1597
+ test "changing a connection handler in a main thread does not poison the other threads" do
1598
+ klass = Class.new(ActiveRecord::Base)
1599
+ orig_handler = klass.connection_handler
1600
+ new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
1601
+ after_handler = nil
1602
+ latch1 = ActiveSupport::Concurrency::Latch.new
1603
+ latch2 = ActiveSupport::Concurrency::Latch.new
1604
+
1605
+ t = Thread.new do
1606
+ klass.connection_handler = new_handler
1607
+ latch1.release
1608
+ latch2.await
1609
+ after_handler = klass.connection_handler
1610
+ end
1611
+
1612
+ latch1.await
1613
+
1614
+ klass.connection_handler = orig_handler
1615
+ latch2.release
1616
+ t.join
1617
+
1618
+ assert_equal after_handler, new_handler
1619
+ assert_equal orig_handler, klass.connection_handler
1620
+ end
1621
+
1622
+ # Note: This is a performance optimization for Array#uniq and Hash#[] with
1623
+ # AR::Base objects. If the future has made this irrelevant, feel free to
1624
+ # delete this.
1625
+ test "records without an id have unique hashes" do
1626
+ assert_not_equal Post.new.hash, Post.new.hash
1627
+ end
1628
+
1629
+ test "resetting column information doesn't remove attribute methods" do
1630
+ topic = topics(:first)
1631
+
1632
+ assert_not topic.id_changed?
1633
+
1634
+ Topic.reset_column_information
1635
+
1636
+ assert_not topic.id_changed?
1637
+ end
1638
+ end