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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (586) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +4 -0
  3. data/LICENSE +1 -1
  4. data/MANIFEST +14 -14
  5. data/ParameterizedQueries README +6 -6
  6. data/README +208 -225
  7. data/ext/Makefile.nt32 +181 -181
  8. data/ext/Makefile.nt32.191 +212 -212
  9. data/ext/extconf.rb +291 -291
  10. data/ext/ibm_db.c +11887 -11887
  11. data/ext/ruby_ibm_db.h +241 -241
  12. data/ext/ruby_ibm_db_cli.c +866 -866
  13. data/ext/ruby_ibm_db_cli.h +500 -500
  14. data/init.rb +41 -41
  15. data/lib/IBM_DB.rb +27 -27
  16. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3452 -3177
  17. data/lib/active_record/connection_adapters/ibmdb_adapter.rb +5 -2
  18. data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
  19. data/lib/mswin32/ibm_db.rb +91 -123
  20. data/lib/mswin32/rb2x/i386/ibm_db.so +0 -0
  21. data/test/active_record/connection_adapters/fake_adapter.rb +49 -46
  22. data/test/assets/example.log +1 -1
  23. data/test/assets/test.txt +1 -1
  24. data/test/cases/adapter_test.rb +351 -276
  25. data/test/cases/adapters/mysql2/active_schema_test.rb +193 -0
  26. data/test/cases/adapters/mysql2/bind_parameter_test.rb +50 -0
  27. data/test/cases/adapters/mysql2/boolean_test.rb +100 -0
  28. data/test/cases/adapters/mysql2/case_sensitivity_test.rb +63 -0
  29. data/test/cases/adapters/mysql2/charset_collation_test.rb +54 -0
  30. data/test/cases/adapters/mysql2/connection_test.rb +210 -0
  31. data/test/cases/adapters/mysql2/datetime_precision_quoting_test.rb +45 -0
  32. data/test/cases/adapters/mysql2/enum_test.rb +26 -0
  33. data/test/cases/adapters/mysql2/explain_test.rb +21 -0
  34. data/test/cases/adapters/mysql2/json_test.rb +195 -0
  35. data/test/cases/adapters/mysql2/mysql2_adapter_test.rb +83 -0
  36. data/test/cases/adapters/mysql2/reserved_word_test.rb +152 -0
  37. data/test/cases/adapters/mysql2/schema_migrations_test.rb +59 -0
  38. data/test/cases/adapters/mysql2/schema_test.rb +126 -0
  39. data/test/cases/adapters/mysql2/sp_test.rb +36 -0
  40. data/test/cases/adapters/mysql2/sql_types_test.rb +14 -0
  41. data/test/cases/adapters/mysql2/table_options_test.rb +42 -0
  42. data/test/cases/adapters/mysql2/unsigned_type_test.rb +66 -0
  43. data/test/cases/adapters/postgresql/active_schema_test.rb +98 -0
  44. data/test/cases/adapters/postgresql/array_test.rb +339 -0
  45. data/test/cases/adapters/postgresql/bit_string_test.rb +82 -0
  46. data/test/cases/adapters/postgresql/bytea_test.rb +134 -0
  47. data/test/cases/adapters/postgresql/case_insensitive_test.rb +26 -0
  48. data/test/cases/adapters/postgresql/change_schema_test.rb +38 -0
  49. data/test/cases/adapters/postgresql/cidr_test.rb +25 -0
  50. data/test/cases/adapters/postgresql/citext_test.rb +78 -0
  51. data/test/cases/adapters/postgresql/collation_test.rb +53 -0
  52. data/test/cases/adapters/postgresql/composite_test.rb +132 -0
  53. data/test/cases/adapters/postgresql/connection_test.rb +257 -0
  54. data/test/cases/adapters/postgresql/datatype_test.rb +92 -0
  55. data/test/cases/adapters/postgresql/domain_test.rb +47 -0
  56. data/test/cases/adapters/postgresql/enum_test.rb +91 -0
  57. data/test/cases/adapters/postgresql/explain_test.rb +20 -0
  58. data/test/cases/adapters/postgresql/extension_migration_test.rb +63 -0
  59. data/test/cases/adapters/postgresql/full_text_test.rb +44 -0
  60. data/test/cases/adapters/postgresql/geometric_test.rb +378 -0
  61. data/test/cases/adapters/postgresql/hstore_test.rb +382 -0
  62. data/test/cases/adapters/postgresql/infinity_test.rb +69 -0
  63. data/test/cases/adapters/postgresql/integer_test.rb +25 -0
  64. data/test/cases/adapters/postgresql/json_test.rb +237 -0
  65. data/test/cases/adapters/postgresql/ltree_test.rb +53 -0
  66. data/test/cases/adapters/postgresql/money_test.rb +96 -0
  67. data/test/cases/adapters/postgresql/network_test.rb +94 -0
  68. data/test/cases/adapters/postgresql/numbers_test.rb +49 -0
  69. data/test/cases/adapters/postgresql/postgresql_adapter_test.rb +405 -0
  70. data/test/cases/adapters/postgresql/prepared_statements_test.rb +22 -0
  71. data/test/cases/adapters/postgresql/quoting_test.rb +44 -0
  72. data/test/cases/adapters/postgresql/range_test.rb +343 -0
  73. data/test/cases/adapters/postgresql/referential_integrity_test.rb +111 -0
  74. data/test/cases/adapters/postgresql/rename_table_test.rb +34 -0
  75. data/test/cases/adapters/postgresql/schema_authorization_test.rb +119 -0
  76. data/test/cases/adapters/postgresql/schema_test.rb +597 -0
  77. data/test/cases/adapters/postgresql/serial_test.rb +154 -0
  78. data/test/cases/adapters/postgresql/statement_pool_test.rb +41 -0
  79. data/test/cases/adapters/postgresql/timestamp_test.rb +90 -0
  80. data/test/cases/adapters/postgresql/type_lookup_test.rb +33 -0
  81. data/test/cases/adapters/postgresql/utils_test.rb +62 -0
  82. data/test/cases/adapters/postgresql/uuid_test.rb +294 -0
  83. data/test/cases/adapters/postgresql/xml_test.rb +54 -0
  84. data/test/cases/adapters/sqlite3/collation_test.rb +53 -0
  85. data/test/cases/adapters/sqlite3/copy_table_test.rb +98 -0
  86. data/test/cases/adapters/sqlite3/explain_test.rb +21 -0
  87. data/test/cases/adapters/sqlite3/quoting_test.rb +101 -0
  88. data/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +441 -0
  89. data/test/cases/adapters/sqlite3/sqlite3_create_folder_test.rb +24 -0
  90. data/test/cases/adapters/sqlite3/statement_pool_test.rb +20 -0
  91. data/test/cases/aggregations_test.rb +168 -158
  92. data/test/cases/ar_schema_test.rb +146 -161
  93. data/test/cases/associations/association_scope_test.rb +16 -21
  94. data/test/cases/associations/belongs_to_associations_test.rb +1141 -1029
  95. data/test/cases/associations/bidirectional_destroy_dependencies_test.rb +41 -0
  96. data/test/cases/associations/callbacks_test.rb +190 -192
  97. data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
  98. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
  99. data/test/cases/associations/eager_load_nested_include_test.rb +126 -128
  100. data/test/cases/associations/eager_singularization_test.rb +148 -148
  101. data/test/cases/associations/eager_test.rb +1514 -1429
  102. data/test/cases/associations/extension_test.rb +87 -82
  103. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +1004 -972
  104. data/test/cases/associations/has_many_associations_test.rb +2501 -2182
  105. data/test/cases/associations/has_many_through_associations_test.rb +1271 -1204
  106. data/test/cases/associations/has_one_associations_test.rb +707 -610
  107. data/test/cases/associations/has_one_through_associations_test.rb +383 -380
  108. data/test/cases/associations/inner_join_association_test.rb +139 -139
  109. data/test/cases/associations/inverse_associations_test.rb +733 -706
  110. data/test/cases/associations/join_model_test.rb +777 -754
  111. data/test/cases/associations/left_outer_join_association_test.rb +88 -0
  112. data/test/cases/associations/nested_through_associations_test.rb +579 -579
  113. data/test/cases/associations/required_test.rb +102 -82
  114. data/test/cases/associations_test.rb +385 -380
  115. data/test/cases/attribute_decorators_test.rb +125 -125
  116. data/test/cases/attribute_methods/read_test.rb +60 -60
  117. data/test/cases/attribute_methods_test.rb +1009 -952
  118. data/test/cases/attribute_set_test.rb +270 -210
  119. data/test/cases/attribute_test.rb +246 -180
  120. data/test/cases/attributes_test.rb +253 -136
  121. data/test/cases/autosave_association_test.rb +1708 -1595
  122. data/test/cases/base_test.rb +1713 -1664
  123. data/test/cases/batches_test.rb +489 -212
  124. data/test/cases/binary_test.rb +44 -52
  125. data/test/cases/bind_parameter_test.rb +110 -100
  126. data/test/cases/cache_key_test.rb +25 -0
  127. data/test/cases/calculations_test.rb +798 -646
  128. data/test/cases/callbacks_test.rb +636 -543
  129. data/test/cases/clone_test.rb +40 -40
  130. data/test/cases/coders/json_test.rb +15 -0
  131. data/test/cases/coders/yaml_column_test.rb +63 -63
  132. data/test/cases/collection_cache_key_test.rb +115 -0
  133. data/test/cases/column_alias_test.rb +17 -17
  134. data/test/cases/column_definition_test.rb +92 -123
  135. data/test/cases/comment_test.rb +143 -0
  136. data/test/cases/connection_adapters/adapter_leasing_test.rb +56 -54
  137. data/test/cases/connection_adapters/connection_handler_test.rb +160 -53
  138. data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
  139. data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +255 -293
  140. data/test/cases/connection_adapters/mysql_type_lookup_test.rb +69 -65
  141. data/test/cases/connection_adapters/quoting_test.rb +13 -13
  142. data/test/cases/connection_adapters/schema_cache_test.rb +61 -56
  143. data/test/cases/connection_adapters/type_lookup_test.rb +118 -110
  144. data/test/cases/connection_management_test.rb +112 -122
  145. data/test/cases/connection_pool_test.rb +521 -346
  146. data/test/cases/connection_specification/resolver_test.rb +131 -116
  147. data/test/cases/core_test.rb +112 -112
  148. data/test/cases/counter_cache_test.rb +214 -209
  149. data/test/cases/custom_locking_test.rb +17 -17
  150. data/test/cases/database_statements_test.rb +34 -19
  151. data/test/cases/{invalid_date_test.rb → date_test.rb} +44 -32
  152. data/test/cases/date_time_precision_test.rb +106 -0
  153. data/test/cases/date_time_test.rb +61 -61
  154. data/test/cases/defaults_test.rb +218 -223
  155. data/test/cases/dirty_test.rb +763 -785
  156. data/test/cases/disconnected_test.rb +30 -28
  157. data/test/cases/dup_test.rb +157 -157
  158. data/test/cases/enum_test.rb +444 -290
  159. data/test/cases/errors_test.rb +16 -0
  160. data/test/cases/explain_subscriber_test.rb +64 -64
  161. data/test/cases/explain_test.rb +87 -76
  162. data/test/cases/finder_respond_to_test.rb +60 -60
  163. data/test/cases/finder_test.rb +1294 -1169
  164. data/test/cases/fixture_set/file_test.rb +156 -138
  165. data/test/cases/fixtures_test.rb +988 -908
  166. data/test/cases/forbidden_attributes_protection_test.rb +165 -99
  167. data/test/cases/habtm_destroy_order_test.rb +61 -61
  168. data/test/cases/helper.rb +204 -210
  169. data/test/cases/hot_compatibility_test.rb +142 -54
  170. data/test/cases/i18n_test.rb +45 -45
  171. data/test/cases/inheritance_test.rb +606 -375
  172. data/test/cases/integration_test.rb +155 -139
  173. data/test/cases/invalid_connection_test.rb +24 -22
  174. data/test/cases/invertible_migration_test.rb +387 -295
  175. data/test/cases/json_serialization_test.rb +311 -302
  176. data/test/cases/locking_test.rb +493 -477
  177. data/test/cases/log_subscriber_test.rb +225 -136
  178. data/test/cases/migration/change_schema_test.rb +458 -512
  179. data/test/cases/migration/change_table_test.rb +256 -224
  180. data/test/cases/migration/column_attributes_test.rb +176 -192
  181. data/test/cases/migration/column_positioning_test.rb +56 -56
  182. data/test/cases/migration/columns_test.rb +310 -304
  183. data/test/cases/migration/command_recorder_test.rb +350 -305
  184. data/test/cases/migration/compatibility_test.rb +118 -0
  185. data/test/cases/migration/create_join_table_test.rb +157 -148
  186. data/test/cases/migration/foreign_key_test.rb +360 -328
  187. data/test/cases/migration/helper.rb +39 -39
  188. data/test/cases/migration/index_test.rb +218 -216
  189. data/test/cases/migration/logger_test.rb +36 -36
  190. data/test/cases/migration/pending_migrations_test.rb +52 -53
  191. data/test/cases/migration/references_foreign_key_test.rb +216 -169
  192. data/test/cases/migration/references_index_test.rb +101 -101
  193. data/test/cases/migration/references_statements_test.rb +136 -116
  194. data/test/cases/migration/rename_table_test.rb +93 -93
  195. data/test/cases/migration_test.rb +1157 -959
  196. data/test/cases/migrator_test.rb +470 -388
  197. data/test/cases/mixin_test.rb +68 -70
  198. data/test/cases/modules_test.rb +172 -173
  199. data/test/cases/multiparameter_attributes_test.rb +372 -350
  200. data/test/cases/multiple_db_test.rb +122 -115
  201. data/test/cases/nested_attributes_test.rb +1098 -1070
  202. data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
  203. data/test/cases/persistence_test.rb +1001 -909
  204. data/test/cases/pooled_connections_test.rb +81 -81
  205. data/test/cases/primary_keys_test.rb +376 -237
  206. data/test/cases/query_cache_test.rb +446 -326
  207. data/test/cases/quoting_test.rb +202 -156
  208. data/test/cases/readonly_test.rb +119 -118
  209. data/test/cases/reaper_test.rb +85 -85
  210. data/test/cases/reflection_test.rb +509 -463
  211. data/test/cases/relation/delegation_test.rb +63 -68
  212. data/test/cases/relation/merging_test.rb +157 -161
  213. data/test/cases/relation/mutation_test.rb +183 -165
  214. data/test/cases/relation/or_test.rb +92 -0
  215. data/test/cases/relation/predicate_builder_test.rb +16 -14
  216. data/test/cases/relation/record_fetch_warning_test.rb +40 -0
  217. data/test/cases/relation/where_chain_test.rb +105 -181
  218. data/test/cases/relation/where_clause_test.rb +182 -0
  219. data/test/cases/relation/where_test.rb +322 -300
  220. data/test/cases/relation_test.rb +328 -319
  221. data/test/cases/relations_test.rb +2026 -1815
  222. data/test/cases/reload_models_test.rb +22 -22
  223. data/test/cases/result_test.rb +90 -80
  224. data/test/cases/sanitize_test.rb +176 -83
  225. data/test/cases/schema_dumper_test.rb +457 -463
  226. data/test/cases/schema_loading_test.rb +52 -0
  227. data/test/cases/scoping/default_scoping_test.rb +528 -454
  228. data/test/cases/scoping/named_scoping_test.rb +561 -524
  229. data/test/cases/scoping/relation_scoping_test.rb +400 -357
  230. data/test/cases/secure_token_test.rb +32 -0
  231. data/test/cases/serialization_test.rb +104 -104
  232. data/test/cases/serialized_attribute_test.rb +364 -277
  233. data/test/cases/statement_cache_test.rb +136 -98
  234. data/test/cases/store_test.rb +195 -194
  235. data/test/cases/suppressor_test.rb +63 -0
  236. data/test/cases/tasks/database_tasks_test.rb +462 -398
  237. data/test/cases/tasks/mysql_rake_test.rb +345 -324
  238. data/test/cases/tasks/postgresql_rake_test.rb +304 -250
  239. data/test/cases/tasks/sqlite_rake_test.rb +220 -193
  240. data/test/cases/test_case.rb +131 -123
  241. data/test/cases/test_fixtures_test.rb +36 -0
  242. data/test/cases/time_precision_test.rb +102 -0
  243. data/test/cases/timestamp_test.rb +501 -467
  244. data/test/cases/touch_later_test.rb +121 -0
  245. data/test/cases/transaction_callbacks_test.rb +518 -452
  246. data/test/cases/transaction_isolation_test.rb +106 -106
  247. data/test/cases/transactions_test.rb +834 -817
  248. data/test/cases/type/adapter_specific_registry_test.rb +133 -0
  249. data/test/cases/type/date_time_test.rb +14 -0
  250. data/test/cases/type/integer_test.rb +27 -121
  251. data/test/cases/type/string_test.rb +22 -36
  252. data/test/cases/type/type_map_test.rb +177 -177
  253. data/test/cases/type_test.rb +39 -0
  254. data/test/cases/types_test.rb +24 -141
  255. data/test/cases/unconnected_test.rb +33 -33
  256. data/test/cases/validations/absence_validation_test.rb +73 -0
  257. data/test/cases/validations/association_validation_test.rb +97 -86
  258. data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
  259. data/test/cases/validations/i18n_validation_test.rb +86 -90
  260. data/test/cases/validations/length_validation_test.rb +79 -47
  261. data/test/cases/validations/presence_validation_test.rb +103 -68
  262. data/test/cases/validations/uniqueness_validation_test.rb +548 -457
  263. data/test/cases/validations_repair_helper.rb +19 -23
  264. data/test/cases/validations_test.rb +194 -165
  265. data/test/cases/view_test.rb +216 -119
  266. data/test/cases/yaml_serialization_test.rb +121 -126
  267. data/test/config.example.yml +97 -0
  268. data/test/config.rb +5 -5
  269. data/test/fixtures/accounts.yml +29 -29
  270. data/test/fixtures/admin/accounts.yml +2 -2
  271. data/test/fixtures/admin/users.yml +10 -10
  272. data/test/fixtures/author_addresses.original +11 -0
  273. data/test/fixtures/author_addresses.yml +17 -17
  274. data/test/fixtures/author_favorites.yml +3 -3
  275. data/test/fixtures/authors.original +17 -0
  276. data/test/fixtures/authors.yml +23 -23
  277. data/test/fixtures/bad_posts.yml +9 -0
  278. data/test/fixtures/binaries.yml +133 -133
  279. data/test/fixtures/books.yml +31 -11
  280. data/test/fixtures/bulbs.yml +5 -5
  281. data/test/fixtures/cars.yml +9 -9
  282. data/test/fixtures/categories.yml +19 -19
  283. data/test/fixtures/categories/special_categories.yml +9 -9
  284. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
  285. data/test/fixtures/categories_ordered.yml +7 -7
  286. data/test/fixtures/categories_posts.yml +31 -31
  287. data/test/fixtures/categorizations.yml +23 -23
  288. data/test/fixtures/clubs.yml +8 -8
  289. data/test/fixtures/collections.yml +3 -3
  290. data/test/fixtures/colleges.yml +3 -3
  291. data/test/fixtures/comments.yml +65 -65
  292. data/test/fixtures/companies.yml +67 -67
  293. data/test/fixtures/computers.yml +10 -10
  294. data/test/fixtures/content.yml +3 -0
  295. data/test/fixtures/content_positions.yml +3 -0
  296. data/test/fixtures/courses.yml +8 -8
  297. data/test/fixtures/customers.yml +25 -25
  298. data/test/fixtures/dashboards.yml +6 -6
  299. data/test/fixtures/dead_parrots.yml +5 -0
  300. data/test/fixtures/developers.yml +22 -22
  301. data/test/fixtures/developers_projects.yml +16 -16
  302. data/test/fixtures/dog_lovers.yml +7 -7
  303. data/test/fixtures/dogs.yml +4 -4
  304. data/test/fixtures/doubloons.yml +3 -3
  305. data/test/fixtures/edges.yml +5 -5
  306. data/test/fixtures/entrants.yml +14 -14
  307. data/test/fixtures/essays.yml +6 -6
  308. data/test/fixtures/faces.yml +11 -11
  309. data/test/fixtures/fk_test_has_fk.yml +3 -3
  310. data/test/fixtures/fk_test_has_pk.yml +1 -1
  311. data/test/fixtures/friendships.yml +4 -4
  312. data/test/fixtures/funny_jokes.yml +10 -10
  313. data/test/fixtures/interests.yml +33 -33
  314. data/test/fixtures/items.yml +3 -3
  315. data/test/fixtures/jobs.yml +7 -7
  316. data/test/fixtures/legacy_things.yml +3 -3
  317. data/test/fixtures/live_parrots.yml +4 -0
  318. data/test/fixtures/mateys.yml +4 -4
  319. data/test/fixtures/member_details.yml +8 -8
  320. data/test/fixtures/member_types.yml +6 -6
  321. data/test/fixtures/members.yml +11 -11
  322. data/test/fixtures/memberships.yml +34 -34
  323. data/test/fixtures/men.yml +5 -5
  324. data/test/fixtures/minimalistics.yml +2 -2
  325. data/test/fixtures/minivans.yml +5 -5
  326. data/test/fixtures/mixed_case_monkeys.yml +6 -6
  327. data/test/fixtures/mixins.yml +29 -29
  328. data/test/fixtures/movies.yml +7 -7
  329. data/test/fixtures/naked/yml/accounts.yml +1 -1
  330. data/test/fixtures/naked/yml/companies.yml +1 -1
  331. data/test/fixtures/naked/yml/courses.yml +1 -1
  332. data/test/fixtures/naked/yml/parrots.yml +2 -0
  333. data/test/fixtures/naked/yml/trees.yml +3 -0
  334. data/test/fixtures/nodes.yml +29 -0
  335. data/test/fixtures/organizations.yml +5 -5
  336. data/test/fixtures/other_comments.yml +6 -0
  337. data/test/fixtures/other_dogs.yml +2 -0
  338. data/test/fixtures/other_posts.yml +7 -0
  339. data/test/fixtures/other_topics.yml +42 -42
  340. data/test/fixtures/owners.yml +9 -9
  341. data/test/fixtures/parrots.yml +27 -27
  342. data/test/fixtures/parrots_pirates.yml +7 -7
  343. data/test/fixtures/people.yml +24 -24
  344. data/test/fixtures/peoples_treasures.yml +3 -3
  345. data/test/fixtures/pets.yml +19 -19
  346. data/test/fixtures/pirates.yml +15 -12
  347. data/test/fixtures/posts.yml +80 -80
  348. data/test/fixtures/price_estimates.yml +16 -7
  349. data/test/fixtures/products.yml +4 -4
  350. data/test/fixtures/projects.yml +7 -7
  351. data/test/fixtures/ratings.yml +14 -14
  352. data/test/fixtures/readers.yml +11 -11
  353. data/test/fixtures/references.yml +17 -17
  354. data/test/fixtures/reserved_words/distinct.yml +5 -5
  355. data/test/fixtures/reserved_words/distinct_select.yml +11 -11
  356. data/test/fixtures/reserved_words/group.yml +14 -14
  357. data/test/fixtures/reserved_words/select.yml +8 -8
  358. data/test/fixtures/reserved_words/values.yml +7 -7
  359. data/test/fixtures/ships.yml +6 -6
  360. data/test/fixtures/speedometers.yml +8 -8
  361. data/test/fixtures/sponsors.yml +12 -12
  362. data/test/fixtures/string_key_objects.yml +7 -7
  363. data/test/fixtures/subscribers.yml +10 -10
  364. data/test/fixtures/subscriptions.yml +12 -12
  365. data/test/fixtures/taggings.yml +78 -78
  366. data/test/fixtures/tags.yml +11 -11
  367. data/test/fixtures/tasks.yml +7 -7
  368. data/test/fixtures/teapots.yml +3 -3
  369. data/test/fixtures/to_be_linked/accounts.yml +2 -2
  370. data/test/fixtures/to_be_linked/users.yml +10 -10
  371. data/test/fixtures/topics.yml +49 -49
  372. data/test/fixtures/toys.yml +14 -14
  373. data/test/fixtures/traffic_lights.yml +9 -9
  374. data/test/fixtures/treasures.yml +10 -10
  375. data/test/fixtures/trees.yml +3 -0
  376. data/test/fixtures/uuid_children.yml +3 -3
  377. data/test/fixtures/uuid_parents.yml +2 -2
  378. data/test/fixtures/variants.yml +4 -4
  379. data/test/fixtures/vegetables.yml +19 -19
  380. data/test/fixtures/vertices.yml +3 -3
  381. data/test/fixtures/warehouse_things.yml +2 -2
  382. data/test/fixtures/zines.yml +5 -5
  383. data/test/migrations/10_urban/9_add_expressions.rb +11 -11
  384. data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
  385. data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
  386. data/test/migrations/missing/1000_people_have_middle_names.rb +9 -9
  387. data/test/migrations/missing/1_people_have_last_names.rb +9 -9
  388. data/test/migrations/missing/3_we_need_reminders.rb +12 -12
  389. data/test/migrations/missing/4_innocent_jointable.rb +12 -12
  390. data/test/migrations/rename/1_we_need_things.rb +11 -11
  391. data/test/migrations/rename/2_rename_things.rb +9 -9
  392. data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
  393. data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
  394. data/test/migrations/to_copy2/1_create_articles.rb +7 -7
  395. data/test/migrations/to_copy2/2_create_comments.rb +7 -7
  396. data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
  397. data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
  398. data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
  399. data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
  400. data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
  401. data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
  402. data/test/migrations/valid/2_we_need_reminders.rb +12 -12
  403. data/test/migrations/valid/3_innocent_jointable.rb +12 -12
  404. data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
  405. data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +12 -12
  406. data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +12 -12
  407. data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
  408. data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
  409. data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
  410. data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
  411. data/test/models/admin.rb +5 -5
  412. data/test/models/admin/account.rb +3 -3
  413. data/test/models/admin/randomly_named_c1.rb +6 -2
  414. data/test/models/admin/user.rb +40 -40
  415. data/test/models/aircraft.rb +5 -4
  416. data/test/models/arunit2_model.rb +3 -3
  417. data/test/models/author.rb +209 -212
  418. data/test/models/auto_id.rb +4 -4
  419. data/test/models/autoloadable/extra_firm.rb +2 -2
  420. data/test/models/binary.rb +2 -2
  421. data/test/models/bird.rb +12 -12
  422. data/test/models/book.rb +23 -18
  423. data/test/models/boolean.rb +2 -2
  424. data/test/models/bulb.rb +52 -51
  425. data/test/models/cake_designer.rb +3 -3
  426. data/test/models/car.rb +29 -26
  427. data/test/models/carrier.rb +2 -2
  428. data/test/models/cat.rb +10 -0
  429. data/test/models/categorization.rb +19 -19
  430. data/test/models/category.rb +35 -35
  431. data/test/models/chef.rb +8 -7
  432. data/test/models/citation.rb +3 -3
  433. data/test/models/club.rb +25 -23
  434. data/test/models/college.rb +10 -10
  435. data/test/models/column.rb +3 -3
  436. data/test/models/column_name.rb +3 -3
  437. data/test/models/comment.rb +76 -64
  438. data/test/models/company.rb +230 -228
  439. data/test/models/company_in_module.rb +98 -98
  440. data/test/models/computer.rb +3 -3
  441. data/test/models/contact.rb +41 -41
  442. data/test/models/content.rb +40 -0
  443. data/test/models/contract.rb +20 -20
  444. data/test/models/country.rb +7 -7
  445. data/test/models/course.rb +6 -6
  446. data/test/models/customer.rb +83 -77
  447. data/test/models/customer_carrier.rb +14 -14
  448. data/test/models/dashboard.rb +3 -3
  449. data/test/models/default.rb +2 -2
  450. data/test/models/department.rb +4 -4
  451. data/test/models/developer.rb +274 -255
  452. data/test/models/dog.rb +5 -5
  453. data/test/models/dog_lover.rb +5 -5
  454. data/test/models/doubloon.rb +12 -12
  455. data/test/models/drink_designer.rb +3 -3
  456. data/test/models/edge.rb +5 -5
  457. data/test/models/electron.rb +5 -5
  458. data/test/models/engine.rb +4 -4
  459. data/test/models/entrant.rb +3 -3
  460. data/test/models/essay.rb +5 -5
  461. data/test/models/event.rb +3 -3
  462. data/test/models/eye.rb +37 -37
  463. data/test/models/face.rb +9 -9
  464. data/test/models/friendship.rb +6 -6
  465. data/test/models/guid.rb +2 -2
  466. data/test/models/guitar.rb +4 -0
  467. data/test/models/hotel.rb +11 -9
  468. data/test/models/image.rb +3 -3
  469. data/test/models/interest.rb +5 -5
  470. data/test/models/invoice.rb +4 -4
  471. data/test/models/item.rb +7 -7
  472. data/test/models/job.rb +7 -7
  473. data/test/models/joke.rb +7 -7
  474. data/test/models/keyboard.rb +3 -3
  475. data/test/models/legacy_thing.rb +3 -3
  476. data/test/models/lesson.rb +11 -11
  477. data/test/models/line_item.rb +3 -3
  478. data/test/models/liquid.rb +4 -4
  479. data/test/models/man.rb +11 -11
  480. data/test/models/matey.rb +4 -4
  481. data/test/models/member.rb +42 -41
  482. data/test/models/member_detail.rb +8 -7
  483. data/test/models/member_type.rb +3 -3
  484. data/test/models/membership.rb +35 -35
  485. data/test/models/mentor.rb +3 -0
  486. data/test/models/minimalistic.rb +2 -2
  487. data/test/models/minivan.rb +9 -9
  488. data/test/models/mixed_case_monkey.rb +3 -3
  489. data/test/models/mocktail_designer.rb +2 -0
  490. data/test/models/molecule.rb +6 -6
  491. data/test/models/movie.rb +5 -5
  492. data/test/models/node.rb +5 -0
  493. data/test/models/non_primary_key.rb +2 -0
  494. data/test/models/notification.rb +3 -0
  495. data/test/models/order.rb +4 -4
  496. data/test/models/organization.rb +14 -14
  497. data/test/models/other_dog.rb +5 -0
  498. data/test/models/owner.rb +37 -34
  499. data/test/models/parrot.rb +28 -29
  500. data/test/models/person.rb +142 -143
  501. data/test/models/personal_legacy_thing.rb +4 -4
  502. data/test/models/pet.rb +18 -15
  503. data/test/models/pet_treasure.rb +6 -0
  504. data/test/models/pirate.rb +92 -92
  505. data/test/models/possession.rb +3 -3
  506. data/test/models/post.rb +273 -264
  507. data/test/models/price_estimate.rb +4 -4
  508. data/test/models/professor.rb +5 -5
  509. data/test/models/project.rb +40 -31
  510. data/test/models/publisher.rb +2 -2
  511. data/test/models/publisher/article.rb +4 -4
  512. data/test/models/publisher/magazine.rb +3 -3
  513. data/test/models/randomly_named_c1.rb +1 -1
  514. data/test/models/rating.rb +4 -4
  515. data/test/models/reader.rb +23 -23
  516. data/test/models/recipe.rb +3 -0
  517. data/test/models/record.rb +2 -2
  518. data/test/models/reference.rb +22 -22
  519. data/test/models/reply.rb +61 -61
  520. data/test/models/ship.rb +39 -33
  521. data/test/models/ship_part.rb +8 -8
  522. data/test/models/shop.rb +17 -17
  523. data/test/models/shop_account.rb +6 -6
  524. data/test/models/speedometer.rb +6 -6
  525. data/test/models/sponsor.rb +7 -7
  526. data/test/models/string_key_object.rb +3 -3
  527. data/test/models/student.rb +4 -4
  528. data/test/models/subject.rb +16 -16
  529. data/test/models/subscriber.rb +8 -8
  530. data/test/models/subscription.rb +4 -4
  531. data/test/models/tag.rb +13 -7
  532. data/test/models/tagging.rb +13 -13
  533. data/test/models/task.rb +5 -5
  534. data/test/models/topic.rb +118 -124
  535. data/test/models/toy.rb +6 -6
  536. data/test/models/traffic_light.rb +4 -4
  537. data/test/models/treasure.rb +14 -14
  538. data/test/models/treaty.rb +7 -7
  539. data/test/models/tree.rb +3 -0
  540. data/test/models/tuning_peg.rb +4 -0
  541. data/test/models/tyre.rb +11 -11
  542. data/test/models/user.rb +14 -0
  543. data/test/models/uuid_child.rb +3 -3
  544. data/test/models/uuid_item.rb +6 -0
  545. data/test/models/uuid_parent.rb +3 -3
  546. data/test/models/vegetables.rb +24 -24
  547. data/test/models/vehicle.rb +6 -6
  548. data/test/models/vertex.rb +9 -9
  549. data/test/models/warehouse_thing.rb +5 -5
  550. data/test/models/wheel.rb +3 -3
  551. data/test/models/without_table.rb +3 -3
  552. data/test/models/zine.rb +3 -3
  553. data/test/schema/mysql2_specific_schema.rb +68 -58
  554. data/test/schema/oracle_specific_schema.rb +40 -43
  555. data/test/schema/postgresql_specific_schema.rb +114 -202
  556. data/test/schema/schema.rb +1057 -952
  557. data/test/schema/schema.rb.original +1057 -0
  558. data/test/schema/sqlite_specific_schema.rb +18 -22
  559. data/test/support/config.rb +43 -43
  560. data/test/support/connection.rb +23 -22
  561. data/test/support/connection_helper.rb +14 -14
  562. data/test/support/ddl_helper.rb +8 -8
  563. data/test/support/schema_dumping_helper.rb +20 -20
  564. data/test/support/yaml_compatibility_fixtures/rails_4_1.yml +22 -0
  565. data/test/support/yaml_compatibility_fixtures/rails_4_2_0.yml +182 -0
  566. metadata +129 -28
  567. data/lib/mswin32/rb19x/ibm_db.so +0 -0
  568. data/lib/mswin32/rb21x/i386/ibm_db.so +0 -0
  569. data/lib/mswin32/rb22x/i386/ibm_db.so +0 -0
  570. data/lib/mswin32/rb23x/i386/ibm_db.so +0 -0
  571. data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +0 -26
  572. data/test/cases/attribute_methods/serialization_test.rb +0 -29
  573. data/test/cases/migration/change_schema_test - Copy.rb +0 -448
  574. data/test/cases/migration/foreign_key_test - Changed.rb +0 -325
  575. data/test/cases/migration/table_and_index_test.rb +0 -24
  576. data/test/cases/relation/where_test2.rb +0 -36
  577. data/test/cases/type/decimal_test.rb +0 -56
  578. data/test/cases/type/unsigned_integer_test.rb +0 -18
  579. data/test/cases/xml_serialization_test.rb +0 -457
  580. data/test/connections/native_ibm_db/connection.rb +0 -44
  581. data/test/fixtures/naked/csv/accounts.csv +0 -1
  582. data/test/schema/i5/ibm_db_specific_schema.rb +0 -137
  583. data/test/schema/ids/ibm_db_specific_schema.rb +0 -140
  584. data/test/schema/luw/ibm_db_specific_schema.rb +0 -137
  585. data/test/schema/mysql_specific_schema.rb +0 -70
  586. data/test/schema/zOS/ibm_db_specific_schema.rb +0 -208
@@ -0,0 +1,16 @@
1
+ require_relative "../cases/helper"
2
+
3
+ class ErrorsTest < ActiveRecord::TestCase
4
+ def test_can_be_instantiated_with_no_args
5
+ base = ActiveRecord::ActiveRecordError
6
+ error_klasses = ObjectSpace.each_object(Class).select { |klass| klass < base }
7
+
8
+ error_klasses.each do |error_klass|
9
+ begin
10
+ error_klass.new.inspect
11
+ rescue ArgumentError
12
+ raise "Instance of #{error_klass} can't be initialized with no arguments"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,64 +1,64 @@
1
- require 'cases/helper'
2
- require 'active_record/explain_subscriber'
3
- require 'active_record/explain_registry'
4
-
5
- if ActiveRecord::Base.connection.supports_explain?
6
- class ExplainSubscriberTest < ActiveRecord::TestCase
7
- SUBSCRIBER = ActiveRecord::ExplainSubscriber.new
8
-
9
- def setup
10
- ActiveRecord::ExplainRegistry.reset
11
- ActiveRecord::ExplainRegistry.collect = true
12
- end
13
-
14
- def test_collects_nothing_if_the_payload_has_an_exception
15
- SUBSCRIBER.finish(nil, nil, exception: Exception.new)
16
- assert queries.empty?
17
- end
18
-
19
- def test_collects_nothing_for_ignored_payloads
20
- ActiveRecord::ExplainSubscriber::IGNORED_PAYLOADS.each do |ip|
21
- SUBSCRIBER.finish(nil, nil, name: ip)
22
- end
23
- assert queries.empty?
24
- end
25
-
26
- def test_collects_nothing_if_collect_is_false
27
- ActiveRecord::ExplainRegistry.collect = false
28
- SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'select 1 from users', binds: [1, 2])
29
- assert queries.empty?
30
- end
31
-
32
- def test_collects_pairs_of_queries_and_binds
33
- sql = 'select 1 from users'
34
- binds = [1, 2]
35
- SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: sql, binds: binds)
36
- assert_equal 1, queries.size
37
- assert_equal sql, queries[0][0]
38
- assert_equal binds, queries[0][1]
39
- end
40
-
41
- def test_collects_nothing_if_the_statement_is_not_whitelisted
42
- SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'SHOW max_identifier_length')
43
- assert queries.empty?
44
- end
45
-
46
- def test_collects_nothing_if_the_statement_is_only_partially_matched
47
- SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'select_db yo_mama')
48
- assert queries.empty?
49
- end
50
-
51
- def test_collects_cte_queries
52
- SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'with s as (values(3)) select 1 from s')
53
- assert_equal 1, queries.size
54
- end
55
-
56
- teardown do
57
- ActiveRecord::ExplainRegistry.reset
58
- end
59
-
60
- def queries
61
- ActiveRecord::ExplainRegistry.queries
62
- end
63
- end
64
- end
1
+ require 'cases/helper'
2
+ require 'active_record/explain_subscriber'
3
+ require 'active_record/explain_registry'
4
+
5
+ if ActiveRecord::Base.connection.supports_explain?
6
+ class ExplainSubscriberTest < ActiveRecord::TestCase
7
+ SUBSCRIBER = ActiveRecord::ExplainSubscriber.new
8
+
9
+ def setup
10
+ ActiveRecord::ExplainRegistry.reset
11
+ ActiveRecord::ExplainRegistry.collect = true
12
+ end
13
+
14
+ def test_collects_nothing_if_the_payload_has_an_exception
15
+ SUBSCRIBER.finish(nil, nil, exception: Exception.new)
16
+ assert queries.empty?
17
+ end
18
+
19
+ def test_collects_nothing_for_ignored_payloads
20
+ ActiveRecord::ExplainSubscriber::IGNORED_PAYLOADS.each do |ip|
21
+ SUBSCRIBER.finish(nil, nil, name: ip)
22
+ end
23
+ assert queries.empty?
24
+ end
25
+
26
+ def test_collects_nothing_if_collect_is_false
27
+ ActiveRecord::ExplainRegistry.collect = false
28
+ SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'select 1 from users', binds: [1, 2])
29
+ assert queries.empty?
30
+ end
31
+
32
+ def test_collects_pairs_of_queries_and_binds
33
+ sql = 'select 1 from users'
34
+ binds = [1, 2]
35
+ SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: sql, binds: binds)
36
+ assert_equal 1, queries.size
37
+ assert_equal sql, queries[0][0]
38
+ assert_equal binds, queries[0][1]
39
+ end
40
+
41
+ def test_collects_nothing_if_the_statement_is_not_whitelisted
42
+ SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'SHOW max_identifier_length')
43
+ assert queries.empty?
44
+ end
45
+
46
+ def test_collects_nothing_if_the_statement_is_only_partially_matched
47
+ SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'select_db yo_mama')
48
+ assert queries.empty?
49
+ end
50
+
51
+ def test_collects_cte_queries
52
+ SUBSCRIBER.finish(nil, nil, name: 'SQL', sql: 'with s as (values(3)) select 1 from s')
53
+ assert_equal 1, queries.size
54
+ end
55
+
56
+ teardown do
57
+ ActiveRecord::ExplainRegistry.reset
58
+ end
59
+
60
+ def queries
61
+ ActiveRecord::ExplainRegistry.queries
62
+ end
63
+ end
64
+ end
@@ -1,76 +1,87 @@
1
- require 'cases/helper'
2
- require 'models/car'
3
- require 'active_support/core_ext/string/strip'
4
-
5
- if ActiveRecord::Base.connection.supports_explain?
6
- class ExplainTest < ActiveRecord::TestCase
7
- fixtures :cars
8
-
9
- def base
10
- ActiveRecord::Base
11
- end
12
-
13
- def connection
14
- base.connection
15
- end
16
-
17
- def test_relation_explain
18
- message = Car.where(:name => 'honda').explain
19
- assert_match(/^EXPLAIN for:/, message)
20
- end
21
-
22
- def test_collecting_queries_for_explain
23
- queries = ActiveRecord::Base.collecting_queries_for_explain do
24
- Car.where(:name => 'honda').to_a
25
- end
26
-
27
- sql, binds = queries[0]
28
- assert_match "SELECT", sql
29
- if binds.any?
30
- assert_equal 1, binds.length
31
- assert_equal "honda", binds.flatten.last
32
- else
33
- assert_match 'honda', sql
34
- end
35
- end
36
-
37
- def test_exec_explain_with_no_binds
38
- sqls = %w(foo bar)
39
- binds = [[], []]
40
- queries = sqls.zip(binds)
41
-
42
- connection.stubs(:explain).returns('query plan foo', 'query plan bar')
43
- expected = sqls.map {|sql| "EXPLAIN for: #{sql}\nquery plan #{sql}"}.join("\n")
44
- assert_equal expected, base.exec_explain(queries)
45
- end
46
-
47
- def test_exec_explain_with_binds
48
- cols = [Object.new, Object.new]
49
- cols[0].expects(:name).returns('wadus')
50
- cols[1].expects(:name).returns('chaflan')
51
-
52
- sqls = %w(foo bar)
53
- binds = [[[cols[0], 1]], [[cols[1], 2]]]
54
- queries = sqls.zip(binds)
55
-
56
- connection.stubs(:explain).returns("query plan foo\n", "query plan bar\n")
57
- expected = <<-SQL.strip_heredoc
58
- EXPLAIN for: #{sqls[0]} [["wadus", 1]]
59
- query plan foo
60
-
61
- EXPLAIN for: #{sqls[1]} [["chaflan", 2]]
62
- query plan bar
63
- SQL
64
- assert_equal expected, base.exec_explain(queries)
65
- end
66
-
67
- def test_unsupported_connection_adapter
68
- connection.stubs(:supports_explain?).returns(false)
69
-
70
- base.logger.expects(:warn).never
71
-
72
- Car.where(:name => 'honda').to_a
73
- end
74
-
75
- end
76
- end
1
+ require 'cases/helper'
2
+ require 'models/car'
3
+ require 'active_support/core_ext/string/strip'
4
+
5
+ if ActiveRecord::Base.connection.supports_explain?
6
+ class ExplainTest < ActiveRecord::TestCase
7
+ fixtures :cars
8
+
9
+ def base
10
+ ActiveRecord::Base
11
+ end
12
+
13
+ def connection
14
+ base.connection
15
+ end
16
+
17
+ def test_relation_explain
18
+ message = Car.where(:name => 'honda').explain
19
+ assert_match(/^EXPLAIN for:/, message)
20
+ end
21
+
22
+ def test_collecting_queries_for_explain
23
+ queries = ActiveRecord::Base.collecting_queries_for_explain do
24
+ Car.where(:name => 'honda').to_a
25
+ end
26
+
27
+ sql, binds = queries[0]
28
+ assert_match "SELECT", sql
29
+ if binds.any?
30
+ assert_equal 1, binds.length
31
+ assert_equal "honda", binds.last.value
32
+ else
33
+ assert_match 'honda', sql
34
+ end
35
+ end
36
+
37
+ def test_exec_explain_with_no_binds
38
+ sqls = %w(foo bar)
39
+ binds = [[], []]
40
+ queries = sqls.zip(binds)
41
+
42
+ stub_explain_for_query_plans do
43
+ expected = sqls.map {|sql| "EXPLAIN for: #{sql}\nquery plan #{sql}"}.join("\n")
44
+ assert_equal expected, base.exec_explain(queries)
45
+ end
46
+ end
47
+
48
+ def test_exec_explain_with_binds
49
+ sqls = %w(foo bar)
50
+ binds = [[bind_param("wadus", 1)], [bind_param("chaflan", 2)]]
51
+ queries = sqls.zip(binds)
52
+
53
+ stub_explain_for_query_plans(["query plan foo\n", "query plan bar\n"]) do
54
+ expected = <<-SQL.strip_heredoc
55
+ EXPLAIN for: #{sqls[0]} [["wadus", 1]]
56
+ query plan foo
57
+
58
+ EXPLAIN for: #{sqls[1]} [["chaflan", 2]]
59
+ query plan bar
60
+ SQL
61
+ assert_equal expected, base.exec_explain(queries)
62
+ end
63
+ end
64
+
65
+ def test_unsupported_connection_adapter
66
+ connection.stub(:supports_explain?, false) do
67
+ assert_not_called(base.logger, :warn) do
68
+ Car.where(:name => 'honda').to_a
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ def stub_explain_for_query_plans(query_plans = ['query plan foo', 'query plan bar'])
76
+ explain_called = 0
77
+
78
+ connection.stub(:explain, proc{ explain_called += 1; query_plans[explain_called - 1] }) do
79
+ yield
80
+ end
81
+ end
82
+
83
+ def bind_param(name, value)
84
+ ActiveRecord::Relation::QueryAttribute.new(name, value, ActiveRecord::Type::Value.new)
85
+ end
86
+ end
87
+ end
@@ -1,60 +1,60 @@
1
- require "cases/helper"
2
- require 'models/topic'
3
-
4
- class FinderRespondToTest < ActiveRecord::TestCase
5
-
6
- fixtures :topics
7
-
8
- def test_should_preserve_normal_respond_to_behaviour_on_base
9
- assert_respond_to ActiveRecord::Base, :new
10
- assert !ActiveRecord::Base.respond_to?(:find_by_something)
11
- end
12
-
13
- def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method
14
- class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { }
15
- assert_respond_to Topic, :method_added_for_finder_respond_to_test
16
- ensure
17
- class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test)
18
- end
19
-
20
- def test_should_preserve_normal_respond_to_behaviour_and_respond_to_standard_object_method
21
- assert_respond_to Topic, :to_s
22
- end
23
-
24
- def test_should_respond_to_find_by_one_attribute_before_caching
25
- ensure_topic_method_is_not_cached(:find_by_title)
26
- assert_respond_to Topic, :find_by_title
27
- end
28
-
29
- def test_should_respond_to_find_by_with_bang
30
- ensure_topic_method_is_not_cached(:find_by_title!)
31
- assert_respond_to Topic, :find_by_title!
32
- end
33
-
34
- def test_should_respond_to_find_by_two_attributes
35
- ensure_topic_method_is_not_cached(:find_by_title_and_author_name)
36
- assert_respond_to Topic, :find_by_title_and_author_name
37
- end
38
-
39
- def test_should_respond_to_find_all_by_an_aliased_attribute
40
- ensure_topic_method_is_not_cached(:find_by_heading)
41
- assert_respond_to Topic, :find_by_heading
42
- end
43
-
44
- def test_should_not_respond_to_find_by_one_missing_attribute
45
- assert !Topic.respond_to?(:find_by_undertitle)
46
- end
47
-
48
- def test_should_not_respond_to_find_by_invalid_method_syntax
49
- assert !Topic.respond_to?(:fail_to_find_by_title)
50
- assert !Topic.respond_to?(:find_by_title?)
51
- assert !Topic.respond_to?(:fail_to_find_or_create_by_title)
52
- assert !Topic.respond_to?(:find_or_create_by_title?)
53
- end
54
-
55
- private
56
-
57
- def ensure_topic_method_is_not_cached(method_id)
58
- class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.include? method_id
59
- end
60
- end
1
+ require "cases/helper"
2
+ require 'models/topic'
3
+
4
+ class FinderRespondToTest < ActiveRecord::TestCase
5
+
6
+ fixtures :topics
7
+
8
+ def test_should_preserve_normal_respond_to_behaviour_on_base
9
+ assert_respond_to ActiveRecord::Base, :new
10
+ assert !ActiveRecord::Base.respond_to?(:find_by_something)
11
+ end
12
+
13
+ def test_should_preserve_normal_respond_to_behaviour_and_respond_to_newly_added_method
14
+ class << Topic; self; end.send(:define_method, :method_added_for_finder_respond_to_test) { }
15
+ assert_respond_to Topic, :method_added_for_finder_respond_to_test
16
+ ensure
17
+ class << Topic; self; end.send(:remove_method, :method_added_for_finder_respond_to_test)
18
+ end
19
+
20
+ def test_should_preserve_normal_respond_to_behaviour_and_respond_to_standard_object_method
21
+ assert_respond_to Topic, :to_s
22
+ end
23
+
24
+ def test_should_respond_to_find_by_one_attribute_before_caching
25
+ ensure_topic_method_is_not_cached(:find_by_title)
26
+ assert_respond_to Topic, :find_by_title
27
+ end
28
+
29
+ def test_should_respond_to_find_by_with_bang
30
+ ensure_topic_method_is_not_cached(:find_by_title!)
31
+ assert_respond_to Topic, :find_by_title!
32
+ end
33
+
34
+ def test_should_respond_to_find_by_two_attributes
35
+ ensure_topic_method_is_not_cached(:find_by_title_and_author_name)
36
+ assert_respond_to Topic, :find_by_title_and_author_name
37
+ end
38
+
39
+ def test_should_respond_to_find_all_by_an_aliased_attribute
40
+ ensure_topic_method_is_not_cached(:find_by_heading)
41
+ assert_respond_to Topic, :find_by_heading
42
+ end
43
+
44
+ def test_should_not_respond_to_find_by_one_missing_attribute
45
+ assert !Topic.respond_to?(:find_by_undertitle)
46
+ end
47
+
48
+ def test_should_not_respond_to_find_by_invalid_method_syntax
49
+ assert !Topic.respond_to?(:fail_to_find_by_title)
50
+ assert !Topic.respond_to?(:find_by_title?)
51
+ assert !Topic.respond_to?(:fail_to_find_or_create_by_title)
52
+ assert !Topic.respond_to?(:find_or_create_by_title?)
53
+ end
54
+
55
+ private
56
+
57
+ def ensure_topic_method_is_not_cached(method_id)
58
+ class << Topic; self; end.send(:remove_method, method_id) if Topic.public_methods.include? method_id
59
+ end
60
+ end
@@ -1,1169 +1,1294 @@
1
- require "cases/helper"
2
- require 'models/post'
3
- require 'models/author'
4
- require 'models/categorization'
5
- require 'models/comment'
6
- require 'models/company'
7
- require 'models/tagging'
8
- require 'models/topic'
9
- require 'models/reply'
10
- require 'models/entrant'
11
- require 'models/project'
12
- require 'models/developer'
13
- require 'models/computer'
14
- require 'models/customer'
15
- require 'models/toy'
16
- require 'models/matey'
17
- require 'models/dog'
18
- require 'models/car'
19
- require 'models/tyre'
20
-
21
- class FinderTest < ActiveRecord::TestCase
22
- fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :author_addresses, :customers, :categories, :categorizations, :cars
23
-
24
- def test_find_by_id_with_hash
25
- assert_raises(ActiveRecord::StatementInvalid) do
26
- Post.find_by_id(:limit => 1)
27
- end
28
- end
29
-
30
- def test_find_by_title_and_id_with_hash
31
- assert_raises(ActiveRecord::StatementInvalid) do
32
- Post.find_by_title_and_id('foo', :limit => 1)
33
- end
34
- end
35
-
36
- def test_find
37
- assert_equal(topics(:first).title, Topic.find(1).title)
38
- end
39
-
40
- def test_find_with_proc_parameter_and_block
41
- exception = assert_raises(RuntimeError) do
42
- Topic.all.find(-> { raise "should happen" }) { |e| e.title == "non-existing-title" }
43
- end
44
- assert_equal "should happen", exception.message
45
-
46
- assert_nothing_raised(RuntimeError) do
47
- Topic.all.find(-> { raise "should not happen" }) { |e| e.title == topics(:first).title }
48
- end
49
- end
50
-
51
- def test_find_passing_active_record_object_is_deprecated
52
- assert_deprecated do
53
- Topic.find(Topic.last)
54
- end
55
- end
56
-
57
- def test_symbols_table_ref
58
- gc_disabled = GC.disable
59
- Post.where("author_id" => nil) # warm up
60
- x = Symbol.all_symbols.count
61
- Post.where("title" => {"xxxqqqq" => "bar"})
62
- assert_equal x, Symbol.all_symbols.count
63
- ensure
64
- GC.enable if gc_disabled == false
65
- end
66
-
67
- # find should handle strings that come from URLs
68
- # (example: Category.find(params[:id]))
69
- def test_find_with_string
70
- assert_equal(Topic.find(1).title,Topic.find("1").title)
71
- end
72
-
73
- def test_exists
74
- assert_equal true, Topic.exists?(1)
75
- assert_equal true, Topic.exists?("1")
76
- assert_equal true, Topic.exists?(title: "The First Topic")
77
- assert_equal true, Topic.exists?(heading: "The First Topic")
78
- assert_equal true, Topic.exists?(:author_name => "Mary", :approved => true)
79
- assert_equal true, Topic.exists?(["parent_id = ?", 1])
80
- assert_equal true, Topic.exists?(id: [1, 9999])
81
-
82
- assert_equal false, Topic.exists?(45)
83
- assert_equal false, Topic.exists?(Topic.new.id)
84
-
85
- assert_raise(NoMethodError) { Topic.exists?([1,2]) }
86
- end
87
-
88
- def test_exists_with_polymorphic_relation
89
- post = Post.create!(title: 'Post', body: 'default', taggings: [Tagging.new(comment: 'tagging comment')])
90
- relation = Post.tagged_with_comment('tagging comment')
91
-
92
- assert_equal true, relation.exists?(title: ['Post'])
93
- assert_equal true, relation.exists?(['title LIKE ?', 'Post%'])
94
- assert_equal true, relation.exists?
95
- assert_equal true, relation.exists?(post.id)
96
- assert_equal true, relation.exists?(post.id.to_s)
97
-
98
- assert_equal false, relation.exists?(false)
99
- end
100
-
101
- def test_exists_passing_active_record_object_is_deprecated
102
- assert_deprecated do
103
- Topic.exists?(Topic.new)
104
- end
105
- end
106
-
107
- def test_exists_fails_when_parameter_has_invalid_type
108
- assert_raises(RangeError) do
109
- assert_equal false, Topic.exists?(("9"*53).to_i) # number that's bigger than int
110
- end
111
- assert_equal false, Topic.exists?("foo")
112
- end
113
-
114
- def test_exists_does_not_select_columns_without_alias
115
- assert_sql(/SELECT\W+1 AS one FROM ["`]topics["`]/i) do
116
- Topic.exists?
117
- end
118
- end
119
-
120
- def test_exists_returns_true_with_one_record_and_no_args
121
- assert_equal true, Topic.exists?
122
- end
123
-
124
- def test_exists_returns_false_with_false_arg
125
- assert_equal false, Topic.exists?(false)
126
- end
127
-
128
- # exists? should handle nil for id's that come from URLs and always return false
129
- # (example: Topic.exists?(params[:id])) where params[:id] is nil
130
- def test_exists_with_nil_arg
131
- assert_equal false, Topic.exists?(nil)
132
- assert_equal true, Topic.exists?
133
-
134
- assert_equal false, Topic.first.replies.exists?(nil)
135
- assert_equal true, Topic.first.replies.exists?
136
- end
137
-
138
- # ensures +exists?+ runs valid SQL by excluding order value
139
- def test_exists_with_order
140
- assert_equal true, Topic.order(:id).distinct.exists?
141
- end
142
-
143
- def test_exists_with_includes_limit_and_empty_result
144
- assert_equal false, Topic.includes(:replies).limit(0).exists?
145
- assert_equal false, Topic.includes(:replies).limit(1).where('0 = 1').exists?
146
- end
147
-
148
- def test_exists_with_distinct_association_includes_and_limit
149
- author = Author.first
150
- assert_equal false, author.unique_categorized_posts.includes(:special_comments).limit(0).exists?
151
- assert_equal true, author.unique_categorized_posts.includes(:special_comments).limit(1).exists?
152
- end
153
-
154
- def test_exists_with_distinct_association_includes_limit_and_order
155
- author = Author.first
156
- assert_equal false, author.unique_categorized_posts.includes(:special_comments).order('comments.tags_count DESC').limit(0).exists?
157
- assert_equal true, author.unique_categorized_posts.includes(:special_comments).order('comments.tags_count DESC').limit(1).exists?
158
- end
159
-
160
- def test_exists_with_empty_table_and_no_args_given
161
- Topic.delete_all
162
- assert_equal false, Topic.exists?
163
- end
164
-
165
- def test_exists_with_aggregate_having_three_mappings
166
- existing_address = customers(:david).address
167
- assert_equal true, Customer.exists?(:address => existing_address)
168
- end
169
-
170
- def test_exists_with_aggregate_having_three_mappings_with_one_difference
171
- existing_address = customers(:david).address
172
- assert_equal false, Customer.exists?(:address =>
173
- Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
174
- assert_equal false, Customer.exists?(:address =>
175
- Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
176
- assert_equal false, Customer.exists?(:address =>
177
- Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
178
- end
179
-
180
- def test_exists_does_not_instantiate_records
181
- Developer.expects(:instantiate).never
182
- Developer.exists?
183
- end
184
-
185
- def test_find_by_array_of_one_id
186
- assert_kind_of(Array, Topic.find([ 1 ]))
187
- assert_equal(1, Topic.find([ 1 ]).length)
188
- end
189
-
190
- def test_find_by_ids
191
- assert_equal 2, Topic.find(1, 2).size
192
- assert_equal topics(:second).title, Topic.find([2]).first.title
193
- end
194
-
195
- def test_find_by_ids_with_limit_and_offset
196
- assert_equal 2, Entrant.limit(2).find([1,3,2]).size
197
- assert_equal 1, Entrant.limit(3).offset(2).find([1,3,2]).size
198
-
199
- # Also test an edge case: If you have 11 results, and you set a
200
- # limit of 3 and offset of 9, then you should find that there
201
- # will be only 2 results, regardless of the limit.
202
- devs = Developer.all
203
- last_devs = Developer.limit(3).offset(9).find devs.map(&:id)
204
- assert_equal 2, last_devs.size
205
- end
206
-
207
- def test_find_with_large_number
208
- assert_raises(ActiveRecord::RecordNotFound) { Topic.find('9999999999999999999999999999999') }
209
- end
210
-
211
- def test_find_by_with_large_number
212
- assert_nil Topic.find_by(id: '9999999999999999999999999999999')
213
- end
214
-
215
- def test_find_by_id_with_large_number
216
- assert_nil Topic.find_by_id('9999999999999999999999999999999')
217
- end
218
-
219
- def test_find_on_relation_with_large_number
220
- assert_nil Topic.where('1=1').find_by(id: 9999999999999999999999999999999)
221
- end
222
-
223
- def test_find_by_bang_on_relation_with_large_number
224
- assert_raises(ActiveRecord::RecordNotFound) do
225
- Topic.where('1=1').find_by!(id: 9999999999999999999999999999999)
226
- end
227
- end
228
-
229
- def test_find_an_empty_array
230
- assert_equal [], Topic.find([])
231
- end
232
-
233
- def test_find_doesnt_have_implicit_ordering
234
- assert_sql(/^((?!ORDER).)*$/) { Topic.find(1) }
235
- end
236
-
237
- def test_find_by_ids_missing_one
238
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
239
- end
240
-
241
- def test_find_with_group_and_sanitized_having_method
242
- developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select('salary').to_a
243
- assert_equal 3, developers.size
244
- assert_equal 3, developers.map(&:salary).uniq.size
245
- assert developers.all? { |developer| developer.salary > 10000 }
246
- end
247
-
248
- def test_find_with_entire_select_statement
249
- topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
250
-
251
- assert_equal(1, topics.size)
252
- assert_equal(topics(:second).title, topics.first.title)
253
- end
254
-
255
- def test_find_with_prepared_select_statement
256
- topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
257
-
258
- assert_equal(1, topics.size)
259
- assert_equal(topics(:second).title, topics.first.title)
260
- end
261
-
262
- def test_find_by_sql_with_sti_on_joined_table
263
- accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
264
- assert_equal [Account], accounts.collect(&:class).uniq
265
- end
266
-
267
- def test_take
268
- assert_equal topics(:first), Topic.take
269
- end
270
-
271
- def test_take_failing
272
- assert_nil Topic.where("title = 'This title does not exist'").take
273
- end
274
-
275
- def test_take_bang_present
276
- assert_nothing_raised do
277
- assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").take!
278
- end
279
- end
280
-
281
- def test_take_bang_missing
282
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
283
- Topic.where("title = 'This title does not exist'").take!
284
- end
285
- end
286
-
287
- def test_first
288
- assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
289
- end
290
-
291
- def test_first_failing
292
- assert_nil Topic.where("title = 'The Second Topic of the day!'").first
293
- end
294
-
295
- def test_first_bang_present
296
- assert_nothing_raised do
297
- assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").first!
298
- end
299
- end
300
-
301
- def test_first_bang_missing
302
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
303
- Topic.where("title = 'This title does not exist'").first!
304
- end
305
- end
306
-
307
- def test_first_have_primary_key_order_by_default
308
- expected = topics(:first)
309
- expected.touch # PostgreSQL changes the default order if no order clause is used
310
- assert_equal expected, Topic.first
311
- end
312
-
313
- def test_model_class_responds_to_first_bang
314
- assert Topic.first!
315
- Topic.delete_all
316
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
317
- Topic.first!
318
- end
319
- end
320
-
321
- def test_second
322
- assert_equal topics(:second).title, Topic.second.title
323
- end
324
-
325
- def test_second_with_offset
326
- assert_equal topics(:fifth), Topic.offset(3).second
327
- end
328
-
329
- def test_second_have_primary_key_order_by_default
330
- expected = topics(:second)
331
- expected.touch # PostgreSQL changes the default order if no order clause is used
332
- assert_equal expected, Topic.second
333
- end
334
-
335
- def test_model_class_responds_to_second_bang
336
- assert Topic.second!
337
- Topic.delete_all
338
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
339
- Topic.second!
340
- end
341
- end
342
-
343
- def test_third
344
- assert_equal topics(:third).title, Topic.third.title
345
- end
346
-
347
- def test_third_with_offset
348
- assert_equal topics(:fifth), Topic.offset(2).third
349
- end
350
-
351
- def test_third_have_primary_key_order_by_default
352
- expected = topics(:third)
353
- expected.touch # PostgreSQL changes the default order if no order clause is used
354
- assert_equal expected, Topic.third
355
- end
356
-
357
- def test_model_class_responds_to_third_bang
358
- assert Topic.third!
359
- Topic.delete_all
360
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
361
- Topic.third!
362
- end
363
- end
364
-
365
- def test_fourth
366
- assert_equal topics(:fourth).title, Topic.fourth.title
367
- end
368
-
369
- def test_fourth_with_offset
370
- assert_equal topics(:fifth), Topic.offset(1).fourth
371
- end
372
-
373
- def test_fourth_have_primary_key_order_by_default
374
- expected = topics(:fourth)
375
- expected.touch # PostgreSQL changes the default order if no order clause is used
376
- assert_equal expected, Topic.fourth
377
- end
378
-
379
- def test_model_class_responds_to_fourth_bang
380
- assert Topic.fourth!
381
- Topic.delete_all
382
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
383
- Topic.fourth!
384
- end
385
- end
386
-
387
- def test_fifth
388
- assert_equal topics(:fifth).title, Topic.fifth.title
389
- end
390
-
391
- def test_fifth_with_offset
392
- assert_equal topics(:fifth), Topic.offset(0).fifth
393
- end
394
-
395
- def test_fifth_have_primary_key_order_by_default
396
- expected = topics(:fifth)
397
- expected.touch # PostgreSQL changes the default order if no order clause is used
398
- assert_equal expected, Topic.fifth
399
- end
400
-
401
- def test_model_class_responds_to_fifth_bang
402
- assert Topic.fifth!
403
- Topic.delete_all
404
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
405
- Topic.fifth!
406
- end
407
- end
408
-
409
- def test_last_bang_present
410
- assert_nothing_raised do
411
- assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").last!
412
- end
413
- end
414
-
415
- def test_last_bang_missing
416
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
417
- Topic.where("title = 'This title does not exist'").last!
418
- end
419
- end
420
-
421
- def test_model_class_responds_to_last_bang
422
- assert_equal topics(:fifth), Topic.last!
423
- assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
424
- Topic.delete_all
425
- Topic.last!
426
- end
427
- end
428
-
429
- def test_take_and_first_and_last_with_integer_should_use_sql_limit
430
- assert_sql(/LIMIT 3|ROWNUM <= 3/) { Topic.take(3).entries }
431
- assert_sql(/LIMIT 2|ROWNUM <= 2/) { Topic.first(2).entries }
432
- assert_sql(/LIMIT 5|ROWNUM <= 5/) { Topic.last(5).entries }
433
- end
434
-
435
- def test_last_with_integer_and_order_should_keep_the_order
436
- assert_equal Topic.order("title").to_a.last(2), Topic.order("title").last(2)
437
- end
438
-
439
- def test_last_with_integer_and_order_should_not_use_sql_limit
440
- query = assert_sql { Topic.order("title").last(5).entries }
441
- assert_equal 1, query.length
442
- assert_no_match(/LIMIT/, query.first)
443
- end
444
-
445
- def test_last_with_integer_and_reorder_should_not_use_sql_limit
446
- query = assert_sql { Topic.reorder("title").last(5).entries }
447
- assert_equal 1, query.length
448
- assert_no_match(/LIMIT/, query.first)
449
- end
450
-
451
- def test_take_and_first_and_last_with_integer_should_return_an_array
452
- assert_kind_of Array, Topic.take(5)
453
- assert_kind_of Array, Topic.first(5)
454
- assert_kind_of Array, Topic.last(5)
455
- end
456
-
457
- def test_unexisting_record_exception_handling
458
- assert_raise(ActiveRecord::RecordNotFound) {
459
- Topic.find(1).parent
460
- }
461
-
462
- Topic.find(2).topic
463
- end
464
-
465
- def test_find_only_some_columns
466
- topic = Topic.select("author_name").find(1)
467
- assert_raise(ActiveModel::MissingAttributeError) {topic.title}
468
- assert_raise(ActiveModel::MissingAttributeError) {topic.title?}
469
- assert_nil topic.read_attribute("title")
470
- assert_equal "David", topic.author_name
471
- assert !topic.attribute_present?("title")
472
- assert !topic.attribute_present?(:title)
473
- assert topic.attribute_present?("author_name")
474
- assert_respond_to topic, "author_name"
475
- end
476
-
477
- def test_find_on_array_conditions
478
- assert Topic.where(["approved = ?", false]).find(1)
479
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where(["approved = ?", true]).find(1) }
480
- end
481
-
482
- def test_find_on_hash_conditions
483
- assert Topic.where(approved: false).find(1)
484
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where(approved: true).find(1) }
485
- end
486
-
487
- def test_find_on_hash_conditions_with_explicit_table_name
488
- assert Topic.where('topics.approved' => false).find(1)
489
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => true).find(1) }
490
- end
491
-
492
- def test_find_on_hash_conditions_with_hashed_table_name
493
- assert Topic.where(topics: { approved: false }).find(1)
494
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where(topics: { approved: true }).find(1) }
495
- end
496
-
497
- def test_find_with_hash_conditions_on_joined_table
498
- firms = Firm.joins(:account).where(:accounts => { :credit_limit => 50 })
499
- assert_equal 1, firms.size
500
- assert_equal companies(:first_firm), firms.first
501
- end
502
-
503
- def test_find_with_hash_conditions_on_joined_table_and_with_range
504
- firms = DependentFirm.joins(:account).where(name: 'RailsCore', accounts: { credit_limit: 55..60 })
505
- assert_equal 1, firms.size
506
- assert_equal companies(:rails_core), firms.first
507
- end
508
-
509
- def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
510
- david = customers(:david)
511
- assert Customer.where('customers.name' => david.name, :address => david.address).find(david.id)
512
- assert_raise(ActiveRecord::RecordNotFound) {
513
- Customer.where('customers.name' => david.name + "1", :address => david.address).find(david.id)
514
- }
515
- end
516
-
517
- def test_find_on_association_proxy_conditions
518
- assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], Comment.where(post_id: authors(:david).posts).map(&:id).sort
519
- end
520
-
521
- def test_find_on_hash_conditions_with_range
522
- assert_equal [1,2], Topic.where(id: 1..2).to_a.map(&:id).sort
523
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2..3).find(1) }
524
- end
525
-
526
- def test_find_on_hash_conditions_with_end_exclusive_range
527
- assert_equal [1,2,3], Topic.where(id: 1..3).to_a.map(&:id).sort
528
- assert_equal [1,2], Topic.where(id: 1...3).to_a.map(&:id).sort
529
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2...3).find(3) }
530
- end
531
-
532
- def test_find_on_hash_conditions_with_multiple_ranges
533
- assert_equal [1,2,3], Comment.where(id: 1..3, post_id: 1..2).to_a.map(&:id).sort
534
- assert_equal [1], Comment.where(id: 1..1, post_id: 1..10).to_a.map(&:id).sort
535
- end
536
-
537
- def test_find_on_hash_conditions_with_array_of_integers_and_ranges
538
- assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [1..2, 3, 5, 6..8, 9]).to_a.map(&:id).sort
539
- end
540
-
541
- def test_find_on_hash_conditions_with_array_of_ranges
542
- assert_equal [1,2,6,7,8], Comment.where(id: [1..2, 6..8]).to_a.map(&:id).sort
543
- end
544
-
545
- def test_find_on_hash_conditions_with_nested_array_of_integers_and_ranges
546
- assert_deprecated do
547
- assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [[1..2], 3, [5], 6..8, 9]).to_a.map(&:id).sort
548
- end
549
- end
550
-
551
- def test_find_on_hash_conditions_with_array_of_integers_and_arrays
552
- assert_deprecated do
553
- assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [[1, 2], 3, 5, [6, [7], 8], 9]).to_a.map(&:id).sort
554
- end
555
- end
556
-
557
- def test_find_on_hash_conditions_with_nested_array_of_integers_and_ranges_and_nils
558
- assert_deprecated do
559
- assert_equal [1,3,4,5], Topic.where(parent_id: [[2..6], nil]).to_a.map(&:id).sort
560
- end
561
- end
562
-
563
- def test_find_on_hash_conditions_with_nested_array_of_integers_and_ranges_and_more_nils
564
- assert_deprecated do
565
- assert_equal [], Topic.where(parent_id: [[7..10, nil, [nil]], [nil]]).to_a.map(&:id).sort
566
- end
567
- end
568
-
569
- def test_find_on_multiple_hash_conditions
570
- assert Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: false).find(1)
571
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) }
572
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "HHC", replies_count: 1, approved: false).find(1) }
573
- assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) }
574
- end
575
-
576
- def test_condition_interpolation
577
- assert_kind_of Firm, Company.where("name = '%s'", "37signals").first
578
- assert_nil Company.where(["name = '%s'", "37signals!"]).first
579
- assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
580
- assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
581
- end
582
-
583
- def test_condition_array_interpolation
584
- assert_kind_of Firm, Company.where(["name = '%s'", "37signals"]).first
585
- assert_nil Company.where(["name = '%s'", "37signals!"]).first
586
- assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
587
- assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
588
- end
589
-
590
- def test_condition_hash_interpolation
591
- assert_kind_of Firm, Company.where(name: "37signals").first
592
- assert_nil Company.where(name: "37signals!").first
593
- assert_kind_of Time, Topic.where(id: 1).first.written_on
594
- end
595
-
596
- def test_hash_condition_find_malformed
597
- assert_raise(ActiveRecord::StatementInvalid) {
598
- Company.where(id: 2, dhh: true).first
599
- }
600
- end
601
-
602
- def test_hash_condition_find_with_escaped_characters
603
- Company.create("name" => "Ain't noth'n like' \#stuff")
604
- assert Company.where(name: "Ain't noth'n like' \#stuff").first
605
- end
606
-
607
- def test_hash_condition_find_with_array
608
- p1, p2 = Post.limit(2).order('id asc').to_a
609
- assert_equal [p1, p2], Post.where(id: [p1, p2]).order('id asc').to_a
610
- assert_equal [p1, p2], Post.where(id: [p1, p2.id]).order('id asc').to_a
611
- end
612
-
613
- def test_hash_condition_find_with_nil
614
- topic = Topic.where(last_read: nil).first
615
- assert_not_nil topic
616
- assert_nil topic.last_read
617
- end
618
-
619
- def test_hash_condition_find_with_aggregate_having_one_mapping
620
- balance = customers(:david).balance
621
- assert_kind_of Money, balance
622
- found_customer = Customer.where(:balance => balance).first
623
- assert_equal customers(:david), found_customer
624
- end
625
-
626
- def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
627
- gps_location = customers(:david).gps_location
628
- assert_kind_of GpsLocation, gps_location
629
- found_customer = Customer.where(:gps_location => gps_location).first
630
- assert_equal customers(:david), found_customer
631
- end
632
-
633
- def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
634
- balance = customers(:david).balance
635
- assert_kind_of Money, balance
636
- found_customer = Customer.where(:balance => balance.amount).first
637
- assert_equal customers(:david), found_customer
638
- end
639
-
640
- def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
641
- gps_location = customers(:david).gps_location
642
- assert_kind_of GpsLocation, gps_location
643
- found_customer = Customer.where(:gps_location => gps_location.gps_location).first
644
- assert_equal customers(:david), found_customer
645
- end
646
-
647
- def test_hash_condition_find_with_aggregate_having_three_mappings
648
- address = customers(:david).address
649
- assert_kind_of Address, address
650
- found_customer = Customer.where(:address => address).first
651
- assert_equal customers(:david), found_customer
652
- end
653
-
654
- def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
655
- address = customers(:david).address
656
- assert_kind_of Address, address
657
- found_customer = Customer.where(:address => address, :name => customers(:david).name).first
658
- assert_equal customers(:david), found_customer
659
- end
660
-
661
- def test_condition_utc_time_interpolation_with_default_timezone_local
662
- with_env_tz 'America/New_York' do
663
- with_timezone_config default: :local do
664
- topic = Topic.first
665
- assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getutc]).first
666
- end
667
- end
668
- end
669
-
670
- def test_hash_condition_utc_time_interpolation_with_default_timezone_local
671
- with_env_tz 'America/New_York' do
672
- with_timezone_config default: :local do
673
- topic = Topic.first
674
- assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
675
- end
676
- end
677
- end
678
-
679
- def test_condition_local_time_interpolation_with_default_timezone_utc
680
- with_env_tz 'America/New_York' do
681
- with_timezone_config default: :utc do
682
- topic = Topic.first
683
- assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getlocal]).first
684
- end
685
- end
686
- end
687
-
688
- def test_hash_condition_local_time_interpolation_with_default_timezone_utc
689
- with_env_tz 'America/New_York' do
690
- with_timezone_config default: :utc do
691
- topic = Topic.first
692
- assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
693
- end
694
- end
695
- end
696
-
697
- def test_bind_variables
698
- assert_kind_of Firm, Company.where(["name = ?", "37signals"]).first
699
- assert_nil Company.where(["name = ?", "37signals!"]).first
700
- assert_nil Company.where(["name = ?", "37signals!' OR 1=1"]).first
701
- assert_kind_of Time, Topic.where(["id = ?", 1]).first.written_on
702
- assert_raise(ActiveRecord::PreparedStatementInvalid) {
703
- Company.where(["id=? AND name = ?", 2]).first
704
- }
705
- assert_raise(ActiveRecord::PreparedStatementInvalid) {
706
- Company.where(["id=?", 2, 3, 4]).first
707
- }
708
- end
709
-
710
- def test_bind_variables_with_quotes
711
- Company.create("name" => "37signals' go'es agains")
712
- assert Company.where(["name = ?", "37signals' go'es agains"]).first
713
- end
714
-
715
- def test_named_bind_variables_with_quotes
716
- Company.create("name" => "37signals' go'es agains")
717
- assert Company.where(["name = :name", {name: "37signals' go'es agains"}]).first
718
- end
719
-
720
- def test_bind_arity
721
- assert_nothing_raised { bind '' }
722
- assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '', 1 }
723
-
724
- assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?' }
725
- assert_nothing_raised { bind '?', 1 }
726
- assert_raise(ActiveRecord::PreparedStatementInvalid) { bind '?', 1, 1 }
727
- end
728
-
729
- def test_named_bind_variables
730
- assert_equal '1', bind(':a', :a => 1) # ' ruby-mode
731
- assert_equal '1 1', bind(':a :a', :a => 1) # ' ruby-mode
732
-
733
- assert_nothing_raised { bind("'+00:00'", :foo => "bar") }
734
-
735
- assert_kind_of Firm, Company.where(["name = :name", { name: "37signals" }]).first
736
- assert_nil Company.where(["name = :name", { name: "37signals!" }]).first
737
- assert_nil Company.where(["name = :name", { name: "37signals!' OR 1=1" }]).first
738
- assert_kind_of Time, Topic.where(["id = :id", { id: 1 }]).first.written_on
739
- end
740
-
741
- class SimpleEnumerable
742
- include Enumerable
743
-
744
- def initialize(ary)
745
- @ary = ary
746
- end
747
-
748
- def each(&b)
749
- @ary.each(&b)
750
- end
751
- end
752
-
753
- def test_bind_enumerable
754
- quoted_abc = %(#{ActiveRecord::Base.connection.quote('a')},#{ActiveRecord::Base.connection.quote('b')},#{ActiveRecord::Base.connection.quote('c')})
755
-
756
- assert_equal '1,2,3', bind('?', [1, 2, 3])
757
- assert_equal quoted_abc, bind('?', %w(a b c))
758
-
759
- assert_equal '1,2,3', bind(':a', :a => [1, 2, 3])
760
- assert_equal quoted_abc, bind(':a', :a => %w(a b c)) # '
761
-
762
- assert_equal '1,2,3', bind('?', SimpleEnumerable.new([1, 2, 3]))
763
- assert_equal quoted_abc, bind('?', SimpleEnumerable.new(%w(a b c)))
764
-
765
- assert_equal '1,2,3', bind(':a', :a => SimpleEnumerable.new([1, 2, 3]))
766
- assert_equal quoted_abc, bind(':a', :a => SimpleEnumerable.new(%w(a b c))) # '
767
- end
768
-
769
- def test_bind_empty_enumerable
770
- quoted_nil = ActiveRecord::Base.connection.quote(nil)
771
- assert_equal quoted_nil, bind('?', [])
772
- assert_equal " in (#{quoted_nil})", bind(' in (?)', [])
773
- assert_equal "foo in (#{quoted_nil})", bind('foo in (?)', [])
774
- end
775
-
776
- def test_bind_empty_string
777
- quoted_empty = ActiveRecord::Base.connection.quote('')
778
- assert_equal quoted_empty, bind('?', '')
779
- end
780
-
781
- def test_bind_chars
782
- quoted_bambi = ActiveRecord::Base.connection.quote("Bambi")
783
- quoted_bambi_and_thumper = ActiveRecord::Base.connection.quote("Bambi\nand\nThumper")
784
- assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi")
785
- assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper")
786
- assert_equal "name=#{quoted_bambi}", bind('name=?', "Bambi".mb_chars)
787
- assert_equal "name=#{quoted_bambi_and_thumper}", bind('name=?', "Bambi\nand\nThumper".mb_chars)
788
- end
789
-
790
- def test_bind_record
791
- o = Struct.new(:quoted_id).new(1)
792
- assert_equal '1', bind('?', o)
793
-
794
- os = [o] * 3
795
- assert_equal '1,1,1', bind('?', os)
796
- end
797
-
798
- def test_named_bind_with_postgresql_type_casts
799
- l = Proc.new { bind(":a::integer '2009-01-01'::date", :a => '10') }
800
- assert_nothing_raised(&l)
801
- assert_equal "#{ActiveRecord::Base.connection.quote('10')}::integer '2009-01-01'::date", l.call
802
- end
803
-
804
- def test_string_sanitation
805
- assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
806
- assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
807
- end
808
-
809
- def test_count_by_sql
810
- assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
811
- assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
812
- assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
813
- end
814
-
815
- def test_find_by_one_attribute
816
- assert_equal topics(:first), Topic.find_by_title("The First Topic")
817
- assert_nil Topic.find_by_title("The First Topic!")
818
- end
819
-
820
- def test_find_by_one_attribute_bang
821
- assert_equal topics(:first), Topic.find_by_title!("The First Topic")
822
- assert_raises_with_message(ActiveRecord::RecordNotFound, "Couldn't find Topic") do
823
- Topic.find_by_title!("The First Topic!")
824
- end
825
- end
826
-
827
- def test_find_by_on_attribute_that_is_a_reserved_word
828
- dog_alias = 'Dog'
829
- dog = Dog.create(alias: dog_alias)
830
-
831
- assert_equal dog, Dog.find_by_alias(dog_alias)
832
- end
833
-
834
- def test_find_by_one_attribute_that_is_an_alias
835
- assert_equal topics(:first), Topic.find_by_heading("The First Topic")
836
- assert_nil Topic.find_by_heading("The First Topic!")
837
- end
838
-
839
- def test_find_by_one_attribute_bang_with_blank_defined
840
- blank_topic = BlankTopic.create(title: "The Blank One")
841
- assert_equal blank_topic, BlankTopic.find_by_title!("The Blank One")
842
- end
843
-
844
- def test_find_by_one_attribute_with_conditions
845
- assert_equal accounts(:rails_core_account), Account.where('firm_id = ?', 6).find_by_credit_limit(50)
846
- end
847
-
848
- def test_find_by_one_attribute_that_is_an_aggregate
849
- address = customers(:david).address
850
- assert_kind_of Address, address
851
- found_customer = Customer.find_by_address(address)
852
- assert_equal customers(:david), found_customer
853
- end
854
-
855
- def test_find_by_one_attribute_that_is_an_aggregate_with_one_attribute_difference
856
- address = customers(:david).address
857
- assert_kind_of Address, address
858
- missing_address = Address.new(address.street, address.city, address.country + "1")
859
- assert_nil Customer.find_by_address(missing_address)
860
- missing_address = Address.new(address.street, address.city + "1", address.country)
861
- assert_nil Customer.find_by_address(missing_address)
862
- missing_address = Address.new(address.street + "1", address.city, address.country)
863
- assert_nil Customer.find_by_address(missing_address)
864
- end
865
-
866
- def test_find_by_two_attributes_that_are_both_aggregates
867
- balance = customers(:david).balance
868
- address = customers(:david).address
869
- assert_kind_of Money, balance
870
- assert_kind_of Address, address
871
- found_customer = Customer.find_by_balance_and_address(balance, address)
872
- assert_equal customers(:david), found_customer
873
- end
874
-
875
- def test_find_by_two_attributes_with_one_being_an_aggregate
876
- balance = customers(:david).balance
877
- assert_kind_of Money, balance
878
- found_customer = Customer.find_by_balance_and_name(balance, customers(:david).name)
879
- assert_equal customers(:david), found_customer
880
- end
881
-
882
- def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
883
- # ensure this test can run independently of order
884
- class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.include?(:find_by_credit_limit)
885
- a = Account.where('firm_id = ?', 6).find_by_credit_limit(50)
886
- assert_equal a, Account.where('firm_id = ?', 6).find_by_credit_limit(50) # find_by_credit_limit has been cached
887
- end
888
-
889
- def test_find_by_one_attribute_with_several_options
890
- assert_equal accounts(:unknown), Account.order('id DESC').where('id != ?', 3).find_by_credit_limit(50)
891
- end
892
-
893
- def test_find_by_one_missing_attribute
894
- assert_raise(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
895
- end
896
-
897
- def test_find_by_invalid_method_syntax
898
- assert_raise(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") }
899
- assert_raise(NoMethodError) { Topic.find_by_title?("The First Topic") }
900
- assert_raise(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") }
901
- assert_raise(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") }
902
- end
903
-
904
- def test_find_by_two_attributes
905
- assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
906
- assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
907
- end
908
-
909
- def test_find_by_two_attributes_but_passing_only_one
910
- assert_raise(ArgumentError) { Topic.find_by_title_and_author_name("The First Topic") }
911
- end
912
-
913
- def test_find_last_with_offset
914
- devs = Developer.order('id')
915
-
916
- assert_equal devs[2], Developer.offset(2).first
917
- assert_equal devs[-3], Developer.offset(2).last
918
- assert_equal devs[-3], Developer.offset(2).last
919
- assert_equal devs[-3], Developer.offset(2).order('id DESC').first
920
- end
921
-
922
- def test_find_by_nil_attribute
923
- topic = Topic.find_by_last_read nil
924
- assert_not_nil topic
925
- assert_nil topic.last_read
926
- end
927
-
928
- def test_find_by_nil_and_not_nil_attributes
929
- topic = Topic.find_by_last_read_and_author_name nil, "Mary"
930
- assert_equal "Mary", topic.author_name
931
- end
932
-
933
- def test_find_with_bad_sql
934
- assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
935
- end
936
-
937
- def test_find_all_with_join
938
- developers_on_project_one = Developer.
939
- joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').
940
- where('project_id=1').to_a
941
- assert_equal 3, developers_on_project_one.length
942
- developer_names = developers_on_project_one.map { |d| d.name }
943
- assert developer_names.include?('David')
944
- assert developer_names.include?('Jamis')
945
- end
946
-
947
- def test_joins_dont_clobber_id
948
- first = Firm.
949
- joins('INNER JOIN companies clients ON clients.firm_id = companies.id').
950
- where('companies.id = 1').first
951
- assert_equal 1, first.id
952
- end
953
-
954
- def test_joins_with_string_array
955
- person_with_reader_and_post = Post.
956
- joins(["INNER JOIN categorizations ON categorizations.post_id = posts.id",
957
- "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
958
- ])
959
- assert_equal 1, person_with_reader_and_post.size
960
- end
961
-
962
- def test_find_by_id_with_conditions_with_or
963
- assert_nothing_raised do
964
- Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1,2,3])
965
- end
966
- end
967
-
968
- # http://dev.rubyonrails.org/ticket/6778
969
- def test_find_ignores_previously_inserted_record
970
- Post.create!(:title => 'test', :body => 'it out')
971
- assert_equal [], Post.where(id: nil)
972
- end
973
-
974
- def test_find_by_empty_ids
975
- assert_equal [], Post.find([])
976
- end
977
-
978
- def test_find_by_empty_in_condition
979
- assert_equal [], Post.where('id in (?)', [])
980
- end
981
-
982
- def test_find_by_records
983
- p1, p2 = Post.limit(2).order('id asc').to_a
984
- assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2]]).order('id asc')
985
- assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2.id]]).order('id asc')
986
- end
987
-
988
- def test_select_value
989
- assert_equal "37signals", Company.connection.select_value("SELECT name FROM companies WHERE id = 1")
990
- assert_nil Company.connection.select_value("SELECT name FROM companies WHERE id = -1")
991
- # make sure we didn't break count...
992
- assert_equal 0, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = 'Halliburton'")
993
- assert_equal 1, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = '37signals'")
994
- end
995
-
996
- def test_select_values
997
- assert_equal ["1","2","3","4","5","6","7","8","9", "10", "11"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map! { |i| i.to_s }
998
- assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy", "Ex Nihilo Part Deux", "Apex"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
999
- end
1000
-
1001
- def test_select_rows
1002
- assert_equal(
1003
- [["1", "1", nil, "37signals"],
1004
- ["2", "1", "2", "Summit"],
1005
- ["3", "1", "1", "Microsoft"]],
1006
- Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}})
1007
- assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]],
1008
- Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}}
1009
- end
1010
-
1011
- def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
1012
- assert_equal 2, Post.includes(authors: :author_address).
1013
- where.not(author_addresses: { id: nil }).
1014
- order('author_addresses.id DESC').limit(2).to_a.size
1015
-
1016
- assert_equal 3, Post.includes(author: :author_address, authors: :author_address).
1017
- where.not(author_addresses_authors: { id: nil }).
1018
- order('author_addresses_authors.id DESC').limit(3).to_a.size
1019
- end
1020
-
1021
- def test_find_with_nil_inside_set_passed_for_one_attribute
1022
- client_of = Company.
1023
- where(client_of: [2, 1, nil],
1024
- name: ['37signals', 'Summit', 'Microsoft']).
1025
- order('client_of DESC').
1026
- map { |x| x.client_of }
1027
-
1028
- assert client_of.include?(nil)
1029
- assert_equal [2, 1].sort, client_of.compact.sort
1030
- end
1031
-
1032
- def test_find_with_nil_inside_set_passed_for_attribute
1033
- client_of = Company.
1034
- where(client_of: [nil]).
1035
- order('client_of DESC').
1036
- map { |x| x.client_of }
1037
-
1038
- assert_equal [], client_of.compact
1039
- end
1040
-
1041
- def test_with_limiting_with_custom_select
1042
- posts = Post.references(:authors).merge(
1043
- :includes => :author, :select => 'posts.*, authors.id as "author_id"',
1044
- :limit => 3, :order => 'posts.id'
1045
- ).to_a
1046
- assert_equal 3, posts.size
1047
- assert_equal [0, 1, 1], posts.map(&:author_id).sort
1048
- end
1049
-
1050
- def test_find_one_message_with_custom_primary_key
1051
- table_with_custom_primary_key do |model|
1052
- model.primary_key = :name
1053
- e = assert_raises(ActiveRecord::RecordNotFound) do
1054
- model.find 'Hello World!'
1055
- end
1056
- assert_equal %Q{Couldn't find MercedesCar with 'name'=Hello World!}, e.message
1057
- end
1058
- end
1059
-
1060
- def test_find_some_message_with_custom_primary_key
1061
- table_with_custom_primary_key do |model|
1062
- model.primary_key = :name
1063
- e = assert_raises(ActiveRecord::RecordNotFound) do
1064
- model.find 'Hello', 'World!'
1065
- end
1066
- assert_equal %Q{Couldn't find all MercedesCars with 'name': (Hello, World!) (found 0 results, but was looking for 2)}, e.message
1067
- end
1068
- end
1069
-
1070
- def test_find_without_primary_key
1071
- assert_raises(ActiveRecord::UnknownPrimaryKey) do
1072
- Matey.find(1)
1073
- end
1074
- end
1075
-
1076
- def test_finder_with_offset_string
1077
- assert_nothing_raised(ActiveRecord::StatementInvalid) { Topic.offset("3").to_a }
1078
- end
1079
-
1080
- test "find_by with hash conditions returns the first matching record" do
1081
- assert_equal posts(:eager_other), Post.find_by(id: posts(:eager_other).id)
1082
- end
1083
-
1084
- test "find_by with non-hash conditions returns the first matching record" do
1085
- assert_equal posts(:eager_other), Post.find_by("id = #{posts(:eager_other).id}")
1086
- end
1087
-
1088
- test "find_by with multi-arg conditions returns the first matching record" do
1089
- assert_equal posts(:eager_other), Post.find_by('id = ?', posts(:eager_other).id)
1090
- end
1091
-
1092
- test "find_by returns nil if the record is missing" do
1093
- assert_equal nil, Post.find_by("1 = 0")
1094
- end
1095
-
1096
- test "find_by with associations" do
1097
- assert_equal authors(:david), Post.find_by(author: authors(:david)).author
1098
- assert_equal authors(:mary) , Post.find_by(author: authors(:mary) ).author
1099
- end
1100
-
1101
- test "find_by doesn't have implicit ordering" do
1102
- assert_sql(/^((?!ORDER).)*$/) { Post.find_by(id: posts(:eager_other).id) }
1103
- end
1104
-
1105
- test "find_by! with hash conditions returns the first matching record" do
1106
- assert_equal posts(:eager_other), Post.find_by!(id: posts(:eager_other).id)
1107
- end
1108
-
1109
- test "find_by! with non-hash conditions returns the first matching record" do
1110
- assert_equal posts(:eager_other), Post.find_by!("id = #{posts(:eager_other).id}")
1111
- end
1112
-
1113
- test "find_by! with multi-arg conditions returns the first matching record" do
1114
- assert_equal posts(:eager_other), Post.find_by!('id = ?', posts(:eager_other).id)
1115
- end
1116
-
1117
- test "find_by! doesn't have implicit ordering" do
1118
- assert_sql(/^((?!ORDER).)*$/) { Post.find_by!(id: posts(:eager_other).id) }
1119
- end
1120
-
1121
- test "find_by! raises RecordNotFound if the record is missing" do
1122
- assert_raises(ActiveRecord::RecordNotFound) do
1123
- Post.find_by!("1 = 0")
1124
- end
1125
- end
1126
-
1127
- test "find on a scope does not perform statement caching" do
1128
- honda = cars(:honda)
1129
- zyke = cars(:zyke)
1130
- tyre = honda.tyres.create!
1131
- tyre2 = zyke.tyres.create!
1132
-
1133
- assert_equal tyre, honda.tyres.custom_find(tyre.id)
1134
- assert_equal tyre2, zyke.tyres.custom_find(tyre2.id)
1135
- end
1136
-
1137
- test "find_by on a scope does not perform statement caching" do
1138
- honda = cars(:honda)
1139
- zyke = cars(:zyke)
1140
- tyre = honda.tyres.create!
1141
- tyre2 = zyke.tyres.create!
1142
-
1143
- assert_equal tyre, honda.tyres.custom_find_by(id: tyre.id)
1144
- assert_equal tyre2, zyke.tyres.custom_find_by(id: tyre2.id)
1145
- end
1146
-
1147
- protected
1148
- def bind(statement, *vars)
1149
- if vars.first.is_a?(Hash)
1150
- ActiveRecord::Base.send(:replace_named_bind_variables, statement, vars.first)
1151
- else
1152
- ActiveRecord::Base.send(:replace_bind_variables, statement, vars)
1153
- end
1154
- end
1155
-
1156
- def table_with_custom_primary_key
1157
- yield(Class.new(Toy) do
1158
- def self.name
1159
- 'MercedesCar'
1160
- end
1161
- end)
1162
- end
1163
-
1164
- def assert_raises_with_message(exception_class, message, &block)
1165
- err = assert_raises(exception_class) { block.call }
1166
- assert_match message, err.message
1167
- end
1168
-
1169
- end
1
+ require "cases/helper"
2
+ require 'models/post'
3
+ require 'models/author'
4
+ require 'models/categorization'
5
+ require 'models/comment'
6
+ require 'models/company'
7
+ require 'models/tagging'
8
+ require 'models/topic'
9
+ require 'models/reply'
10
+ require 'models/entrant'
11
+ require 'models/project'
12
+ require 'models/developer'
13
+ require 'models/computer'
14
+ require 'models/customer'
15
+ require 'models/toy'
16
+ require 'models/matey'
17
+ require 'models/dog'
18
+ require 'models/car'
19
+ require 'models/tyre'
20
+
21
+ class FinderTest < ActiveRecord::TestCase
22
+ fixtures :companies, :topics, :entrants, :developers, :developers_projects, :posts, :comments, :accounts, :authors, :author_addresses, :customers, :categories, :categorizations, :cars
23
+
24
+ def test_find_by_id_with_hash
25
+ assert_raises(ActiveRecord::StatementInvalid) do
26
+ Post.find_by_id(:limit => 1)
27
+ end
28
+ end
29
+
30
+ def test_find_by_title_and_id_with_hash
31
+ assert_raises(ActiveRecord::StatementInvalid) do
32
+ Post.find_by_title_and_id('foo', :limit => 1)
33
+ end
34
+ end
35
+
36
+ def test_find
37
+ assert_equal(topics(:first).title, Topic.find(1).title)
38
+ end
39
+
40
+ def test_find_with_proc_parameter_and_block
41
+ exception = assert_raises(RuntimeError) do
42
+ Topic.all.find(-> { raise "should happen" }) { |e| e.title == "non-existing-title" }
43
+ end
44
+ assert_equal "should happen", exception.message
45
+
46
+ assert_nothing_raised do
47
+ Topic.all.find(-> { raise "should not happen" }) { |e| e.title == topics(:first).title }
48
+ end
49
+ end
50
+
51
+ def test_find_with_ids_returning_ordered
52
+ puts "finder_test.test_find_with_ids_returning_ordered"
53
+ records = Topic.find([4,2,5])
54
+ assert_equal 'The Fourth Topic of the day', records[0].title
55
+ assert_equal 'The Second Topic of the day', records[1].title
56
+ assert_equal 'The Fifth Topic of the day', records[2].title
57
+
58
+ records = Topic.find(4,2,5)
59
+ assert_equal 'The Fourth Topic of the day', records[0].title
60
+ assert_equal 'The Second Topic of the day', records[1].title
61
+ assert_equal 'The Fifth Topic of the day', records[2].title
62
+
63
+ records = Topic.find(['4','2','5'])
64
+ assert_equal 'The Fourth Topic of the day', records[0].title
65
+ assert_equal 'The Second Topic of the day', records[1].title
66
+ assert_equal 'The Fifth Topic of the day', records[2].title
67
+
68
+ records = Topic.find('4','2','5')
69
+ assert_equal 'The Fourth Topic of the day', records[0].title
70
+ assert_equal 'The Second Topic of the day', records[1].title
71
+ assert_equal 'The Fifth Topic of the day', records[2].title
72
+ end
73
+
74
+ def test_find_with_ids_and_order_clause
75
+ # The order clause takes precedence over the informed ids
76
+ records = Topic.order(:author_name).find([5,3,1])
77
+ assert_equal 'The Third Topic of the day', records[0].title
78
+ assert_equal 'The First Topic', records[1].title
79
+ assert_equal 'The Fifth Topic of the day', records[2].title
80
+
81
+ records = Topic.order(:id).find([5,3,1])
82
+ assert_equal 'The First Topic', records[0].title
83
+ assert_equal 'The Third Topic of the day', records[1].title
84
+ assert_equal 'The Fifth Topic of the day', records[2].title
85
+ end
86
+
87
+ def test_find_with_ids_with_limit_and_order_clause
88
+ puts "finder_test.test_find_with_ids_with_limit_and_order_clause"
89
+ # The order clause takes precedence over the informed ids
90
+ records = Topic.limit(2).order(:id).find([5,3,1])
91
+ assert_equal 2, records.size
92
+ assert_equal 'The First Topic', records[0].title
93
+ assert_equal 'The Third Topic of the day', records[1].title
94
+ end
95
+
96
+ def test_find_with_ids_and_limit
97
+ records = Topic.limit(3).find([3,2,5,1,4])
98
+ assert_equal 3, records.size
99
+ assert_equal 'The Third Topic of the day', records[0].title
100
+ assert_equal 'The Second Topic of the day', records[1].title
101
+ assert_equal 'The Fifth Topic of the day', records[2].title
102
+ end
103
+
104
+ def test_find_with_ids_where_and_limit
105
+ # Please note that Topic 1 is the only not approved so
106
+ # if it were among the first 3 it would raise an ActiveRecord::RecordNotFound
107
+ records = Topic.where(approved: true).limit(3).find([3,2,5,1,4])
108
+ assert_equal 3, records.size
109
+ assert_equal 'The Third Topic of the day', records[0].title
110
+ assert_equal 'The Second Topic of the day', records[1].title
111
+ assert_equal 'The Fifth Topic of the day', records[2].title
112
+ end
113
+
114
+ def test_find_with_ids_and_offset
115
+ records = Topic.offset(2).find([3,2,5,1,4])
116
+ assert_equal 3, records.size
117
+ assert_equal 'The Fifth Topic of the day', records[0].title
118
+ assert_equal 'The First Topic', records[1].title
119
+ assert_equal 'The Fourth Topic of the day', records[2].title
120
+ end
121
+
122
+ def test_find_passing_active_record_object_is_deprecated
123
+ assert_deprecated do
124
+ Topic.find(Topic.last)
125
+ end
126
+ end
127
+
128
+ def test_symbols_table_ref
129
+ gc_disabled = GC.disable
130
+ Post.where("author_id" => nil) # warm up
131
+ x = Symbol.all_symbols.count
132
+ Post.where("title" => {"xxxqqqq" => "bar"})
133
+ assert_equal x, Symbol.all_symbols.count
134
+ ensure
135
+ GC.enable if gc_disabled == false
136
+ end
137
+
138
+ # find should handle strings that come from URLs
139
+ # (example: Category.find(params[:id]))
140
+ def test_find_with_string
141
+ assert_equal(Topic.find(1).title,Topic.find("1").title)
142
+ end
143
+
144
+ def test_exists
145
+ assert_equal true, Topic.exists?(1)
146
+ assert_equal true, Topic.exists?("1")
147
+ assert_equal true, Topic.exists?(title: "The First Topic")
148
+ assert_equal true, Topic.exists?(heading: "The First Topic")
149
+ assert_equal true, Topic.exists?(:author_name => "Mary", :approved => true)
150
+ assert_equal true, Topic.exists?(["parent_id = ?", 1])
151
+ assert_equal true, Topic.exists?(id: [1, 9999])
152
+
153
+ assert_equal false, Topic.exists?(45)
154
+ assert_equal false, Topic.exists?(Topic.new.id)
155
+
156
+ assert_raise(NoMethodError) { Topic.exists?([1,2]) }
157
+ end
158
+
159
+ def test_exists_with_polymorphic_relation
160
+ puts "finder_test.test_exists_with_polymorphic_relation"
161
+ post = Post.create!(title: 'Post', body: 'default', taggings: [Tagging.new(comment: 'tagging comment')])
162
+ relation = Post.tagged_with_comment('tagging comment')
163
+
164
+ assert_equal true, relation.exists?(title: ['Post'])
165
+ assert_equal true, relation.exists?(['title LIKE ?', 'Post%'])
166
+ assert_equal true, relation.exists?
167
+ assert_equal true, relation.exists?(post.id)
168
+ assert_equal true, relation.exists?(post.id.to_s)
169
+
170
+ assert_equal false, relation.exists?(false)
171
+ end
172
+
173
+ def test_exists_passing_active_record_object_is_deprecated
174
+ assert_deprecated do
175
+ Topic.exists?(Topic.new)
176
+ end
177
+ end
178
+
179
+ def test_exists_fails_when_parameter_has_invalid_type
180
+ puts "finder_test.test_exists_fails_when_parameter_has_invalid_type"
181
+ assert_raises(ActiveModel::RangeError) do
182
+ assert_equal false, Topic.exists?(("9"*53).to_i) # number that's bigger than int
183
+ end
184
+ assert_equal false, Topic.exists?("foo")
185
+ end
186
+
187
+ def test_exists_does_not_select_columns_without_alias
188
+ puts "finder_test.test_exists_does_not_select_columns_without_alias"
189
+ assert_sql(/SELECT\W+1 AS one FROM ["`]topics["`]/i) do
190
+ Topic.exists?
191
+ end
192
+ end
193
+
194
+ def test_exists_returns_true_with_one_record_and_no_args
195
+ assert_equal true, Topic.exists?
196
+ end
197
+
198
+ def test_exists_returns_false_with_false_arg
199
+ assert_equal false, Topic.exists?(false)
200
+ end
201
+
202
+ # exists? should handle nil for id's that come from URLs and always return false
203
+ # (example: Topic.exists?(params[:id])) where params[:id] is nil
204
+ def test_exists_with_nil_arg
205
+ assert_equal false, Topic.exists?(nil)
206
+ assert_equal true, Topic.exists?
207
+
208
+ assert_equal false, Topic.first.replies.exists?(nil)
209
+ assert_equal true, Topic.first.replies.exists?
210
+ end
211
+
212
+ # ensures +exists?+ runs valid SQL by excluding order value
213
+ def test_exists_with_order
214
+ assert_equal true, Topic.order(:id).distinct.exists?
215
+ end
216
+
217
+ def test_exists_with_includes_limit_and_empty_result
218
+ puts "finder_test.test_exists_with_includes_limit_and_empty_result"
219
+ assert_equal false, Topic.includes(:replies).limit(0).exists?
220
+ assert_equal false, Topic.includes(:replies).limit(1).where('0 = 1').exists?
221
+ end
222
+
223
+ def test_exists_with_distinct_association_includes_and_limit
224
+ puts "finder_test.test_exists_with_distinct_association_includes_and_limit"
225
+ author = Author.first
226
+ assert_equal false, author.unique_categorized_posts.includes(:special_comments).limit(0).exists?
227
+ assert_equal true, author.unique_categorized_posts.includes(:special_comments).limit(1).exists?
228
+ end
229
+
230
+ def test_exists_with_distinct_association_includes_limit_and_order
231
+ puts "finder_test.test_exists_with_distinct_association_includes_limit_and_order"
232
+ author = Author.first
233
+ assert_equal false, author.unique_categorized_posts.includes(:special_comments).order('comments.tags_count DESC').limit(0).exists?
234
+ assert_equal true, author.unique_categorized_posts.includes(:special_comments).order('comments.tags_count DESC').limit(1).exists?
235
+ end
236
+
237
+ def test_exists_with_empty_table_and_no_args_given
238
+ Topic.delete_all
239
+ assert_equal false, Topic.exists?
240
+ end
241
+
242
+ def test_exists_with_aggregate_having_three_mappings
243
+ existing_address = customers(:david).address
244
+ assert_equal true, Customer.exists?(:address => existing_address)
245
+ end
246
+
247
+ def test_exists_with_aggregate_having_three_mappings_with_one_difference
248
+ existing_address = customers(:david).address
249
+ assert_equal false, Customer.exists?(:address =>
250
+ Address.new(existing_address.street, existing_address.city, existing_address.country + "1"))
251
+ assert_equal false, Customer.exists?(:address =>
252
+ Address.new(existing_address.street, existing_address.city + "1", existing_address.country))
253
+ assert_equal false, Customer.exists?(:address =>
254
+ Address.new(existing_address.street + "1", existing_address.city, existing_address.country))
255
+ end
256
+
257
+ def test_exists_does_not_instantiate_records
258
+ assert_not_called(Developer, :instantiate) do
259
+ Developer.exists?
260
+ end
261
+ end
262
+
263
+ def test_find_by_array_of_one_id
264
+ assert_kind_of(Array, Topic.find([ 1 ]))
265
+ assert_equal(1, Topic.find([ 1 ]).length)
266
+ end
267
+
268
+ def test_find_by_ids
269
+ assert_equal 2, Topic.find(1, 2).size
270
+ assert_equal topics(:second).title, Topic.find([2]).first.title
271
+ end
272
+
273
+ def test_find_by_ids_with_limit_and_offset
274
+ assert_equal 2, Entrant.limit(2).find([1,3,2]).size
275
+ entrants = Entrant.limit(3).offset(2).find([1,3,2])
276
+ assert_equal 1, entrants.size
277
+ assert_equal 'Ruby Guru', entrants.first.name
278
+
279
+ # Also test an edge case: If you have 11 results, and you set a
280
+ # limit of 3 and offset of 9, then you should find that there
281
+ # will be only 2 results, regardless of the limit.
282
+ devs = Developer.all
283
+ last_devs = Developer.limit(3).offset(9).find devs.map(&:id)
284
+ assert_equal 2, last_devs.size
285
+ assert_equal 'fixture_10', last_devs[0].name
286
+ assert_equal 'Jamis', last_devs[1].name
287
+ end
288
+
289
+ unless current_adapter?(:IBM_DBAdapter)
290
+ def test_find_with_large_number
291
+ assert_raises(ActiveRecord::RecordNotFound) { Topic.find('9999999999999999999999999999999') }
292
+ end
293
+
294
+ def test_find_by_with_large_number
295
+ assert_nil Topic.find_by(id: '9999999999999999999999999999999')
296
+ end
297
+
298
+ def test_find_by_id_with_large_number
299
+ assert_nil Topic.find_by_id('9999999999999999999999999999999')
300
+ end
301
+
302
+ def test_find_on_relation_with_large_number
303
+ assert_nil Topic.where('1=1').find_by(id: 9999999999999999999999999999999)
304
+ end
305
+
306
+ def test_find_by_bang_on_relation_with_large_number
307
+ assert_raises(ActiveRecord::RecordNotFound) do
308
+ Topic.where('1=1').find_by!(id: 9999999999999999999999999999999)
309
+ end
310
+ end
311
+ end
312
+
313
+ def test_find_an_empty_array
314
+ assert_equal [], Topic.find([])
315
+ end
316
+
317
+ def test_find_doesnt_have_implicit_ordering
318
+ assert_sql(/^((?!ORDER).)*$/) { Topic.find(1) }
319
+ end
320
+
321
+ def test_find_by_ids_missing_one
322
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1, 2, 45) }
323
+ end
324
+
325
+ def test_find_with_group_and_sanitized_having_method
326
+ developers = Developer.group(:salary).having("sum(salary) > ?", 10000).select('salary').to_a
327
+ assert_equal 3, developers.size
328
+ assert_equal 3, developers.map(&:salary).uniq.size
329
+ assert developers.all? { |developer| developer.salary > 10000 }
330
+ end
331
+
332
+ def test_find_with_entire_select_statement
333
+ topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
334
+
335
+ assert_equal(1, topics.size)
336
+ assert_equal(topics(:second).title, topics.first.title)
337
+ end
338
+
339
+ def test_find_with_prepared_select_statement
340
+ topics = Topic.find_by_sql ["SELECT * FROM topics WHERE author_name = ?", "Mary"]
341
+
342
+ assert_equal(1, topics.size)
343
+ assert_equal(topics(:second).title, topics.first.title)
344
+ end
345
+
346
+ def test_find_by_sql_with_sti_on_joined_table
347
+ accounts = Account.find_by_sql("SELECT * FROM accounts INNER JOIN companies ON companies.id = accounts.firm_id")
348
+ assert_equal [Account], accounts.collect(&:class).uniq
349
+ end
350
+
351
+ def test_find_by_association_subquery
352
+ author = authors(:david)
353
+ assert_equal author.post, Post.find_by(author: Author.where(id: author))
354
+ assert_equal author.post, Post.find_by(author_id: Author.where(id: author))
355
+ end
356
+
357
+ def test_find_by_and_where_consistency_with_active_record_instance
358
+ author = authors(:david)
359
+ assert_equal Post.where(author_id: author).take, Post.find_by(author_id: author)
360
+ end
361
+
362
+ def test_take
363
+ assert_equal topics(:first), Topic.take
364
+ end
365
+
366
+ def test_take_failing
367
+ assert_nil Topic.where("title = 'This title does not exist'").take
368
+ end
369
+
370
+ def test_take_bang_present
371
+ assert_nothing_raised do
372
+ assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").take!
373
+ end
374
+ end
375
+
376
+ def test_take_bang_missing
377
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
378
+ Topic.where("title = 'This title does not exist'").take!
379
+ end
380
+ end
381
+
382
+ def test_first
383
+ assert_equal topics(:second).title, Topic.where("title = 'The Second Topic of the day'").first.title
384
+ end
385
+
386
+ def test_first_failing
387
+ assert_nil Topic.where("title = 'The Second Topic of the day!'").first
388
+ end
389
+
390
+ def test_first_bang_present
391
+ assert_nothing_raised do
392
+ assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").first!
393
+ end
394
+ end
395
+
396
+ def test_first_bang_missing
397
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
398
+ Topic.where("title = 'This title does not exist'").first!
399
+ end
400
+ end
401
+
402
+ def test_first_have_primary_key_order_by_default
403
+ expected = topics(:first)
404
+ expected.touch # PostgreSQL changes the default order if no order clause is used
405
+ assert_equal expected, Topic.first
406
+ end
407
+
408
+ def test_model_class_responds_to_first_bang
409
+ assert Topic.first!
410
+ Topic.delete_all
411
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
412
+ Topic.first!
413
+ end
414
+ end
415
+
416
+ def test_second
417
+ puts "finder_test.test_second"
418
+ assert_equal topics(:second).title, Topic.second.title
419
+ end
420
+
421
+ def test_second_with_offset
422
+ puts "finder_test.test_second_with_offset"
423
+ assert_equal topics(:fifth), Topic.offset(3).second
424
+ end
425
+
426
+ def test_second_have_primary_key_order_by_default
427
+ puts "finder_test.test_second_have_primary_key_order_by_default"
428
+ expected = topics(:second)
429
+ expected.touch # PostgreSQL changes the default order if no order clause is used
430
+ assert_equal expected, Topic.second
431
+ end
432
+
433
+ def test_model_class_responds_to_second_bang
434
+ assert Topic.second!
435
+ Topic.delete_all
436
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
437
+ Topic.second!
438
+ end
439
+ end
440
+
441
+ def test_third
442
+ puts "finder_test.test_third"
443
+ assert_equal topics(:third).title, Topic.third.title
444
+ end
445
+
446
+ def test_third_with_offset
447
+ puts "finder_test.test_third_with_offset"
448
+ assert_equal topics(:fifth), Topic.offset(2).third
449
+ end
450
+
451
+ def test_third_have_primary_key_order_by_default
452
+ puts "finder_test.test_third_have_primary_key_order_by_default"
453
+ expected = topics(:third)
454
+ expected.touch # PostgreSQL changes the default order if no order clause is used
455
+ assert_equal expected, Topic.third
456
+ end
457
+
458
+ def test_model_class_responds_to_third_bang
459
+ assert Topic.third!
460
+ Topic.delete_all
461
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
462
+ Topic.third!
463
+ end
464
+ end
465
+
466
+ def test_fourth
467
+ puts "finder_test.test_fourth"
468
+ assert_equal topics(:fourth).title, Topic.fourth.title
469
+ end
470
+
471
+ def test_fourth_with_offset
472
+ puts "finder_test.test_fourth_with_offset"
473
+ assert_equal topics(:fifth), Topic.offset(1).fourth
474
+ end
475
+
476
+ def test_fourth_have_primary_key_order_by_default
477
+ puts "finder_test.test_fourth_have_primary_key_order_by_default"
478
+ expected = topics(:fourth)
479
+ expected.touch # PostgreSQL changes the default order if no order clause is used
480
+ assert_equal expected, Topic.fourth
481
+ end
482
+
483
+ def test_model_class_responds_to_fourth_bang
484
+ assert Topic.fourth!
485
+ Topic.delete_all
486
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
487
+ Topic.fourth!
488
+ end
489
+ end
490
+
491
+ def test_fifth
492
+ assert_equal topics(:fifth).title, Topic.fifth.title
493
+ end
494
+
495
+ def test_fifth_with_offset
496
+ puts "finder_test.test_fifth_with_offset"
497
+ assert_equal topics(:fifth), Topic.offset(0).fifth
498
+ end
499
+
500
+ def test_fifth_have_primary_key_order_by_default
501
+ puts "finder_test.test_fifth_have_primary_key_order_by_default"
502
+ expected = topics(:fifth)
503
+ expected.touch # PostgreSQL changes the default order if no order clause is used
504
+ assert_equal expected, Topic.fifth
505
+ end
506
+
507
+ def test_model_class_responds_to_fifth_bang
508
+ assert Topic.fifth!
509
+ Topic.delete_all
510
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
511
+ Topic.fifth!
512
+ end
513
+ end
514
+
515
+ def test_second_to_last
516
+ puts "finder_test.test_second_to_last"
517
+ assert_equal topics(:fourth).title, Topic.second_to_last.title
518
+
519
+ # test with offset
520
+ assert_equal topics(:fourth), Topic.offset(1).second_to_last
521
+ assert_equal topics(:fourth), Topic.offset(2).second_to_last
522
+ assert_equal topics(:fourth), Topic.offset(3).second_to_last
523
+ assert_equal nil, Topic.offset(4).second_to_last
524
+ assert_equal nil, Topic.offset(5).second_to_last
525
+
526
+ #test with limit
527
+ # assert_equal nil, Topic.limit(1).second # TODO: currently failing
528
+ assert_equal nil, Topic.limit(1).second_to_last
529
+ end
530
+
531
+ def test_second_to_last_have_primary_key_order_by_default
532
+ expected = topics(:fourth)
533
+ expected.touch # PostgreSQL changes the default order if no order clause is used
534
+ assert_equal expected, Topic.second_to_last
535
+ end
536
+
537
+ def test_model_class_responds_to_second_to_last_bang
538
+ assert Topic.second_to_last!
539
+ Topic.delete_all
540
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
541
+ Topic.second_to_last!
542
+ end
543
+ end
544
+
545
+ def test_third_to_last
546
+ assert_equal topics(:third).title, Topic.third_to_last.title
547
+
548
+ # test with offset
549
+ assert_equal topics(:third), Topic.offset(1).third_to_last
550
+ assert_equal topics(:third), Topic.offset(2).third_to_last
551
+ assert_equal nil, Topic.offset(3).third_to_last
552
+ assert_equal nil, Topic.offset(4).third_to_last
553
+ assert_equal nil, Topic.offset(5).third_to_last
554
+
555
+ # test with limit
556
+ # assert_equal nil, Topic.limit(1).third # TODO: currently failing
557
+ assert_equal nil, Topic.limit(1).third_to_last
558
+ # assert_equal nil, Topic.limit(2).third # TODO: currently failing
559
+ assert_equal nil, Topic.limit(2).third_to_last
560
+ end
561
+
562
+ def test_third_to_last_have_primary_key_order_by_default
563
+ expected = topics(:third)
564
+ expected.touch # PostgreSQL changes the default order if no order clause is used
565
+ assert_equal expected, Topic.third_to_last
566
+ end
567
+
568
+ def test_model_class_responds_to_third_to_last_bang
569
+ assert Topic.third_to_last!
570
+ Topic.delete_all
571
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
572
+ Topic.third_to_last!
573
+ end
574
+ end
575
+
576
+ def test_last_bang_present
577
+ assert_nothing_raised do
578
+ assert_equal topics(:second), Topic.where("title = 'The Second Topic of the day'").last!
579
+ end
580
+ end
581
+
582
+ def test_last_bang_missing
583
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
584
+ Topic.where("title = 'This title does not exist'").last!
585
+ end
586
+ end
587
+
588
+ def test_model_class_responds_to_last_bang
589
+ assert_equal topics(:fifth), Topic.last!
590
+ assert_raises_with_message ActiveRecord::RecordNotFound, "Couldn't find Topic" do
591
+ Topic.delete_all
592
+ Topic.last!
593
+ end
594
+ end
595
+
596
+ def test_take_and_first_and_last_with_integer_should_use_sql_limit
597
+ puts "finder_test.test_take_and_first_and_last_with_integer_should_use_sql_limit"
598
+ assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.take(3).entries }
599
+ assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.first(2).entries }
600
+ assert_sql(/LIMIT|ROWNUM <=|FETCH FIRST/) { Topic.last(5).entries }
601
+ end
602
+
603
+ def test_last_with_integer_and_order_should_keep_the_order
604
+ puts "finder_test.test_last_with_integer_and_order_should_keep_the_order"
605
+ assert_equal Topic.order("title").to_a.last(2), Topic.order("title").last(2)
606
+ end
607
+
608
+ def test_last_with_integer_and_order_should_use_sql_limit
609
+ relation = Topic.order("title")
610
+ assert_queries(1) { relation.last(5) }
611
+ assert !relation.loaded?
612
+ end
613
+
614
+ def test_last_with_integer_and_reorder_should_use_sql_limit
615
+ relation = Topic.reorder("title")
616
+ assert_queries(1) { relation.last(5) }
617
+ assert !relation.loaded?
618
+ end
619
+
620
+ def test_last_on_loaded_relation_should_not_use_sql
621
+ relation = Topic.limit(10).load
622
+ assert_no_queries do
623
+ relation.last
624
+ relation.last(2)
625
+ end
626
+ end
627
+
628
+ def test_last_with_irreversible_order
629
+ assert_deprecated do
630
+ Topic.order("coalesce(author_name, title)").last
631
+ end
632
+ end
633
+
634
+ def test_last_on_relation_with_limit_and_offset
635
+ post = posts('sti_comments')
636
+
637
+ comments = post.comments.order(id: :asc)
638
+ assert_equal comments.limit(2).to_a.last, comments.limit(2).last
639
+ assert_equal comments.limit(2).to_a.last(2), comments.limit(2).last(2)
640
+ assert_equal comments.limit(2).to_a.last(3), comments.limit(2).last(3)
641
+
642
+ comments = comments.offset(1)
643
+ assert_equal comments.limit(2).to_a.last, comments.limit(2).last
644
+ assert_equal comments.limit(2).to_a.last(2), comments.limit(2).last(2)
645
+ assert_equal comments.limit(2).to_a.last(3), comments.limit(2).last(3)
646
+ end
647
+
648
+ def test_take_and_first_and_last_with_integer_should_return_an_array
649
+ assert_kind_of Array, Topic.take(5)
650
+ assert_kind_of Array, Topic.first(5)
651
+ assert_kind_of Array, Topic.last(5)
652
+ end
653
+
654
+ def test_unexisting_record_exception_handling
655
+ assert_raise(ActiveRecord::RecordNotFound) {
656
+ Topic.find(1).parent
657
+ }
658
+
659
+ Topic.find(2).topic
660
+ end
661
+
662
+ def test_find_only_some_columns
663
+ topic = Topic.select("author_name").find(1)
664
+ assert_raise(ActiveModel::MissingAttributeError) {topic.title}
665
+ assert_raise(ActiveModel::MissingAttributeError) {topic.title?}
666
+ assert_nil topic.read_attribute("title")
667
+ assert_equal "David", topic.author_name
668
+ assert !topic.attribute_present?("title")
669
+ assert !topic.attribute_present?(:title)
670
+ assert topic.attribute_present?("author_name")
671
+ assert_respond_to topic, "author_name"
672
+ end
673
+
674
+ def test_find_on_array_conditions
675
+ assert Topic.where(["approved = ?", false]).find(1)
676
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(["approved = ?", true]).find(1) }
677
+ end
678
+
679
+ def test_find_on_hash_conditions
680
+ assert Topic.where(approved: false).find(1)
681
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(approved: true).find(1) }
682
+ end
683
+
684
+ def test_find_on_hash_conditions_with_qualified_attribute_dot_notation_string
685
+ assert Topic.where('topics.approved' => false).find(1)
686
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => true).find(1) }
687
+ end
688
+
689
+ def test_find_on_hash_conditions_with_qualified_attribute_dot_notation_symbol
690
+ assert Topic.where('topics.approved': false).find(1)
691
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved': true).find(1) }
692
+ end
693
+
694
+ def test_find_on_hash_conditions_with_hashed_table_name
695
+ assert Topic.where(topics: { approved: false }).find(1)
696
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(topics: { approved: true }).find(1) }
697
+ end
698
+
699
+ def test_find_on_combined_explicit_and_hashed_table_names
700
+ assert Topic.where('topics.approved' => false, topics: { author_name: "David" }).find(1)
701
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => true, topics: { author_name: "David" }).find(1) }
702
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where('topics.approved' => false, topics: { author_name: "Melanie" }).find(1) }
703
+ end
704
+
705
+ def test_find_with_hash_conditions_on_joined_table
706
+ firms = Firm.joins(:account).where(:accounts => { :credit_limit => 50 })
707
+ assert_equal 1, firms.size
708
+ assert_equal companies(:first_firm), firms.first
709
+ end
710
+
711
+ def test_find_with_hash_conditions_on_joined_table_and_with_range
712
+ firms = DependentFirm.joins(:account).where(name: 'RailsCore', accounts: { credit_limit: 55..60 })
713
+ assert_equal 1, firms.size
714
+ assert_equal companies(:rails_core), firms.first
715
+ end
716
+
717
+ def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
718
+ david = customers(:david)
719
+ assert Customer.where('customers.name' => david.name, :address => david.address).find(david.id)
720
+ assert_raise(ActiveRecord::RecordNotFound) {
721
+ Customer.where('customers.name' => david.name + "1", :address => david.address).find(david.id)
722
+ }
723
+ end
724
+
725
+ def test_find_on_association_proxy_conditions
726
+ assert_equal [1, 2, 3, 5, 6, 7, 8, 9, 10, 12], Comment.where(post_id: authors(:david).posts).map(&:id).sort
727
+ end
728
+
729
+ def test_find_on_hash_conditions_with_range
730
+ assert_equal [1,2], Topic.where(id: 1..2).to_a.map(&:id).sort
731
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2..3).find(1) }
732
+ end
733
+
734
+ def test_find_on_hash_conditions_with_end_exclusive_range
735
+ assert_equal [1,2,3], Topic.where(id: 1..3).to_a.map(&:id).sort
736
+ assert_equal [1,2], Topic.where(id: 1...3).to_a.map(&:id).sort
737
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(id: 2...3).find(3) }
738
+ end
739
+
740
+ def test_find_on_hash_conditions_with_multiple_ranges
741
+ assert_equal [1,2,3], Comment.where(id: 1..3, post_id: 1..2).to_a.map(&:id).sort
742
+ assert_equal [1], Comment.where(id: 1..1, post_id: 1..10).to_a.map(&:id).sort
743
+ end
744
+
745
+ def test_find_on_hash_conditions_with_array_of_integers_and_ranges
746
+ assert_equal [1,2,3,5,6,7,8,9], Comment.where(id: [1..2, 3, 5, 6..8, 9]).to_a.map(&:id).sort
747
+ end
748
+
749
+ def test_find_on_hash_conditions_with_array_of_ranges
750
+ assert_equal [1,2,6,7,8], Comment.where(id: [1..2, 6..8]).to_a.map(&:id).sort
751
+ end
752
+
753
+ def test_find_on_multiple_hash_conditions
754
+ assert Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: false).find(1)
755
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) }
756
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "HHC", replies_count: 1, approved: false).find(1) }
757
+ assert_raise(ActiveRecord::RecordNotFound) { Topic.where(author_name: "David", title: "The First Topic", replies_count: 1, approved: true).find(1) }
758
+ end
759
+
760
+ def test_condition_interpolation
761
+ puts "finder_test.test_condition_interpolation"
762
+ assert_kind_of Firm, Company.where("name = '%s'", "37signals").first
763
+ assert_nil Company.where(["name = '%s'", "37signals!"]).first
764
+ assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
765
+ assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
766
+ end
767
+
768
+ def test_condition_array_interpolation
769
+ puts "finder_test.test_condition_array_interpolation"
770
+ assert_kind_of Firm, Company.where(["name = '%s'", "37signals"]).first
771
+ assert_nil Company.where(["name = '%s'", "37signals!"]).first
772
+ assert_nil Company.where(["name = '%s'", "37signals!' OR 1=1"]).first
773
+ assert_kind_of Time, Topic.where(["id = %d", 1]).first.written_on
774
+ end
775
+
776
+ def test_condition_hash_interpolation
777
+ assert_kind_of Firm, Company.where(name: "37signals").first
778
+ assert_nil Company.where(name: "37signals!").first
779
+ assert_kind_of Time, Topic.where(id: 1).first.written_on
780
+ end
781
+
782
+ def test_hash_condition_find_malformed
783
+ assert_raise(ActiveRecord::StatementInvalid) {
784
+ Company.where(id: 2, dhh: true).first
785
+ }
786
+ end
787
+
788
+ def test_hash_condition_find_with_escaped_characters
789
+ puts "finder_test.test_hash_condition_find_with_escaped_characters"
790
+ Company.create("name" => "Ain't noth'n like' \#stuff")
791
+ assert Company.where(name: "Ain't noth'n like' \#stuff").first
792
+ end
793
+
794
+ def test_hash_condition_find_with_array
795
+ puts "finder_test.test_hash_condition_find_with_array"
796
+ p1, p2 = Post.limit(2).order('id asc').to_a
797
+ assert_equal [p1, p2], Post.where(id: [p1, p2]).order('id asc').to_a
798
+ assert_equal [p1, p2], Post.where(id: [p1, p2.id]).order('id asc').to_a
799
+ end
800
+
801
+ def test_hash_condition_find_with_nil
802
+ topic = Topic.where(last_read: nil).first
803
+ assert_not_nil topic
804
+ assert_nil topic.last_read
805
+ end
806
+
807
+ def test_hash_condition_find_with_aggregate_having_one_mapping
808
+ balance = customers(:david).balance
809
+ assert_kind_of Money, balance
810
+ found_customer = Customer.where(:balance => balance).first
811
+ assert_equal customers(:david), found_customer
812
+ end
813
+
814
+ def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_aggregate
815
+ gps_location = customers(:david).gps_location
816
+ assert_kind_of GpsLocation, gps_location
817
+ found_customer = Customer.where(:gps_location => gps_location).first
818
+ assert_equal customers(:david), found_customer
819
+ end
820
+
821
+ def test_hash_condition_find_with_aggregate_having_one_mapping_and_key_value_being_attribute_value
822
+ balance = customers(:david).balance
823
+ assert_kind_of Money, balance
824
+ found_customer = Customer.where(:balance => balance.amount).first
825
+ assert_equal customers(:david), found_customer
826
+ end
827
+
828
+ def test_hash_condition_find_with_aggregate_attribute_having_same_name_as_field_and_key_value_being_attribute_value
829
+ gps_location = customers(:david).gps_location
830
+ assert_kind_of GpsLocation, gps_location
831
+ found_customer = Customer.where(:gps_location => gps_location.gps_location).first
832
+ assert_equal customers(:david), found_customer
833
+ end
834
+
835
+ def test_hash_condition_find_with_aggregate_having_three_mappings
836
+ address = customers(:david).address
837
+ assert_kind_of Address, address
838
+ found_customer = Customer.where(:address => address).first
839
+ assert_equal customers(:david), found_customer
840
+ end
841
+
842
+ def test_hash_condition_find_with_one_condition_being_aggregate_and_another_not
843
+ address = customers(:david).address
844
+ assert_kind_of Address, address
845
+ found_customer = Customer.where(:address => address, :name => customers(:david).name).first
846
+ assert_equal customers(:david), found_customer
847
+ end
848
+
849
+ def test_condition_utc_time_interpolation_with_default_timezone_local
850
+ with_env_tz 'America/New_York' do
851
+ with_timezone_config default: :local do
852
+ topic = Topic.first
853
+ assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getutc]).first
854
+ end
855
+ end
856
+ end
857
+
858
+ def test_hash_condition_utc_time_interpolation_with_default_timezone_local
859
+ puts "finder_test.test_hash_condition_utc_time_interpolation_with_default_timezone_local"
860
+ with_env_tz 'America/New_York' do
861
+ with_timezone_config default: :local do
862
+ topic = Topic.first
863
+ assert_equal topic, Topic.where(written_on: topic.written_on.getutc).first
864
+ end
865
+ end
866
+ end
867
+
868
+ def test_condition_local_time_interpolation_with_default_timezone_utc
869
+ puts "finder_test.test_condition_local_time_interpolation_with_default_timezone_utc"
870
+ with_env_tz 'America/New_York' do
871
+ with_timezone_config default: :utc do
872
+ topic = Topic.first
873
+ assert_equal topic, Topic.where(['written_on = ?', topic.written_on.getlocal]).first
874
+ end
875
+ end
876
+ end
877
+
878
+ def test_hash_condition_local_time_interpolation_with_default_timezone_utc
879
+ puts "finder_test.test_hash_condition_local_time_interpolation_with_default_timezone_utc"
880
+ with_env_tz 'America/New_York' do
881
+ with_timezone_config default: :utc do
882
+ topic = Topic.first
883
+ assert_equal topic, Topic.where(written_on: topic.written_on.getlocal).first
884
+ end
885
+ end
886
+ end
887
+
888
+ def test_bind_variables
889
+ assert_kind_of Firm, Company.where(["name = ?", "37signals"]).first
890
+ assert_nil Company.where(["name = ?", "37signals!"]).first
891
+ assert_nil Company.where(["name = ?", "37signals!' OR 1=1"]).first
892
+ assert_kind_of Time, Topic.where(["id = ?", 1]).first.written_on
893
+ assert_raise(ActiveRecord::PreparedStatementInvalid) {
894
+ Company.where(["id=? AND name = ?", 2]).first
895
+ }
896
+ assert_raise(ActiveRecord::PreparedStatementInvalid) {
897
+ Company.where(["id=?", 2, 3, 4]).first
898
+ }
899
+ end
900
+
901
+ def test_bind_variables_with_quotes
902
+ puts "finder_test.test_bind_variables_with_quotes"
903
+ Company.create("name" => "37signals' go'es agains")
904
+ assert Company.where(["name = ?", "37signals' go'es agains"]).first
905
+ end
906
+
907
+ def test_named_bind_variables_with_quotes
908
+ puts "finder_test.test_named_bind_variables_with_quotes"
909
+ Company.create("name" => "37signals' go'es agains")
910
+ assert Company.where(["name = :name", {name: "37signals' go'es agains"}]).first
911
+ end
912
+
913
+ def test_named_bind_variables
914
+ puts "finder_test.test_named_bind_variables"
915
+ assert_kind_of Firm, Company.where(["name = :name", { name: "37signals" }]).first
916
+ assert_nil Company.where(["name = :name", { name: "37signals!" }]).first
917
+ assert_nil Company.where(["name = :name", { name: "37signals!' OR 1=1" }]).first
918
+ assert_kind_of Time, Topic.where(["id = :id", { id: 1 }]).first.written_on
919
+ end
920
+
921
+ def test_string_sanitation
922
+ assert_not_equal "'something ' 1=1'", ActiveRecord::Base.sanitize("something ' 1=1")
923
+ assert_equal "'something; select table'", ActiveRecord::Base.sanitize("something; select table")
924
+ end
925
+
926
+ def test_count_by_sql
927
+ assert_equal(0, Entrant.count_by_sql("SELECT COUNT(*) FROM entrants WHERE id > 3"))
928
+ assert_equal(1, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 2]))
929
+ assert_equal(2, Entrant.count_by_sql(["SELECT COUNT(*) FROM entrants WHERE id > ?", 1]))
930
+ end
931
+
932
+ def test_find_by_one_attribute
933
+ assert_equal topics(:first), Topic.find_by_title("The First Topic")
934
+ assert_nil Topic.find_by_title("The First Topic!")
935
+ end
936
+
937
+ def test_find_by_one_attribute_bang
938
+ assert_equal topics(:first), Topic.find_by_title!("The First Topic")
939
+ assert_raises_with_message(ActiveRecord::RecordNotFound, "Couldn't find Topic") do
940
+ Topic.find_by_title!("The First Topic!")
941
+ end
942
+ end
943
+
944
+ def test_find_by_on_attribute_that_is_a_reserved_word
945
+ puts "finder_test.test_find_by_on_attribute_that_is_a_reserved_word"
946
+ dog_alias = 'Dog'
947
+ dog = Dog.create(alias: dog_alias)
948
+
949
+ assert_equal dog, Dog.find_by_alias(dog_alias)
950
+ end
951
+
952
+ def test_find_by_one_attribute_that_is_an_alias
953
+ assert_equal topics(:first), Topic.find_by_heading("The First Topic")
954
+ assert_nil Topic.find_by_heading("The First Topic!")
955
+ end
956
+
957
+ def test_find_by_one_attribute_bang_with_blank_defined
958
+ puts "finder_test.test_find_by_one_attribute_bang_with_blank_defined"
959
+ blank_topic = BlankTopic.create(title: "The Blank One")
960
+ assert_equal blank_topic, BlankTopic.find_by_title!("The Blank One")
961
+ end
962
+
963
+ def test_find_by_one_attribute_with_conditions
964
+ assert_equal accounts(:rails_core_account), Account.where('firm_id = ?', 6).find_by_credit_limit(50)
965
+ end
966
+
967
+ def test_find_by_one_attribute_that_is_an_aggregate
968
+ address = customers(:david).address
969
+ assert_kind_of Address, address
970
+ found_customer = Customer.find_by_address(address)
971
+ assert_equal customers(:david), found_customer
972
+ end
973
+
974
+ def test_find_by_one_attribute_that_is_an_aggregate_with_one_attribute_difference
975
+ address = customers(:david).address
976
+ assert_kind_of Address, address
977
+ missing_address = Address.new(address.street, address.city, address.country + "1")
978
+ assert_nil Customer.find_by_address(missing_address)
979
+ missing_address = Address.new(address.street, address.city + "1", address.country)
980
+ assert_nil Customer.find_by_address(missing_address)
981
+ missing_address = Address.new(address.street + "1", address.city, address.country)
982
+ assert_nil Customer.find_by_address(missing_address)
983
+ end
984
+
985
+ def test_find_by_two_attributes_that_are_both_aggregates
986
+ balance = customers(:david).balance
987
+ address = customers(:david).address
988
+ assert_kind_of Money, balance
989
+ assert_kind_of Address, address
990
+ found_customer = Customer.find_by_balance_and_address(balance, address)
991
+ assert_equal customers(:david), found_customer
992
+ end
993
+
994
+ def test_find_by_two_attributes_with_one_being_an_aggregate
995
+ balance = customers(:david).balance
996
+ assert_kind_of Money, balance
997
+ found_customer = Customer.find_by_balance_and_name(balance, customers(:david).name)
998
+ assert_equal customers(:david), found_customer
999
+ end
1000
+
1001
+ def test_dynamic_finder_on_one_attribute_with_conditions_returns_same_results_after_caching
1002
+ # ensure this test can run independently of order
1003
+ class << Account; self; end.send(:remove_method, :find_by_credit_limit) if Account.public_methods.include?(:find_by_credit_limit)
1004
+ a = Account.where('firm_id = ?', 6).find_by_credit_limit(50)
1005
+ assert_equal a, Account.where('firm_id = ?', 6).find_by_credit_limit(50) # find_by_credit_limit has been cached
1006
+ end
1007
+
1008
+ def test_find_by_one_attribute_with_several_options
1009
+ assert_equal accounts(:unknown), Account.order('id DESC').where('id != ?', 3).find_by_credit_limit(50)
1010
+ end
1011
+
1012
+ def test_find_by_one_missing_attribute
1013
+ assert_raise(NoMethodError) { Topic.find_by_undertitle("The First Topic!") }
1014
+ end
1015
+
1016
+ def test_find_by_invalid_method_syntax
1017
+ assert_raise(NoMethodError) { Topic.fail_to_find_by_title("The First Topic") }
1018
+ assert_raise(NoMethodError) { Topic.find_by_title?("The First Topic") }
1019
+ assert_raise(NoMethodError) { Topic.fail_to_find_or_create_by_title("Nonexistent Title") }
1020
+ assert_raise(NoMethodError) { Topic.find_or_create_by_title?("Nonexistent Title") }
1021
+ end
1022
+
1023
+ def test_find_by_two_attributes
1024
+ assert_equal topics(:first), Topic.find_by_title_and_author_name("The First Topic", "David")
1025
+ assert_nil Topic.find_by_title_and_author_name("The First Topic", "Mary")
1026
+ end
1027
+
1028
+ def test_find_by_two_attributes_but_passing_only_one
1029
+ assert_raise(ArgumentError) { Topic.find_by_title_and_author_name("The First Topic") }
1030
+ end
1031
+
1032
+ def test_find_last_with_offset
1033
+ puts "finder_test.test_find_last_with_offset"
1034
+ devs = Developer.order('id')
1035
+
1036
+ assert_equal devs[2], Developer.offset(2).first
1037
+ assert_equal devs[-3], Developer.offset(2).last
1038
+ assert_equal devs[-3], Developer.offset(2).last
1039
+ assert_equal devs[-3], Developer.offset(2).order('id DESC').first
1040
+ end
1041
+
1042
+ def test_find_by_nil_attribute
1043
+ topic = Topic.find_by_last_read nil
1044
+ assert_not_nil topic
1045
+ assert_nil topic.last_read
1046
+ end
1047
+
1048
+ def test_find_by_nil_and_not_nil_attributes
1049
+ topic = Topic.find_by_last_read_and_author_name nil, "Mary"
1050
+ assert_equal "Mary", topic.author_name
1051
+ end
1052
+
1053
+ def test_find_with_bad_sql
1054
+ assert_raise(ActiveRecord::StatementInvalid) { Topic.find_by_sql "select 1 from badtable" }
1055
+ end
1056
+
1057
+ def test_find_all_with_join
1058
+ developers_on_project_one = Developer.
1059
+ joins('LEFT JOIN developers_projects ON developers.id = developers_projects.developer_id').
1060
+ where('project_id=1').to_a
1061
+ assert_equal 3, developers_on_project_one.length
1062
+ developer_names = developers_on_project_one.map(&:name)
1063
+ assert developer_names.include?('David')
1064
+ assert developer_names.include?('Jamis')
1065
+ end
1066
+
1067
+ def test_joins_dont_clobber_id
1068
+ first = Firm.
1069
+ joins('INNER JOIN companies clients ON clients.firm_id = companies.id').
1070
+ where('companies.id = 1').first
1071
+ assert_equal 1, first.id
1072
+ end
1073
+
1074
+ def test_joins_with_string_array
1075
+ person_with_reader_and_post = Post.
1076
+ joins(["INNER JOIN categorizations ON categorizations.post_id = posts.id",
1077
+ "INNER JOIN categories ON categories.id = categorizations.category_id AND categories.type = 'SpecialCategory'"
1078
+ ])
1079
+ assert_equal 1, person_with_reader_and_post.size
1080
+ end
1081
+
1082
+ def test_find_by_id_with_conditions_with_or
1083
+ assert_nothing_raised do
1084
+ Post.where("posts.id <= 3 OR posts.#{QUOTED_TYPE} = 'Post'").find([1,2,3])
1085
+ end
1086
+ end
1087
+
1088
+ def test_find_ignores_previously_inserted_record
1089
+ puts "finder_test.test_find_ignores_previously_inserted_record"
1090
+ Post.create!(:title => 'test', :body => 'it out')
1091
+ assert_equal [], Post.where(id: nil)
1092
+ end
1093
+
1094
+ def test_find_by_empty_ids
1095
+ assert_equal [], Post.find([])
1096
+ end
1097
+
1098
+ def test_find_by_empty_in_condition
1099
+ assert_equal [], Post.where('id in (?)', [])
1100
+ end
1101
+
1102
+ def test_find_by_records
1103
+ puts "finder_test.test_find_by_records"
1104
+ p1, p2 = Post.limit(2).order('id asc').to_a
1105
+ assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2]]).order('id asc')
1106
+ assert_equal [p1, p2], Post.where(['id in (?)', [p1, p2.id]]).order('id asc')
1107
+ end
1108
+
1109
+ def test_select_value
1110
+ assert_equal "37signals", Company.connection.select_value("SELECT name FROM companies WHERE id = 1")
1111
+ assert_nil Company.connection.select_value("SELECT name FROM companies WHERE id = -1")
1112
+ # make sure we didn't break count...
1113
+ assert_equal 0, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = 'Halliburton'")
1114
+ assert_equal 1, Company.count_by_sql("SELECT COUNT(*) FROM companies WHERE name = '37signals'")
1115
+ end
1116
+
1117
+ def test_select_values
1118
+ assert_equal ["1","2","3","4","5","6","7","8","9", "10", "11"], Company.connection.select_values("SELECT id FROM companies ORDER BY id").map!(&:to_s)
1119
+ assert_equal ["37signals","Summit","Microsoft", "Flamboyant Software", "Ex Nihilo", "RailsCore", "Leetsoft", "Jadedpixel", "Odegy", "Ex Nihilo Part Deux", "Apex"], Company.connection.select_values("SELECT name FROM companies ORDER BY id")
1120
+ end
1121
+
1122
+ def test_select_rows
1123
+ assert_equal(
1124
+ [["1", "1", nil, "37signals"],
1125
+ ["2", "1", "2", "Summit"],
1126
+ ["3", "1", "1", "Microsoft"]],
1127
+ Company.connection.select_rows("SELECT id, firm_id, client_of, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}})
1128
+ assert_equal [["1", "37signals"], ["2", "Summit"], ["3", "Microsoft"]],
1129
+ Company.connection.select_rows("SELECT id, name FROM companies WHERE id IN (1,2,3) ORDER BY id").map! {|i| i.map! {|j| j.to_s unless j.nil?}}
1130
+ end
1131
+
1132
+ def test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct
1133
+ puts "finder_test.test_find_with_order_on_included_associations_with_construct_finder_sql_for_association_limiting_and_is_distinct"
1134
+ assert_equal 2, Post.includes(authors: :author_address).
1135
+ where.not(author_addresses: { id: nil }).
1136
+ order('author_addresses.id DESC').limit(2).to_a.size
1137
+
1138
+ assert_equal 3, Post.includes(author: :author_address, authors: :author_address).
1139
+ where.not(author_addresses_authors: { id: nil }).
1140
+ order('author_addresses_authors.id DESC').limit(3).to_a.size
1141
+ end
1142
+
1143
+ def test_find_with_nil_inside_set_passed_for_one_attribute
1144
+ client_of = Company.
1145
+ where(client_of: [2, 1, nil],
1146
+ name: ['37signals', 'Summit', 'Microsoft']).
1147
+ order('client_of DESC').
1148
+ map(&:client_of)
1149
+
1150
+ assert client_of.include?(nil)
1151
+ assert_equal [2, 1].sort, client_of.compact.sort
1152
+ end
1153
+
1154
+ def test_find_with_nil_inside_set_passed_for_attribute
1155
+ client_of = Company.
1156
+ where(client_of: [nil]).
1157
+ order('client_of DESC').
1158
+ map(&:client_of)
1159
+
1160
+ assert_equal [], client_of.compact
1161
+ end
1162
+
1163
+ def test_with_limiting_with_custom_select
1164
+ puts "finder_test.test_with_limiting_with_custom_select"
1165
+ posts = Post.references(:authors).merge(
1166
+ :includes => :author, :select => 'posts.*, authors.id as "author_id"',
1167
+ :limit => 3, :order => 'posts.id'
1168
+ ).to_a
1169
+ assert_equal 3, posts.size
1170
+ assert_equal [0, 1, 1], posts.map(&:author_id).sort
1171
+ end
1172
+
1173
+ def test_find_one_message_on_primary_key
1174
+ e = assert_raises(ActiveRecord::RecordNotFound) do
1175
+ Car.find(0)
1176
+ end
1177
+ assert_equal 0, e.id
1178
+ assert_equal "id", e.primary_key
1179
+ assert_equal "Car", e.model
1180
+ assert_equal "Couldn't find Car with 'id'=0", e.message
1181
+ end
1182
+
1183
+ def test_find_one_message_with_custom_primary_key
1184
+ table_with_custom_primary_key do |model|
1185
+ model.primary_key = :name
1186
+ e = assert_raises(ActiveRecord::RecordNotFound) do
1187
+ model.find 'Hello World!'
1188
+ end
1189
+ assert_equal %Q{Couldn't find MercedesCar with 'name'=Hello World!}, e.message
1190
+ end
1191
+ end
1192
+
1193
+ def test_find_some_message_with_custom_primary_key
1194
+ table_with_custom_primary_key do |model|
1195
+ model.primary_key = :name
1196
+ e = assert_raises(ActiveRecord::RecordNotFound) do
1197
+ model.find 'Hello', 'World!'
1198
+ end
1199
+ assert_equal %Q{Couldn't find all MercedesCars with 'name': (Hello, World!) (found 0 results, but was looking for 2)}, e.message
1200
+ end
1201
+ end
1202
+
1203
+ def test_find_without_primary_key
1204
+ assert_raises(ActiveRecord::UnknownPrimaryKey) do
1205
+ Matey.find(1)
1206
+ end
1207
+ end
1208
+
1209
+ def test_finder_with_offset_string
1210
+ assert_nothing_raised { Topic.offset("3").to_a }
1211
+ end
1212
+
1213
+ test "find_by with hash conditions returns the first matching record" do
1214
+ assert_equal posts(:eager_other), Post.find_by(id: posts(:eager_other).id)
1215
+ end
1216
+
1217
+ test "find_by with non-hash conditions returns the first matching record" do
1218
+ assert_equal posts(:eager_other), Post.find_by("id = #{posts(:eager_other).id}")
1219
+ end
1220
+
1221
+ test "find_by with multi-arg conditions returns the first matching record" do
1222
+ assert_equal posts(:eager_other), Post.find_by('id = ?', posts(:eager_other).id)
1223
+ end
1224
+
1225
+ test "find_by returns nil if the record is missing" do
1226
+ assert_equal nil, Post.find_by("1 = 0")
1227
+ end
1228
+
1229
+ test "find_by with associations" do
1230
+ assert_equal authors(:david), Post.find_by(author: authors(:david)).author
1231
+ assert_equal authors(:mary) , Post.find_by(author: authors(:mary) ).author
1232
+ end
1233
+
1234
+ test "find_by doesn't have implicit ordering" do
1235
+ assert_sql(/^((?!ORDER).)*$/) { Post.find_by(id: posts(:eager_other).id) }
1236
+ end
1237
+
1238
+ test "find_by! with hash conditions returns the first matching record" do
1239
+ assert_equal posts(:eager_other), Post.find_by!(id: posts(:eager_other).id)
1240
+ end
1241
+
1242
+ test "find_by! with non-hash conditions returns the first matching record" do
1243
+ assert_equal posts(:eager_other), Post.find_by!("id = #{posts(:eager_other).id}")
1244
+ end
1245
+
1246
+ test "find_by! with multi-arg conditions returns the first matching record" do
1247
+ assert_equal posts(:eager_other), Post.find_by!('id = ?', posts(:eager_other).id)
1248
+ end
1249
+
1250
+ test "find_by! doesn't have implicit ordering" do
1251
+ assert_sql(/^((?!ORDER).)*$/) { Post.find_by!(id: posts(:eager_other).id) }
1252
+ end
1253
+
1254
+ test "find_by! raises RecordNotFound if the record is missing" do
1255
+ assert_raises(ActiveRecord::RecordNotFound) do
1256
+ Post.find_by!("1 = 0")
1257
+ end
1258
+ end
1259
+
1260
+ test "find on a scope does not perform statement caching" do
1261
+ honda = cars(:honda)
1262
+ zyke = cars(:zyke)
1263
+ tyre = honda.tyres.create!
1264
+ tyre2 = zyke.tyres.create!
1265
+
1266
+ assert_equal tyre, honda.tyres.custom_find(tyre.id)
1267
+ assert_equal tyre2, zyke.tyres.custom_find(tyre2.id)
1268
+ end
1269
+
1270
+ test "find_by on a scope does not perform statement caching" do
1271
+ honda = cars(:honda)
1272
+ zyke = cars(:zyke)
1273
+ tyre = honda.tyres.create!
1274
+ tyre2 = zyke.tyres.create!
1275
+
1276
+ assert_equal tyre, honda.tyres.custom_find_by(id: tyre.id)
1277
+ assert_equal tyre2, zyke.tyres.custom_find_by(id: tyre2.id)
1278
+ end
1279
+
1280
+ protected
1281
+ def table_with_custom_primary_key
1282
+ yield(Class.new(Toy) do
1283
+ def self.name
1284
+ 'MercedesCar'
1285
+ end
1286
+ end)
1287
+ end
1288
+
1289
+ def assert_raises_with_message(exception_class, message, &block)
1290
+ err = assert_raises(exception_class) { block.call }
1291
+ assert_match message, err.message
1292
+ end
1293
+
1294
+ end