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