activerecord-nuodb-adapter 1.0.3 → 1.0.4

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