activerecord 2.3.18 → 3.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (378) hide show
  1. data/CHANGELOG +105 -34
  2. data/examples/performance.rb +3 -39
  3. data/examples/simple.rb +14 -0
  4. data/lib/active_record.rb +81 -47
  5. data/lib/active_record/aggregations.rb +1 -3
  6. data/lib/active_record/association_preload.rb +39 -54
  7. data/lib/active_record/associations.rb +262 -419
  8. data/lib/active_record/associations/association_collection.rb +85 -100
  9. data/lib/active_record/associations/association_proxy.rb +20 -18
  10. data/lib/active_record/associations/belongs_to_association.rb +8 -8
  11. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +13 -35
  12. data/lib/active_record/associations/has_many_association.rb +11 -19
  13. data/lib/active_record/associations/has_many_through_association.rb +30 -183
  14. data/lib/active_record/associations/has_one_association.rb +10 -10
  15. data/lib/active_record/associations/has_one_through_association.rb +13 -11
  16. data/lib/active_record/associations/through_association_scope.rb +153 -0
  17. data/lib/active_record/attribute_methods.rb +17 -370
  18. data/lib/active_record/attribute_methods/before_type_cast.rb +33 -0
  19. data/lib/active_record/attribute_methods/dirty.rb +87 -0
  20. data/lib/active_record/attribute_methods/primary_key.rb +44 -0
  21. data/lib/active_record/attribute_methods/query.rb +37 -0
  22. data/lib/active_record/attribute_methods/read.rb +116 -0
  23. data/lib/active_record/attribute_methods/time_zone_conversion.rb +60 -0
  24. data/lib/active_record/attribute_methods/write.rb +37 -0
  25. data/lib/active_record/autosave_association.rb +20 -41
  26. data/lib/active_record/base.rb +357 -1180
  27. data/lib/active_record/batches.rb +10 -16
  28. data/lib/active_record/callbacks.rb +66 -126
  29. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +17 -13
  30. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +5 -25
  31. data/lib/active_record/connection_adapters/abstract/database_statements.rb +4 -43
  32. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -2
  33. data/lib/active_record/connection_adapters/abstract/quoting.rb +15 -4
  34. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  35. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +18 -72
  36. data/lib/active_record/connection_adapters/abstract_adapter.rb +16 -49
  37. data/lib/active_record/connection_adapters/mysql_adapter.rb +15 -27
  38. data/lib/active_record/connection_adapters/postgresql_adapter.rb +84 -46
  39. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +9 -3
  40. data/lib/active_record/connection_adapters/sqlite_adapter.rb +34 -65
  41. data/lib/active_record/fixtures.rb +21 -25
  42. data/lib/active_record/locale/en.yml +9 -27
  43. data/lib/active_record/locking/optimistic.rb +16 -48
  44. data/lib/active_record/migration.rb +59 -46
  45. data/lib/active_record/named_scope.rb +85 -92
  46. data/lib/active_record/nested_attributes.rb +18 -24
  47. data/lib/active_record/observer.rb +18 -94
  48. data/lib/active_record/railtie.rb +83 -0
  49. data/lib/active_record/railties/controller_runtime.rb +38 -0
  50. data/lib/active_record/railties/databases.rake +477 -0
  51. data/lib/active_record/railties/subscriber.rb +27 -0
  52. data/lib/active_record/reflection.rb +2 -15
  53. data/lib/active_record/relation.rb +339 -0
  54. data/lib/active_record/relation/calculations.rb +259 -0
  55. data/lib/active_record/relation/finder_methods.rb +315 -0
  56. data/lib/active_record/relation/predicate_builder.rb +46 -0
  57. data/lib/active_record/relation/query_methods.rb +218 -0
  58. data/lib/active_record/relation/spawn_methods.rb +102 -0
  59. data/lib/active_record/schema_dumper.rb +10 -6
  60. data/lib/active_record/serialization.rb +31 -74
  61. data/lib/active_record/serializers/xml_serializer.rb +33 -121
  62. data/lib/active_record/session_store.rb +1 -9
  63. data/lib/active_record/test_case.rb +1 -3
  64. data/lib/active_record/timestamp.rb +7 -5
  65. data/lib/active_record/transactions.rb +9 -9
  66. data/lib/active_record/validations.rb +51 -1100
  67. data/lib/active_record/validations/associated.rb +47 -0
  68. data/lib/active_record/validations/uniqueness.rb +181 -0
  69. data/lib/active_record/version.rb +3 -3
  70. data/lib/generators/active_record.rb +30 -0
  71. data/lib/generators/active_record/migration/migration_generator.rb +25 -0
  72. data/lib/generators/active_record/migration/templates/migration.rb +11 -0
  73. data/lib/generators/active_record/model/model_generator.rb +33 -0
  74. data/lib/generators/active_record/model/templates/migration.rb +16 -0
  75. data/lib/generators/active_record/model/templates/model.rb +5 -0
  76. data/lib/generators/active_record/observer/observer_generator.rb +15 -0
  77. data/lib/generators/active_record/observer/templates/observer.rb +2 -0
  78. data/lib/generators/active_record/session_migration/session_migration_generator.rb +24 -0
  79. data/lib/generators/active_record/session_migration/templates/migration.rb +16 -0
  80. metadata +67 -325
  81. data/RUNNING_UNIT_TESTS +0 -36
  82. data/Rakefile +0 -268
  83. data/install.rb +0 -30
  84. data/lib/active_record/calculations.rb +0 -321
  85. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -57
  86. data/lib/active_record/dirty.rb +0 -183
  87. data/lib/active_record/serializers/json_serializer.rb +0 -91
  88. data/lib/activerecord.rb +0 -2
  89. data/test/assets/example.log +0 -1
  90. data/test/assets/flowers.jpg +0 -0
  91. data/test/cases/aaa_create_tables_test.rb +0 -24
  92. data/test/cases/active_schema_test_mysql.rb +0 -122
  93. data/test/cases/active_schema_test_postgresql.rb +0 -24
  94. data/test/cases/adapter_test.rb +0 -144
  95. data/test/cases/aggregations_test.rb +0 -167
  96. data/test/cases/ar_schema_test.rb +0 -32
  97. data/test/cases/associations/belongs_to_associations_test.rb +0 -438
  98. data/test/cases/associations/callbacks_test.rb +0 -161
  99. data/test/cases/associations/cascaded_eager_loading_test.rb +0 -131
  100. data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +0 -36
  101. data/test/cases/associations/eager_load_nested_include_test.rb +0 -131
  102. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +0 -19
  103. data/test/cases/associations/eager_singularization_test.rb +0 -145
  104. data/test/cases/associations/eager_test.rb +0 -852
  105. data/test/cases/associations/extension_test.rb +0 -62
  106. data/test/cases/associations/habtm_join_table_test.rb +0 -56
  107. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +0 -827
  108. data/test/cases/associations/has_many_associations_test.rb +0 -1273
  109. data/test/cases/associations/has_many_through_associations_test.rb +0 -360
  110. data/test/cases/associations/has_one_associations_test.rb +0 -330
  111. data/test/cases/associations/has_one_through_associations_test.rb +0 -209
  112. data/test/cases/associations/inner_join_association_test.rb +0 -93
  113. data/test/cases/associations/inverse_associations_test.rb +0 -566
  114. data/test/cases/associations/join_model_test.rb +0 -712
  115. data/test/cases/associations_test.rb +0 -282
  116. data/test/cases/attribute_methods_test.rb +0 -305
  117. data/test/cases/autosave_association_test.rb +0 -1218
  118. data/test/cases/base_test.rb +0 -2166
  119. data/test/cases/batches_test.rb +0 -81
  120. data/test/cases/binary_test.rb +0 -30
  121. data/test/cases/calculations_test.rb +0 -360
  122. data/test/cases/callbacks_observers_test.rb +0 -38
  123. data/test/cases/callbacks_test.rb +0 -438
  124. data/test/cases/class_inheritable_attributes_test.rb +0 -32
  125. data/test/cases/column_alias_test.rb +0 -17
  126. data/test/cases/column_definition_test.rb +0 -70
  127. data/test/cases/connection_pool_test.rb +0 -25
  128. data/test/cases/connection_test_firebird.rb +0 -8
  129. data/test/cases/connection_test_mysql.rb +0 -65
  130. data/test/cases/copy_table_test_sqlite.rb +0 -80
  131. data/test/cases/counter_cache_test.rb +0 -84
  132. data/test/cases/database_statements_test.rb +0 -12
  133. data/test/cases/datatype_test_postgresql.rb +0 -204
  134. data/test/cases/date_time_test.rb +0 -37
  135. data/test/cases/default_test_firebird.rb +0 -16
  136. data/test/cases/defaults_test.rb +0 -111
  137. data/test/cases/deprecated_finder_test.rb +0 -30
  138. data/test/cases/dirty_test.rb +0 -316
  139. data/test/cases/finder_respond_to_test.rb +0 -76
  140. data/test/cases/finder_test.rb +0 -1098
  141. data/test/cases/fixtures_test.rb +0 -661
  142. data/test/cases/helper.rb +0 -68
  143. data/test/cases/i18n_test.rb +0 -46
  144. data/test/cases/inheritance_test.rb +0 -262
  145. data/test/cases/invalid_date_test.rb +0 -24
  146. data/test/cases/json_serialization_test.rb +0 -219
  147. data/test/cases/lifecycle_test.rb +0 -193
  148. data/test/cases/locking_test.rb +0 -350
  149. data/test/cases/method_scoping_test.rb +0 -704
  150. data/test/cases/migration_test.rb +0 -1649
  151. data/test/cases/migration_test_firebird.rb +0 -124
  152. data/test/cases/mixin_test.rb +0 -96
  153. data/test/cases/modules_test.rb +0 -109
  154. data/test/cases/multiple_db_test.rb +0 -85
  155. data/test/cases/named_scope_test.rb +0 -372
  156. data/test/cases/nested_attributes_test.rb +0 -840
  157. data/test/cases/pk_test.rb +0 -119
  158. data/test/cases/pooled_connections_test.rb +0 -103
  159. data/test/cases/query_cache_test.rb +0 -129
  160. data/test/cases/readonly_test.rb +0 -107
  161. data/test/cases/reflection_test.rb +0 -234
  162. data/test/cases/reload_models_test.rb +0 -22
  163. data/test/cases/repair_helper.rb +0 -50
  164. data/test/cases/reserved_word_test_mysql.rb +0 -176
  165. data/test/cases/sanitize_test.rb +0 -25
  166. data/test/cases/schema_authorization_test_postgresql.rb +0 -75
  167. data/test/cases/schema_dumper_test.rb +0 -211
  168. data/test/cases/schema_test_postgresql.rb +0 -178
  169. data/test/cases/serialization_test.rb +0 -47
  170. data/test/cases/sp_test_mysql.rb +0 -16
  171. data/test/cases/synonym_test_oracle.rb +0 -17
  172. data/test/cases/timestamp_test.rb +0 -75
  173. data/test/cases/transactions_test.rb +0 -543
  174. data/test/cases/unconnected_test.rb +0 -32
  175. data/test/cases/validations_i18n_test.rb +0 -925
  176. data/test/cases/validations_test.rb +0 -1684
  177. data/test/cases/xml_serialization_test.rb +0 -240
  178. data/test/cases/yaml_serialization_test.rb +0 -11
  179. data/test/config.rb +0 -5
  180. data/test/connections/jdbc_jdbcderby/connection.rb +0 -18
  181. data/test/connections/jdbc_jdbch2/connection.rb +0 -18
  182. data/test/connections/jdbc_jdbchsqldb/connection.rb +0 -18
  183. data/test/connections/jdbc_jdbcmysql/connection.rb +0 -26
  184. data/test/connections/jdbc_jdbcpostgresql/connection.rb +0 -26
  185. data/test/connections/jdbc_jdbcsqlite3/connection.rb +0 -25
  186. data/test/connections/native_db2/connection.rb +0 -25
  187. data/test/connections/native_firebird/connection.rb +0 -26
  188. data/test/connections/native_frontbase/connection.rb +0 -27
  189. data/test/connections/native_mysql/connection.rb +0 -25
  190. data/test/connections/native_openbase/connection.rb +0 -21
  191. data/test/connections/native_oracle/connection.rb +0 -27
  192. data/test/connections/native_postgresql/connection.rb +0 -21
  193. data/test/connections/native_sqlite/connection.rb +0 -25
  194. data/test/connections/native_sqlite3/connection.rb +0 -25
  195. data/test/connections/native_sqlite3/in_memory_connection.rb +0 -18
  196. data/test/connections/native_sybase/connection.rb +0 -23
  197. data/test/fixtures/accounts.yml +0 -29
  198. data/test/fixtures/all/developers.yml +0 -0
  199. data/test/fixtures/all/people.csv +0 -0
  200. data/test/fixtures/all/tasks.yml +0 -0
  201. data/test/fixtures/author_addresses.yml +0 -5
  202. data/test/fixtures/author_favorites.yml +0 -4
  203. data/test/fixtures/authors.yml +0 -9
  204. data/test/fixtures/binaries.yml +0 -132
  205. data/test/fixtures/books.yml +0 -7
  206. data/test/fixtures/categories.yml +0 -14
  207. data/test/fixtures/categories/special_categories.yml +0 -9
  208. data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +0 -4
  209. data/test/fixtures/categories_ordered.yml +0 -7
  210. data/test/fixtures/categories_posts.yml +0 -23
  211. data/test/fixtures/categorizations.yml +0 -17
  212. data/test/fixtures/clubs.yml +0 -6
  213. data/test/fixtures/comments.yml +0 -59
  214. data/test/fixtures/companies.yml +0 -56
  215. data/test/fixtures/computers.yml +0 -4
  216. data/test/fixtures/courses.yml +0 -7
  217. data/test/fixtures/customers.yml +0 -26
  218. data/test/fixtures/developers.yml +0 -21
  219. data/test/fixtures/developers_projects.yml +0 -17
  220. data/test/fixtures/edges.yml +0 -6
  221. data/test/fixtures/entrants.yml +0 -14
  222. data/test/fixtures/faces.yml +0 -11
  223. data/test/fixtures/fk_test_has_fk.yml +0 -3
  224. data/test/fixtures/fk_test_has_pk.yml +0 -2
  225. data/test/fixtures/funny_jokes.yml +0 -10
  226. data/test/fixtures/interests.yml +0 -33
  227. data/test/fixtures/items.yml +0 -4
  228. data/test/fixtures/jobs.yml +0 -7
  229. data/test/fixtures/legacy_things.yml +0 -3
  230. data/test/fixtures/mateys.yml +0 -4
  231. data/test/fixtures/member_types.yml +0 -6
  232. data/test/fixtures/members.yml +0 -6
  233. data/test/fixtures/memberships.yml +0 -20
  234. data/test/fixtures/men.yml +0 -5
  235. data/test/fixtures/minimalistics.yml +0 -2
  236. data/test/fixtures/mixed_case_monkeys.yml +0 -6
  237. data/test/fixtures/mixins.yml +0 -29
  238. data/test/fixtures/movies.yml +0 -7
  239. data/test/fixtures/naked/csv/accounts.csv +0 -1
  240. data/test/fixtures/naked/yml/accounts.yml +0 -1
  241. data/test/fixtures/naked/yml/companies.yml +0 -1
  242. data/test/fixtures/naked/yml/courses.yml +0 -1
  243. data/test/fixtures/organizations.yml +0 -5
  244. data/test/fixtures/owners.yml +0 -7
  245. data/test/fixtures/parrots.yml +0 -27
  246. data/test/fixtures/parrots_pirates.yml +0 -7
  247. data/test/fixtures/people.yml +0 -15
  248. data/test/fixtures/pets.yml +0 -14
  249. data/test/fixtures/pirates.yml +0 -9
  250. data/test/fixtures/polymorphic_designs.yml +0 -19
  251. data/test/fixtures/polymorphic_prices.yml +0 -19
  252. data/test/fixtures/posts.yml +0 -52
  253. data/test/fixtures/price_estimates.yml +0 -7
  254. data/test/fixtures/projects.yml +0 -7
  255. data/test/fixtures/readers.yml +0 -9
  256. data/test/fixtures/references.yml +0 -17
  257. data/test/fixtures/reserved_words/distinct.yml +0 -5
  258. data/test/fixtures/reserved_words/distincts_selects.yml +0 -11
  259. data/test/fixtures/reserved_words/group.yml +0 -14
  260. data/test/fixtures/reserved_words/select.yml +0 -8
  261. data/test/fixtures/reserved_words/values.yml +0 -7
  262. data/test/fixtures/ships.yml +0 -5
  263. data/test/fixtures/sponsors.yml +0 -9
  264. data/test/fixtures/subscribers.yml +0 -7
  265. data/test/fixtures/subscriptions.yml +0 -12
  266. data/test/fixtures/taggings.yml +0 -28
  267. data/test/fixtures/tags.yml +0 -7
  268. data/test/fixtures/tasks.yml +0 -7
  269. data/test/fixtures/tees.yml +0 -4
  270. data/test/fixtures/ties.yml +0 -4
  271. data/test/fixtures/topics.yml +0 -42
  272. data/test/fixtures/toys.yml +0 -4
  273. data/test/fixtures/treasures.yml +0 -10
  274. data/test/fixtures/vertices.yml +0 -4
  275. data/test/fixtures/warehouse-things.yml +0 -3
  276. data/test/fixtures/zines.yml +0 -5
  277. data/test/migrations/broken/100_migration_that_raises_exception.rb +0 -10
  278. data/test/migrations/decimal/1_give_me_big_numbers.rb +0 -15
  279. data/test/migrations/duplicate/1_people_have_last_names.rb +0 -9
  280. data/test/migrations/duplicate/2_we_need_reminders.rb +0 -12
  281. data/test/migrations/duplicate/3_foo.rb +0 -7
  282. data/test/migrations/duplicate/3_innocent_jointable.rb +0 -12
  283. data/test/migrations/duplicate_names/20080507052938_chunky.rb +0 -7
  284. data/test/migrations/duplicate_names/20080507053028_chunky.rb +0 -7
  285. data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +0 -12
  286. data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +0 -9
  287. data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +0 -12
  288. data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +0 -9
  289. data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +0 -8
  290. data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +0 -12
  291. data/test/migrations/missing/1000_people_have_middle_names.rb +0 -9
  292. data/test/migrations/missing/1_people_have_last_names.rb +0 -9
  293. data/test/migrations/missing/3_we_need_reminders.rb +0 -12
  294. data/test/migrations/missing/4_innocent_jointable.rb +0 -12
  295. data/test/migrations/valid/1_people_have_last_names.rb +0 -9
  296. data/test/migrations/valid/2_we_need_reminders.rb +0 -12
  297. data/test/migrations/valid/3_innocent_jointable.rb +0 -12
  298. data/test/models/author.rb +0 -151
  299. data/test/models/auto_id.rb +0 -4
  300. data/test/models/binary.rb +0 -2
  301. data/test/models/bird.rb +0 -9
  302. data/test/models/book.rb +0 -4
  303. data/test/models/categorization.rb +0 -5
  304. data/test/models/category.rb +0 -34
  305. data/test/models/citation.rb +0 -6
  306. data/test/models/club.rb +0 -13
  307. data/test/models/column_name.rb +0 -3
  308. data/test/models/comment.rb +0 -29
  309. data/test/models/company.rb +0 -173
  310. data/test/models/company_in_module.rb +0 -78
  311. data/test/models/computer.rb +0 -3
  312. data/test/models/contact.rb +0 -16
  313. data/test/models/contract.rb +0 -5
  314. data/test/models/course.rb +0 -3
  315. data/test/models/customer.rb +0 -73
  316. data/test/models/default.rb +0 -2
  317. data/test/models/developer.rb +0 -101
  318. data/test/models/edge.rb +0 -5
  319. data/test/models/entrant.rb +0 -3
  320. data/test/models/essay.rb +0 -3
  321. data/test/models/event.rb +0 -3
  322. data/test/models/event_author.rb +0 -8
  323. data/test/models/face.rb +0 -7
  324. data/test/models/guid.rb +0 -2
  325. data/test/models/interest.rb +0 -5
  326. data/test/models/invoice.rb +0 -4
  327. data/test/models/item.rb +0 -7
  328. data/test/models/job.rb +0 -5
  329. data/test/models/joke.rb +0 -3
  330. data/test/models/keyboard.rb +0 -3
  331. data/test/models/legacy_thing.rb +0 -3
  332. data/test/models/line_item.rb +0 -3
  333. data/test/models/man.rb +0 -9
  334. data/test/models/matey.rb +0 -4
  335. data/test/models/member.rb +0 -12
  336. data/test/models/member_detail.rb +0 -5
  337. data/test/models/member_type.rb +0 -3
  338. data/test/models/membership.rb +0 -9
  339. data/test/models/minimalistic.rb +0 -2
  340. data/test/models/mixed_case_monkey.rb +0 -3
  341. data/test/models/movie.rb +0 -5
  342. data/test/models/order.rb +0 -4
  343. data/test/models/organization.rb +0 -6
  344. data/test/models/owner.rb +0 -5
  345. data/test/models/parrot.rb +0 -22
  346. data/test/models/person.rb +0 -16
  347. data/test/models/pet.rb +0 -5
  348. data/test/models/pirate.rb +0 -80
  349. data/test/models/polymorphic_design.rb +0 -3
  350. data/test/models/polymorphic_price.rb +0 -3
  351. data/test/models/post.rb +0 -102
  352. data/test/models/price_estimate.rb +0 -3
  353. data/test/models/project.rb +0 -30
  354. data/test/models/reader.rb +0 -4
  355. data/test/models/reference.rb +0 -4
  356. data/test/models/reply.rb +0 -46
  357. data/test/models/ship.rb +0 -19
  358. data/test/models/ship_part.rb +0 -7
  359. data/test/models/sponsor.rb +0 -4
  360. data/test/models/subject.rb +0 -4
  361. data/test/models/subscriber.rb +0 -8
  362. data/test/models/subscription.rb +0 -4
  363. data/test/models/tag.rb +0 -7
  364. data/test/models/tagging.rb +0 -10
  365. data/test/models/task.rb +0 -3
  366. data/test/models/tee.rb +0 -4
  367. data/test/models/tie.rb +0 -4
  368. data/test/models/topic.rb +0 -80
  369. data/test/models/toy.rb +0 -6
  370. data/test/models/treasure.rb +0 -8
  371. data/test/models/vertex.rb +0 -9
  372. data/test/models/warehouse_thing.rb +0 -5
  373. data/test/models/zine.rb +0 -3
  374. data/test/schema/mysql_specific_schema.rb +0 -31
  375. data/test/schema/postgresql_specific_schema.rb +0 -114
  376. data/test/schema/schema.rb +0 -550
  377. data/test/schema/schema2.rb +0 -6
  378. data/test/schema/sqlite_specific_schema.rb +0 -25
@@ -1,2166 +0,0 @@
1
- require "cases/helper"
2
- require 'models/post'
3
- require 'models/event_author'
4
- require 'models/topic'
5
- require 'models/reply'
6
- require 'models/category'
7
- require 'models/company'
8
- require 'models/customer'
9
- require 'models/developer'
10
- require 'models/project'
11
- require 'models/default'
12
- require 'models/auto_id'
13
- require 'models/column_name'
14
- require 'models/subscriber'
15
- require 'models/keyboard'
16
- require 'models/comment'
17
- require 'models/minimalistic'
18
- require 'models/warehouse_thing'
19
- require 'models/parrot'
20
- require 'rexml/document'
21
-
22
- class Category < ActiveRecord::Base; end
23
- class Categorization < ActiveRecord::Base; end
24
- class Smarts < ActiveRecord::Base; end
25
- class CreditCard < ActiveRecord::Base
26
- class PinNumber < ActiveRecord::Base
27
- class CvvCode < ActiveRecord::Base; end
28
- class SubCvvCode < CvvCode; end
29
- end
30
- class SubPinNumber < PinNumber; end
31
- class Brand < Category; end
32
- end
33
- class MasterCreditCard < ActiveRecord::Base; end
34
- class Post < ActiveRecord::Base; end
35
- class Computer < ActiveRecord::Base; end
36
- class NonExistentTable < ActiveRecord::Base; end
37
- class TestOracleDefault < ActiveRecord::Base; end
38
-
39
- class LoosePerson < ActiveRecord::Base
40
- self.table_name = 'people'
41
- self.abstract_class = true
42
- attr_protected :credit_rating, :administrator
43
- end
44
-
45
- class LooseDescendant < LoosePerson
46
- attr_protected :phone_number
47
- end
48
-
49
- class LooseDescendantSecond< LoosePerson
50
- attr_protected :phone_number
51
- attr_protected :name
52
- end
53
-
54
- class TightPerson < ActiveRecord::Base
55
- self.table_name = 'people'
56
- attr_accessible :name, :address
57
- end
58
-
59
- class TightDescendant < TightPerson
60
- attr_accessible :phone_number
61
- end
62
-
63
- class ReadonlyTitlePost < Post
64
- attr_readonly :title
65
- end
66
-
67
- class Booleantest < ActiveRecord::Base; end
68
-
69
- class Task < ActiveRecord::Base
70
- attr_protected :starting
71
- end
72
-
73
- class TopicWithProtectedContentAndAccessibleAuthorName < ActiveRecord::Base
74
- self.table_name = 'topics'
75
- attr_accessible :author_name
76
- attr_protected :content
77
- end
78
-
79
- class BasicsTest < ActiveRecord::TestCase
80
- fixtures :topics, :companies, :developers, :projects, :computers, :accounts, :minimalistics, 'warehouse-things', :authors, :categorizations, :categories, :posts
81
-
82
- def test_column_names_are_escaped
83
- conn = ActiveRecord::Base.connection
84
- classname = conn.class.name[/[^:]*$/]
85
- badchar = {
86
- 'SQLite3Adapter' => '"',
87
- 'MysqlAdapter' => '`',
88
- 'Mysql2Adapter' => '`',
89
- 'PostgreSQLAdapter' => '"',
90
- 'OracleAdapter' => '"',
91
- }.fetch(classname) {
92
- raise "need a bad char for #{classname}"
93
- }
94
-
95
- quoted = conn.quote_column_name "foo#{badchar}bar"
96
- assert_equal("#{badchar}foo#{badchar * 2}bar#{badchar}", quoted)
97
- end
98
-
99
- def test_table_exists
100
- assert !NonExistentTable.table_exists?
101
- assert Topic.table_exists?
102
- end
103
-
104
- def test_set_attributes
105
- topic = Topic.find(1)
106
- topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
107
- topic.save
108
- assert_equal("Budget", topic.title)
109
- assert_equal("Jason", topic.author_name)
110
- assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
111
- end
112
-
113
- def test_integers_as_nil
114
- test = AutoId.create('value' => '')
115
- assert_nil AutoId.find(test.id).value
116
- end
117
-
118
- def test_set_attributes_with_block
119
- topic = Topic.new do |t|
120
- t.title = "Budget"
121
- t.author_name = "Jason"
122
- end
123
-
124
- assert_equal("Budget", topic.title)
125
- assert_equal("Jason", topic.author_name)
126
- end
127
-
128
- def test_respond_to?
129
- topic = Topic.find(1)
130
- assert topic.respond_to?("title")
131
- assert topic.respond_to?("title?")
132
- assert topic.respond_to?("title=")
133
- assert topic.respond_to?(:title)
134
- assert topic.respond_to?(:title?)
135
- assert topic.respond_to?(:title=)
136
- assert topic.respond_to?("author_name")
137
- assert topic.respond_to?("attribute_names")
138
- assert !topic.respond_to?("nothingness")
139
- assert !topic.respond_to?(:nothingness)
140
- end
141
-
142
- def test_array_content
143
- topic = Topic.new
144
- topic.content = %w( one two three )
145
- topic.save
146
-
147
- assert_equal(%w( one two three ), Topic.find(topic.id).content)
148
- end
149
-
150
- def test_read_attributes_before_type_cast
151
- category = Category.new({:name=>"Test categoty", :type => nil})
152
- category_attrs = {"name"=>"Test categoty", "type" => nil, "categorizations_count" => nil}
153
- assert_equal category_attrs , category.attributes_before_type_cast
154
- end
155
-
156
- if current_adapter?(:MysqlAdapter)
157
- def test_read_attributes_before_type_cast_on_boolean
158
- bool = Booleantest.create({ "value" => false })
159
- assert_equal "0", bool.reload.attributes_before_type_cast["value"]
160
- end
161
- end
162
-
163
- def test_read_attributes_before_type_cast_on_datetime
164
- developer = Developer.find(:first)
165
- assert_equal developer.created_at.to_s(:db) , developer.attributes_before_type_cast["created_at"]
166
- end
167
-
168
- def test_hash_content
169
- topic = Topic.new
170
- topic.content = { "one" => 1, "two" => 2 }
171
- topic.save
172
-
173
- assert_equal 2, Topic.find(topic.id).content["two"]
174
-
175
- topic.content_will_change!
176
- topic.content["three"] = 3
177
- topic.save
178
-
179
- assert_equal 3, Topic.find(topic.id).content["three"]
180
- end
181
-
182
- def test_update_array_content
183
- topic = Topic.new
184
- topic.content = %w( one two three )
185
-
186
- topic.content.push "four"
187
- assert_equal(%w( one two three four ), topic.content)
188
-
189
- topic.save
190
-
191
- topic = Topic.find(topic.id)
192
- topic.content << "five"
193
- assert_equal(%w( one two three four five ), topic.content)
194
- end
195
-
196
- def test_case_sensitive_attributes_hash
197
- # DB2 is not case-sensitive
198
- return true if current_adapter?(:DB2Adapter)
199
-
200
- assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes
201
- end
202
-
203
- def test_create
204
- topic = Topic.new
205
- topic.title = "New Topic"
206
- topic.save
207
- topic_reloaded = Topic.find(topic.id)
208
- assert_equal("New Topic", topic_reloaded.title)
209
- end
210
-
211
- def test_save!
212
- topic = Topic.new(:title => "New Topic")
213
- assert topic.save!
214
-
215
- reply = Reply.new
216
- assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
217
- end
218
-
219
- def test_save_null_string_attributes
220
- topic = Topic.find(1)
221
- topic.attributes = { "title" => "null", "author_name" => "null" }
222
- topic.save!
223
- topic.reload
224
- assert_equal("null", topic.title)
225
- assert_equal("null", topic.author_name)
226
- end
227
-
228
- def test_save_nil_string_attributes
229
- topic = Topic.find(1)
230
- topic.title = nil
231
- topic.save!
232
- topic.reload
233
- assert_nil topic.title
234
- end
235
-
236
- def test_save_for_record_with_only_primary_key
237
- minimalistic = Minimalistic.new
238
- assert_nothing_raised { minimalistic.save }
239
- end
240
-
241
- def test_save_for_record_with_only_primary_key_that_is_provided
242
- assert_nothing_raised { Minimalistic.create!(:id => 2) }
243
- end
244
-
245
- def test_hashes_not_mangled
246
- new_topic = { :title => "New Topic" }
247
- new_topic_values = { :title => "AnotherTopic" }
248
-
249
- topic = Topic.new(new_topic)
250
- assert_equal new_topic[:title], topic.title
251
-
252
- topic.attributes= new_topic_values
253
- assert_equal new_topic_values[:title], topic.title
254
- end
255
-
256
- def test_create_many
257
- topics = Topic.create([ { "title" => "first" }, { "title" => "second" }])
258
- assert_equal 2, topics.size
259
- assert_equal "first", topics.first.title
260
- end
261
-
262
- def test_create_columns_not_equal_attributes
263
- topic = Topic.new
264
- topic.title = 'Another New Topic'
265
- topic.send :write_attribute, 'does_not_exist', 'test'
266
- assert_nothing_raised { topic.save }
267
- end
268
-
269
- def test_create_through_factory
270
- topic = Topic.create("title" => "New Topic")
271
- topicReloaded = Topic.find(topic.id)
272
- assert_equal(topic, topicReloaded)
273
- end
274
-
275
- def test_create_through_factory_with_block
276
- topic = Topic.create("title" => "New Topic") do |t|
277
- t.author_name = "David"
278
- end
279
- topicReloaded = Topic.find(topic.id)
280
- assert_equal("New Topic", topic.title)
281
- assert_equal("David", topic.author_name)
282
- end
283
-
284
- def test_create_many_through_factory_with_block
285
- topics = Topic.create([ { "title" => "first" }, { "title" => "second" }]) do |t|
286
- t.author_name = "David"
287
- end
288
- assert_equal 2, topics.size
289
- topic1, topic2 = Topic.find(topics[0].id), Topic.find(topics[1].id)
290
- assert_equal "first", topic1.title
291
- assert_equal "David", topic1.author_name
292
- assert_equal "second", topic2.title
293
- assert_equal "David", topic2.author_name
294
- end
295
-
296
- def test_update
297
- topic = Topic.new
298
- topic.title = "Another New Topic"
299
- topic.written_on = "2003-12-12 23:23:00"
300
- topic.save
301
- topicReloaded = Topic.find(topic.id)
302
- assert_equal("Another New Topic", topicReloaded.title)
303
-
304
- topicReloaded.title = "Updated topic"
305
- topicReloaded.save
306
-
307
- topicReloadedAgain = Topic.find(topic.id)
308
-
309
- assert_equal("Updated topic", topicReloadedAgain.title)
310
- end
311
-
312
- def test_update_columns_not_equal_attributes
313
- topic = Topic.new
314
- topic.title = "Still another topic"
315
- topic.save
316
-
317
- topicReloaded = Topic.find(topic.id)
318
- topicReloaded.title = "A New Topic"
319
- topicReloaded.send :write_attribute, 'does_not_exist', 'test'
320
- assert_nothing_raised { topicReloaded.save }
321
- end
322
-
323
- def test_update_for_record_with_only_primary_key
324
- minimalistic = minimalistics(:first)
325
- assert_nothing_raised { minimalistic.save }
326
- end
327
-
328
- def test_write_attribute
329
- topic = Topic.new
330
- topic.send(:write_attribute, :title, "Still another topic")
331
- assert_equal "Still another topic", topic.title
332
-
333
- topic.send(:write_attribute, "title", "Still another topic: part 2")
334
- assert_equal "Still another topic: part 2", topic.title
335
- end
336
-
337
- def test_read_attribute
338
- topic = Topic.new
339
- topic.title = "Don't change the topic"
340
- assert_equal "Don't change the topic", topic.send(:read_attribute, "title")
341
- assert_equal "Don't change the topic", topic["title"]
342
-
343
- assert_equal "Don't change the topic", topic.send(:read_attribute, :title)
344
- assert_equal "Don't change the topic", topic[:title]
345
- end
346
-
347
- def test_read_attribute_when_false
348
- topic = topics(:first)
349
- topic.approved = false
350
- assert !topic.approved?, "approved should be false"
351
- topic.approved = "false"
352
- assert !topic.approved?, "approved should be false"
353
- end
354
-
355
- def test_read_attribute_when_true
356
- topic = topics(:first)
357
- topic.approved = true
358
- assert topic.approved?, "approved should be true"
359
- topic.approved = "true"
360
- assert topic.approved?, "approved should be true"
361
- end
362
-
363
- def test_read_write_boolean_attribute
364
- topic = Topic.new
365
- # puts ""
366
- # puts "New Topic"
367
- # puts topic.inspect
368
- topic.approved = "false"
369
- # puts "Expecting false"
370
- # puts topic.inspect
371
- assert !topic.approved?, "approved should be false"
372
- topic.approved = "false"
373
- # puts "Expecting false"
374
- # puts topic.inspect
375
- assert !topic.approved?, "approved should be false"
376
- topic.approved = "true"
377
- # puts "Expecting true"
378
- # puts topic.inspect
379
- assert topic.approved?, "approved should be true"
380
- topic.approved = "true"
381
- # puts "Expecting true"
382
- # puts topic.inspect
383
- assert topic.approved?, "approved should be true"
384
- # puts ""
385
- end
386
-
387
- def test_query_attribute_string
388
- [nil, "", " "].each do |value|
389
- assert_equal false, Topic.new(:author_name => value).author_name?
390
- end
391
-
392
- assert_equal true, Topic.new(:author_name => "Name").author_name?
393
- end
394
-
395
- def test_query_attribute_number
396
- [nil, 0, "0"].each do |value|
397
- assert_equal false, Developer.new(:salary => value).salary?
398
- end
399
-
400
- assert_equal true, Developer.new(:salary => 1).salary?
401
- assert_equal true, Developer.new(:salary => "1").salary?
402
- end
403
-
404
- def test_query_attribute_boolean
405
- [nil, "", false, "false", "f", 0].each do |value|
406
- assert_equal false, Topic.new(:approved => value).approved?
407
- end
408
-
409
- [true, "true", "1", 1].each do |value|
410
- assert_equal true, Topic.new(:approved => value).approved?
411
- end
412
- end
413
-
414
- def test_query_attribute_with_custom_fields
415
- object = Company.find_by_sql(<<-SQL).first
416
- SELECT c1.*, c2.ruby_type as string_value, c2.rating as int_value
417
- FROM companies c1, companies c2
418
- WHERE c1.firm_id = c2.id
419
- AND c1.id = 2
420
- SQL
421
-
422
- assert_equal "Firm", object.string_value
423
- assert object.string_value?
424
-
425
- object.string_value = " "
426
- assert !object.string_value?
427
-
428
- assert_equal 1, object.int_value.to_i
429
- assert object.int_value?
430
-
431
- object.int_value = "0"
432
- assert !object.int_value?
433
- end
434
-
435
-
436
- def test_reader_for_invalid_column_names
437
- Topic.send(:define_read_method, "mumub-jumbo".to_sym, "mumub-jumbo", nil)
438
- assert !Topic.generated_methods.include?("mumub-jumbo")
439
- end
440
-
441
- def test_non_attribute_access_and_assignment
442
- topic = Topic.new
443
- assert !topic.respond_to?("mumbo")
444
- assert_raise(NoMethodError) { topic.mumbo }
445
- assert_raise(NoMethodError) { topic.mumbo = 5 }
446
- end
447
-
448
- def test_preserving_date_objects
449
- if current_adapter?(:SybaseAdapter, :OracleAdapter)
450
- # Sybase ctlib does not (yet?) support the date type; use datetime instead.
451
- # Oracle treats all dates/times as Time.
452
- assert_kind_of(
453
- Time, Topic.find(1).last_read,
454
- "The last_read attribute should be of the Time class"
455
- )
456
- else
457
- assert_kind_of(
458
- Date, Topic.find(1).last_read,
459
- "The last_read attribute should be of the Date class"
460
- )
461
- end
462
- end
463
-
464
- def test_preserving_time_objects
465
- assert_kind_of(
466
- Time, Topic.find(1).bonus_time,
467
- "The bonus_time attribute should be of the Time class"
468
- )
469
-
470
- assert_kind_of(
471
- Time, Topic.find(1).written_on,
472
- "The written_on attribute should be of the Time class"
473
- )
474
-
475
- # For adapters which support microsecond resolution.
476
- if current_adapter?(:PostgreSQLAdapter)
477
- assert_equal 11, Topic.find(1).written_on.sec
478
- assert_equal 223300, Topic.find(1).written_on.usec
479
- assert_equal 9900, Topic.find(2).written_on.usec
480
- end
481
- end
482
-
483
- def test_custom_mutator
484
- topic = Topic.find(1)
485
- # This mutator is protected in the class definition
486
- topic.send(:approved=, true)
487
- assert topic.instance_variable_get("@custom_approved")
488
- end
489
-
490
- def test_delete
491
- topic = Topic.find(1)
492
- assert_equal topic, topic.delete, 'topic.delete did not return self'
493
- assert topic.frozen?, 'topic not frozen after delete'
494
- assert topic.destroyed?, 'topic not marked as being destroyed'
495
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
496
- end
497
-
498
- def test_delete_doesnt_run_callbacks
499
- Topic.find(1).delete
500
- assert_not_nil Topic.find(2)
501
- end
502
-
503
- def test_destroy
504
- topic = Topic.find(1)
505
- assert_equal topic, topic.destroy, 'topic.destroy did not return self'
506
- assert topic.frozen?, 'topic not frozen after destroy'
507
- assert topic.destroyed?, 'topic not marked as being destroyed'
508
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
509
- end
510
-
511
- def test_record_not_found_exception
512
- assert_raise(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(99999) }
513
- end
514
-
515
- def test_initialize_with_attributes
516
- topic = Topic.new({
517
- "title" => "initialized from attributes", "written_on" => "2003-12-12 23:23"
518
- })
519
-
520
- assert_equal("initialized from attributes", topic.title)
521
- end
522
-
523
- def test_initialize_with_invalid_attribute
524
- begin
525
- topic = Topic.new({ "title" => "test",
526
- "last_read(1i)" => "2005", "last_read(2i)" => "2", "last_read(3i)" => "31"})
527
- rescue ActiveRecord::MultiparameterAssignmentErrors => ex
528
- assert_equal(1, ex.errors.size)
529
- assert_equal("last_read", ex.errors[0].attribute)
530
- end
531
- end
532
-
533
- def test_load
534
- topics = Topic.find(:all, :order => 'id')
535
- assert_equal(4, topics.size)
536
- assert_equal(topics(:first).title, topics.first.title)
537
- end
538
-
539
- def test_load_with_condition
540
- topics = Topic.find(:all, :conditions => "author_name = 'Mary'")
541
-
542
- assert_equal(1, topics.size)
543
- assert_equal(topics(:second).title, topics.first.title)
544
- end
545
-
546
- def test_table_name_guesses
547
- classes = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]
548
-
549
- assert_equal "topics", Topic.table_name
550
-
551
- assert_equal "categories", Category.table_name
552
- assert_equal "smarts", Smarts.table_name
553
- assert_equal "credit_cards", CreditCard.table_name
554
- assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
555
- assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
556
- assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
557
- assert_equal "categories", CreditCard::Brand.table_name
558
- assert_equal "master_credit_cards", MasterCreditCard.table_name
559
-
560
- ActiveRecord::Base.pluralize_table_names = false
561
- classes.each(&:reset_table_name)
562
-
563
- assert_equal "category", Category.table_name
564
- assert_equal "smarts", Smarts.table_name
565
- assert_equal "credit_card", CreditCard.table_name
566
- assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
567
- assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
568
- assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
569
- assert_equal "category", CreditCard::Brand.table_name
570
- assert_equal "master_credit_card", MasterCreditCard.table_name
571
-
572
- ActiveRecord::Base.pluralize_table_names = true
573
- classes.each(&:reset_table_name)
574
-
575
- ActiveRecord::Base.table_name_prefix = "test_"
576
- Category.reset_table_name
577
- assert_equal "test_categories", Category.table_name
578
- ActiveRecord::Base.table_name_suffix = "_test"
579
- Category.reset_table_name
580
- assert_equal "test_categories_test", Category.table_name
581
- ActiveRecord::Base.table_name_prefix = ""
582
- Category.reset_table_name
583
- assert_equal "categories_test", Category.table_name
584
- ActiveRecord::Base.table_name_suffix = ""
585
- Category.reset_table_name
586
- assert_equal "categories", Category.table_name
587
-
588
- ActiveRecord::Base.pluralize_table_names = false
589
- ActiveRecord::Base.table_name_prefix = "test_"
590
- Category.reset_table_name
591
- assert_equal "test_category", Category.table_name
592
- ActiveRecord::Base.table_name_suffix = "_test"
593
- Category.reset_table_name
594
- assert_equal "test_category_test", Category.table_name
595
- ActiveRecord::Base.table_name_prefix = ""
596
- Category.reset_table_name
597
- assert_equal "category_test", Category.table_name
598
- ActiveRecord::Base.table_name_suffix = ""
599
- Category.reset_table_name
600
- assert_equal "category", Category.table_name
601
-
602
- ActiveRecord::Base.pluralize_table_names = true
603
- classes.each(&:reset_table_name)
604
- end
605
-
606
- def test_destroy_all
607
- conditions = "author_name = 'Mary'"
608
- topics_by_mary = Topic.all(:conditions => conditions, :order => 'id')
609
- assert ! topics_by_mary.empty?
610
-
611
- assert_difference('Topic.count', -topics_by_mary.size) do
612
- destroyed = Topic.destroy_all(conditions).sort_by(&:id)
613
- assert_equal topics_by_mary, destroyed
614
- assert destroyed.all? { |topic| topic.frozen? }
615
- end
616
- end
617
-
618
- def test_destroy_many
619
- clients = Client.find([2, 3], :order => 'id')
620
-
621
- assert_difference('Client.count', -2) do
622
- destroyed = Client.destroy([2, 3]).sort_by(&:id)
623
- assert_equal clients, destroyed
624
- assert destroyed.all? { |client| client.frozen? }
625
- end
626
- end
627
-
628
- def test_delete_many
629
- original_count = Topic.count
630
- Topic.delete(deleting = [1, 2])
631
- assert_equal original_count - deleting.size, Topic.count
632
- end
633
-
634
- def test_boolean_attributes
635
- assert ! Topic.find(1).approved?
636
- assert Topic.find(2).approved?
637
- end
638
-
639
- def test_update_all
640
- assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
641
- assert_equal "bulk updated!", Topic.find(1).content
642
- assert_equal "bulk updated!", Topic.find(2).content
643
-
644
- assert_equal Topic.count, Topic.update_all(['content = ?', 'bulk updated again!'])
645
- assert_equal "bulk updated again!", Topic.find(1).content
646
- assert_equal "bulk updated again!", Topic.find(2).content
647
-
648
- assert_equal Topic.count, Topic.update_all(['content = ?', nil])
649
- assert_nil Topic.find(1).content
650
- end
651
-
652
- def test_update_all_with_hash
653
- assert_not_nil Topic.find(1).last_read
654
- assert_equal Topic.count, Topic.update_all(:content => 'bulk updated with hash!', :last_read => nil)
655
- assert_equal "bulk updated with hash!", Topic.find(1).content
656
- assert_equal "bulk updated with hash!", Topic.find(2).content
657
- assert_nil Topic.find(1).last_read
658
- assert_nil Topic.find(2).last_read
659
- end
660
-
661
- def test_update_all_with_non_standard_table_name
662
- assert_equal 1, WarehouseThing.update_all(['value = ?', 0], ['id = ?', 1])
663
- assert_equal 0, WarehouseThing.find(1).value
664
- end
665
-
666
- if current_adapter?(:MysqlAdapter)
667
- def test_update_all_with_order_and_limit
668
- assert_equal 1, Topic.update_all("content = 'bulk updated!'", nil, :limit => 1, :order => 'id DESC')
669
- end
670
- end
671
-
672
- def test_update_all_ignores_order_without_limit_from_association
673
- author = authors(:david)
674
- assert_nothing_raised do
675
- assert_equal author.posts_with_comments_and_categories.length, author.posts_with_comments_and_categories.update_all([ "body = ?", "bulk update!" ])
676
- end
677
- end
678
-
679
- def test_update_all_with_order_and_limit_updates_subset_only
680
- author = authors(:david)
681
- assert_nothing_raised do
682
- assert_equal 1, author.posts_sorted_by_id_limited.size
683
- assert_equal 2, author.posts_sorted_by_id_limited.find(:all, :limit => 2).size
684
- assert_equal 1, author.posts_sorted_by_id_limited.update_all([ "body = ?", "bulk update!" ])
685
- assert_equal "bulk update!", posts(:welcome).body
686
- assert_not_equal "bulk update!", posts(:thinking).body
687
- end
688
- end
689
-
690
- def test_update_many
691
- topic_data = { 1 => { "content" => "1 updated" }, 2 => { "content" => "2 updated" } }
692
- updated = Topic.update(topic_data.keys, topic_data.values)
693
-
694
- assert_equal 2, updated.size
695
- assert_equal "1 updated", Topic.find(1).content
696
- assert_equal "2 updated", Topic.find(2).content
697
- end
698
-
699
- def test_delete_all
700
- assert Topic.count > 0
701
-
702
- assert_equal Topic.count, Topic.delete_all
703
- end
704
-
705
- def test_update_by_condition
706
- Topic.update_all "content = 'bulk updated!'", ["approved = ?", true]
707
- assert_equal "Have a nice day", Topic.find(1).content
708
- assert_equal "bulk updated!", Topic.find(2).content
709
- end
710
-
711
- def test_attribute_present
712
- t = Topic.new
713
- t.title = "hello there!"
714
- t.written_on = Time.now
715
- assert t.attribute_present?("title")
716
- assert t.attribute_present?("written_on")
717
- assert !t.attribute_present?("content")
718
- end
719
-
720
- def test_attribute_keys_on_new_instance
721
- t = Topic.new
722
- assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
723
- assert_raise(NoMethodError) { t.title2 }
724
- end
725
-
726
- def test_class_name
727
- ActiveSupport::Deprecation.silence do
728
- assert_equal "Firm", ActiveRecord::Base.class_name("firms")
729
- assert_equal "Category", ActiveRecord::Base.class_name("categories")
730
- assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder")
731
-
732
- ActiveRecord::Base.pluralize_table_names = false
733
- assert_equal "Firms", ActiveRecord::Base.class_name( "firms" )
734
- ActiveRecord::Base.pluralize_table_names = true
735
-
736
- ActiveRecord::Base.table_name_prefix = "test_"
737
- assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms" )
738
- ActiveRecord::Base.table_name_suffix = "_tests"
739
- assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms_tests" )
740
- ActiveRecord::Base.table_name_prefix = ""
741
- assert_equal "Firm", ActiveRecord::Base.class_name( "firms_tests" )
742
- ActiveRecord::Base.table_name_suffix = ""
743
- assert_equal "Firm", ActiveRecord::Base.class_name( "firms" )
744
- end
745
- end
746
-
747
- def test_null_fields
748
- assert_nil Topic.find(1).parent_id
749
- assert_nil Topic.create("title" => "Hey you").parent_id
750
- end
751
-
752
- def test_default_values
753
- topic = Topic.new
754
- assert topic.approved?
755
- assert_nil topic.written_on
756
- assert_nil topic.bonus_time
757
- assert_nil topic.last_read
758
-
759
- topic.save
760
-
761
- topic = Topic.find(topic.id)
762
- assert topic.approved?
763
- assert_nil topic.last_read
764
-
765
- # Oracle has some funky default handling, so it requires a bit of
766
- # extra testing. See ticket #2788.
767
- if current_adapter?(:OracleAdapter)
768
- test = TestOracleDefault.new
769
- assert_equal "X", test.test_char
770
- assert_equal "hello", test.test_string
771
- assert_equal 3, test.test_int
772
- end
773
- end
774
-
775
- # Oracle, and Sybase do not have a TIME datatype.
776
- unless current_adapter?(:OracleAdapter, :SybaseAdapter)
777
- def test_utc_as_time_zone
778
- Topic.default_timezone = :utc
779
- attributes = { "bonus_time" => "5:42:00AM" }
780
- topic = Topic.find(1)
781
- topic.attributes = attributes
782
- assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
783
- Topic.default_timezone = :local
784
- end
785
-
786
- def test_utc_as_time_zone_and_new
787
- Topic.default_timezone = :utc
788
- attributes = { "bonus_time(1i)"=>"2000",
789
- "bonus_time(2i)"=>"1",
790
- "bonus_time(3i)"=>"1",
791
- "bonus_time(4i)"=>"10",
792
- "bonus_time(5i)"=>"35",
793
- "bonus_time(6i)"=>"50" }
794
- topic = Topic.new(attributes)
795
- assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
796
- Topic.default_timezone = :local
797
- end
798
- end
799
-
800
- def test_default_values_on_empty_strings
801
- topic = Topic.new
802
- topic.approved = nil
803
- topic.last_read = nil
804
-
805
- topic.save
806
-
807
- topic = Topic.find(topic.id)
808
- assert_nil topic.last_read
809
-
810
- # Sybase adapter does not allow nulls in boolean columns
811
- if current_adapter?(:SybaseAdapter)
812
- assert topic.approved == false
813
- else
814
- assert_nil topic.approved
815
- end
816
- end
817
-
818
- def test_equality
819
- assert_equal Topic.find(1), Topic.find(2).topic
820
- end
821
-
822
- def test_equality_of_new_records
823
- assert_not_equal Topic.new, Topic.new
824
- end
825
-
826
- def test_hashing
827
- assert_equal [ Topic.find(1) ], [ Topic.find(2).topic ] & [ Topic.find(1) ]
828
- end
829
-
830
- def test_delete_new_record
831
- client = Client.new
832
- client.delete
833
- assert client.frozen?
834
- end
835
-
836
- def test_delete_record_with_associations
837
- client = Client.find(3)
838
- client.delete
839
- assert client.frozen?
840
- assert_kind_of Firm, client.firm
841
- assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
842
- end
843
-
844
- def test_destroy_new_record
845
- client = Client.new
846
- client.destroy
847
- assert client.frozen?
848
- end
849
-
850
- def test_destroy_record_with_associations
851
- client = Client.find(3)
852
- client.destroy
853
- assert client.frozen?
854
- assert_kind_of Firm, client.firm
855
- assert_raise(ActiveSupport::FrozenObjectError) { client.name = "something else" }
856
- end
857
-
858
- def test_update_attribute
859
- assert !Topic.find(1).approved?
860
- Topic.find(1).update_attribute("approved", true)
861
- assert Topic.find(1).approved?
862
-
863
- Topic.find(1).update_attribute(:approved, false)
864
- assert !Topic.find(1).approved?
865
- end
866
-
867
- def test_update_attributes
868
- topic = Topic.find(1)
869
- assert !topic.approved?
870
- assert_equal "The First Topic", topic.title
871
-
872
- topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
873
- topic.reload
874
- assert topic.approved?
875
- assert_equal "The First Topic Updated", topic.title
876
-
877
- topic.update_attributes(:approved => false, :title => "The First Topic")
878
- topic.reload
879
- assert !topic.approved?
880
- assert_equal "The First Topic", topic.title
881
- end
882
-
883
- def test_update_attributes!
884
- reply = Reply.find(2)
885
- assert_equal "The Second Topic of the day", reply.title
886
- assert_equal "Have a nice day", reply.content
887
-
888
- reply.update_attributes!("title" => "The Second Topic of the day updated", "content" => "Have a nice evening")
889
- reply.reload
890
- assert_equal "The Second Topic of the day updated", reply.title
891
- assert_equal "Have a nice evening", reply.content
892
-
893
- reply.update_attributes!(:title => "The Second Topic of the day", :content => "Have a nice day")
894
- reply.reload
895
- assert_equal "The Second Topic of the day", reply.title
896
- assert_equal "Have a nice day", reply.content
897
-
898
- assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(:title => nil, :content => "Have a nice evening") }
899
- end
900
-
901
- def test_mass_assignment_should_raise_exception_if_accessible_and_protected_attribute_writers_are_both_used
902
- topic = TopicWithProtectedContentAndAccessibleAuthorName.new
903
- assert_raise(RuntimeError) { topic.attributes = { "author_name" => "me" } }
904
- assert_raise(RuntimeError) { topic.attributes = { "content" => "stuff" } }
905
- end
906
-
907
- def test_mass_assignment_protection
908
- firm = Firm.new
909
- firm.attributes = { "name" => "Next Angle", "rating" => 5 }
910
- assert_equal 1, firm.rating
911
- end
912
-
913
- def test_mass_assignment_protection_against_class_attribute_writers
914
- [:logger, :configurations, :primary_key_prefix_type, :table_name_prefix, :table_name_suffix, :pluralize_table_names, :colorize_logging,
915
- :default_timezone, :schema_format, :lock_optimistically, :record_timestamps].each do |method|
916
- assert Task.respond_to?(method)
917
- assert Task.respond_to?("#{method}=")
918
- assert Task.new.respond_to?(method)
919
- assert !Task.new.respond_to?("#{method}=")
920
- end
921
- end
922
-
923
- def test_customized_primary_key_remains_protected
924
- subscriber = Subscriber.new(:nick => 'webster123', :name => 'nice try')
925
- assert_nil subscriber.id
926
-
927
- keyboard = Keyboard.new(:key_number => 9, :name => 'nice try')
928
- assert_nil keyboard.id
929
- end
930
-
931
- def test_customized_primary_key_remains_protected_when_referred_to_as_id
932
- subscriber = Subscriber.new(:id => 'webster123', :name => 'nice try')
933
- assert_nil subscriber.id
934
-
935
- keyboard = Keyboard.new(:id => 9, :name => 'nice try')
936
- assert_nil keyboard.id
937
- end
938
-
939
- def test_mass_assigning_invalid_attribute
940
- firm = Firm.new
941
-
942
- assert_raise(ActiveRecord::UnknownAttributeError) do
943
- firm.attributes = { "id" => 5, "type" => "Client", "i_dont_even_exist" => 20 }
944
- end
945
- end
946
-
947
- def test_mass_assignment_protection_on_defaults
948
- firm = Firm.new
949
- firm.attributes = { "id" => 5, "type" => "Client" }
950
- assert_nil firm.id
951
- assert_equal "Firm", firm[:type]
952
- end
953
-
954
- def test_mass_assignment_accessible
955
- reply = Reply.new("title" => "hello", "content" => "world", "approved" => true)
956
- reply.save
957
-
958
- assert reply.approved?
959
-
960
- reply.approved = false
961
- reply.save
962
-
963
- assert !reply.approved?
964
- end
965
-
966
- def test_mass_assignment_protection_inheritance
967
- assert_nil LoosePerson.accessible_attributes
968
- assert_equal Set.new([ 'credit_rating', 'administrator' ]), LoosePerson.protected_attributes
969
-
970
- assert_nil LooseDescendant.accessible_attributes
971
- assert_equal Set.new([ 'credit_rating', 'administrator', 'phone_number' ]), LooseDescendant.protected_attributes
972
-
973
- assert_nil LooseDescendantSecond.accessible_attributes
974
- assert_equal Set.new([ 'credit_rating', 'administrator', 'phone_number', 'name' ]), LooseDescendantSecond.protected_attributes, 'Running attr_protected twice in one class should merge the protections'
975
-
976
- assert_nil TightPerson.protected_attributes
977
- assert_equal Set.new([ 'name', 'address' ]), TightPerson.accessible_attributes
978
-
979
- assert_nil TightDescendant.protected_attributes
980
- assert_equal Set.new([ 'name', 'address', 'phone_number' ]), TightDescendant.accessible_attributes
981
- end
982
-
983
- def test_readonly_attributes
984
- assert_equal Set.new([ 'title' , 'comments_count' ]), ReadonlyTitlePost.readonly_attributes
985
-
986
- post = ReadonlyTitlePost.create(:title => "cannot change this", :body => "changeable")
987
- post.reload
988
- assert_equal "cannot change this", post.title
989
-
990
- post.update_attributes(:title => "try to change", :body => "changed")
991
- post.reload
992
- assert_equal "cannot change this", post.title
993
- assert_equal "changed", post.body
994
- end
995
-
996
- def test_multiparameter_attribute_assignment_via_association_proxy
997
- multiparameter_date_attribute = {
998
- "ends_on(1i)" => "2004", "ends_on(2i)" => "6", "ends_on(3i)" => "24",
999
- "ends_on(4i)" => "16", "ends_on(5i)" => "24", "ends_on(6i)" => "00"
1000
- }
1001
-
1002
- author = Author.create(:name => "dhh")
1003
- event = author.events.create(multiparameter_date_attribute)
1004
-
1005
- assert_equal Time.local(2004,6,24,16,24,0),event.ends_on
1006
- end
1007
-
1008
- def test_multiparameter_attributes_on_date
1009
- attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "24" }
1010
- topic = Topic.find(1)
1011
- topic.attributes = attributes
1012
- # note that extra #to_date call allows test to pass for Oracle, which
1013
- # treats dates/times the same
1014
- assert_date_from_db Date.new(2004, 6, 24), topic.last_read.to_date
1015
- end
1016
-
1017
- def test_multiparameter_attributes_on_date_with_empty_year
1018
- attributes = { "last_read(1i)" => "", "last_read(2i)" => "6", "last_read(3i)" => "24" }
1019
- topic = Topic.find(1)
1020
- topic.attributes = attributes
1021
- # note that extra #to_date call allows test to pass for Oracle, which
1022
- # treats dates/times the same
1023
- assert_date_from_db Date.new(1, 6, 24), topic.last_read.to_date
1024
- end
1025
-
1026
- def test_multiparameter_attributes_on_date_with_empty_month
1027
- attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "", "last_read(3i)" => "24" }
1028
- topic = Topic.find(1)
1029
- topic.attributes = attributes
1030
- # note that extra #to_date call allows test to pass for Oracle, which
1031
- # treats dates/times the same
1032
- assert_date_from_db Date.new(2004, 1, 24), topic.last_read.to_date
1033
- end
1034
-
1035
- def test_multiparameter_attributes_on_date_with_empty_day
1036
- attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "6", "last_read(3i)" => "" }
1037
- topic = Topic.find(1)
1038
- topic.attributes = attributes
1039
- # note that extra #to_date call allows test to pass for Oracle, which
1040
- # treats dates/times the same
1041
- assert_date_from_db Date.new(2004, 6, 1), topic.last_read.to_date
1042
- end
1043
-
1044
- def test_multiparameter_attributes_on_date_with_empty_day_and_year
1045
- attributes = { "last_read(1i)" => "", "last_read(2i)" => "6", "last_read(3i)" => "" }
1046
- topic = Topic.find(1)
1047
- topic.attributes = attributes
1048
- # note that extra #to_date call allows test to pass for Oracle, which
1049
- # treats dates/times the same
1050
- assert_date_from_db Date.new(1, 6, 1), topic.last_read.to_date
1051
- end
1052
-
1053
- def test_multiparameter_attributes_on_date_with_empty_day_and_month
1054
- attributes = { "last_read(1i)" => "2004", "last_read(2i)" => "", "last_read(3i)" => "" }
1055
- topic = Topic.find(1)
1056
- topic.attributes = attributes
1057
- # note that extra #to_date call allows test to pass for Oracle, which
1058
- # treats dates/times the same
1059
- assert_date_from_db Date.new(2004, 1, 1), topic.last_read.to_date
1060
- end
1061
-
1062
- def test_multiparameter_attributes_on_date_with_empty_year_and_month
1063
- attributes = { "last_read(1i)" => "", "last_read(2i)" => "", "last_read(3i)" => "24" }
1064
- topic = Topic.find(1)
1065
- topic.attributes = attributes
1066
- # note that extra #to_date call allows test to pass for Oracle, which
1067
- # treats dates/times the same
1068
- assert_date_from_db Date.new(1, 1, 24), topic.last_read.to_date
1069
- end
1070
-
1071
- def test_multiparameter_attributes_on_date_with_all_empty
1072
- attributes = { "last_read(1i)" => "", "last_read(2i)" => "", "last_read(3i)" => "" }
1073
- topic = Topic.find(1)
1074
- topic.attributes = attributes
1075
- assert_nil topic.last_read
1076
- end
1077
-
1078
- def test_multiparameter_attributes_on_time
1079
- attributes = {
1080
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
1081
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
1082
- }
1083
- topic = Topic.find(1)
1084
- topic.attributes = attributes
1085
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
1086
- end
1087
-
1088
- def test_multiparameter_attributes_on_time_with_old_date
1089
- attributes = {
1090
- "written_on(1i)" => "1850", "written_on(2i)" => "6", "written_on(3i)" => "24",
1091
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
1092
- }
1093
- topic = Topic.find(1)
1094
- topic.attributes = attributes
1095
- # testing against to_s(:db) representation because either a Time or a DateTime might be returned, depending on platform
1096
- assert_equal "1850-06-24 16:24:00", topic.written_on.to_s(:db)
1097
- end
1098
-
1099
- def test_multiparameter_attributes_on_time_with_utc
1100
- ActiveRecord::Base.default_timezone = :utc
1101
- attributes = {
1102
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
1103
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
1104
- }
1105
- topic = Topic.find(1)
1106
- topic.attributes = attributes
1107
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
1108
- ensure
1109
- ActiveRecord::Base.default_timezone = :local
1110
- end
1111
-
1112
- def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes
1113
- ActiveRecord::Base.time_zone_aware_attributes = true
1114
- ActiveRecord::Base.default_timezone = :utc
1115
- Time.zone = ActiveSupport::TimeZone[-28800]
1116
- attributes = {
1117
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
1118
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
1119
- }
1120
- topic = Topic.find(1)
1121
- topic.attributes = attributes
1122
- assert_equal Time.utc(2004, 6, 24, 23, 24, 0), topic.written_on
1123
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on.time
1124
- assert_equal Time.zone, topic.written_on.time_zone
1125
- ensure
1126
- ActiveRecord::Base.time_zone_aware_attributes = false
1127
- ActiveRecord::Base.default_timezone = :local
1128
- Time.zone = nil
1129
- end
1130
-
1131
- def test_multiparameter_attributes_on_time_with_time_zone_aware_attributes_false
1132
- ActiveRecord::Base.time_zone_aware_attributes = false
1133
- Time.zone = ActiveSupport::TimeZone[-28800]
1134
- attributes = {
1135
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
1136
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
1137
- }
1138
- topic = Topic.find(1)
1139
- topic.attributes = attributes
1140
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
1141
- assert_equal false, topic.written_on.respond_to?(:time_zone)
1142
- ensure
1143
- Time.zone = nil
1144
- end
1145
-
1146
- def test_multiparameter_attributes_on_time_with_skip_time_zone_conversion_for_attributes
1147
- ActiveRecord::Base.time_zone_aware_attributes = true
1148
- ActiveRecord::Base.default_timezone = :utc
1149
- Time.zone = ActiveSupport::TimeZone[-28800]
1150
- Topic.skip_time_zone_conversion_for_attributes = [:written_on]
1151
- attributes = {
1152
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
1153
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "00"
1154
- }
1155
- topic = Topic.find(1)
1156
- topic.attributes = attributes
1157
- assert_equal Time.utc(2004, 6, 24, 16, 24, 0), topic.written_on
1158
- assert_equal false, topic.written_on.respond_to?(:time_zone)
1159
- ensure
1160
- ActiveRecord::Base.time_zone_aware_attributes = false
1161
- ActiveRecord::Base.default_timezone = :local
1162
- Time.zone = nil
1163
- Topic.skip_time_zone_conversion_for_attributes = []
1164
- end
1165
-
1166
- def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion
1167
- ActiveRecord::Base.time_zone_aware_attributes = true
1168
- ActiveRecord::Base.default_timezone = :utc
1169
- Time.zone = ActiveSupport::TimeZone[-28800]
1170
- attributes = {
1171
- "bonus_time(1i)" => "2000", "bonus_time(2i)" => "1", "bonus_time(3i)" => "1",
1172
- "bonus_time(4i)" => "16", "bonus_time(5i)" => "24"
1173
- }
1174
- topic = Topic.find(1)
1175
- topic.attributes = attributes
1176
- assert_equal Time.utc(2000, 1, 1, 16, 24, 0), topic.bonus_time
1177
- assert topic.bonus_time.utc?
1178
- ensure
1179
- ActiveRecord::Base.time_zone_aware_attributes = false
1180
- ActiveRecord::Base.default_timezone = :local
1181
- Time.zone = nil
1182
- end
1183
-
1184
- def test_multiparameter_attributes_on_time_with_empty_seconds
1185
- attributes = {
1186
- "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24",
1187
- "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => ""
1188
- }
1189
- topic = Topic.find(1)
1190
- topic.attributes = attributes
1191
- assert_equal Time.local(2004, 6, 24, 16, 24, 0), topic.written_on
1192
- end
1193
-
1194
- def test_multiparameter_mass_assignment_protector
1195
- task = Task.new
1196
- time = Time.mktime(2000, 1, 1, 1)
1197
- task.starting = time
1198
- attributes = { "starting(1i)" => "2004", "starting(2i)" => "6", "starting(3i)" => "24" }
1199
- task.attributes = attributes
1200
- assert_equal time, task.starting
1201
- end
1202
-
1203
- def test_multiparameter_assignment_of_aggregation
1204
- customer = Customer.new
1205
- address = Address.new("The Street", "The City", "The Country")
1206
- attributes = { "address(1)" => address.street, "address(2)" => address.city, "address(3)" => address.country }
1207
- customer.attributes = attributes
1208
- assert_equal address, customer.address
1209
- end
1210
-
1211
- def test_attributes_on_dummy_time
1212
- # Oracle, and Sybase do not have a TIME datatype.
1213
- return true if current_adapter?(:OracleAdapter, :SybaseAdapter)
1214
-
1215
- attributes = {
1216
- "bonus_time" => "5:42:00AM"
1217
- }
1218
- topic = Topic.find(1)
1219
- topic.attributes = attributes
1220
- assert_equal Time.local(2000, 1, 1, 5, 42, 0), topic.bonus_time
1221
- end
1222
-
1223
- def test_boolean
1224
- b_nil = Booleantest.create({ "value" => nil })
1225
- nil_id = b_nil.id
1226
- b_false = Booleantest.create({ "value" => false })
1227
- false_id = b_false.id
1228
- b_true = Booleantest.create({ "value" => true })
1229
- true_id = b_true.id
1230
-
1231
- b_nil = Booleantest.find(nil_id)
1232
- assert_nil b_nil.value
1233
- b_false = Booleantest.find(false_id)
1234
- assert !b_false.value?
1235
- b_true = Booleantest.find(true_id)
1236
- assert b_true.value?
1237
- end
1238
-
1239
- def test_boolean_cast_from_string
1240
- b_blank = Booleantest.create({ "value" => "" })
1241
- blank_id = b_blank.id
1242
- b_false = Booleantest.create({ "value" => "0" })
1243
- false_id = b_false.id
1244
- b_true = Booleantest.create({ "value" => "1" })
1245
- true_id = b_true.id
1246
-
1247
- b_blank = Booleantest.find(blank_id)
1248
- assert_nil b_blank.value
1249
- b_false = Booleantest.find(false_id)
1250
- assert !b_false.value?
1251
- b_true = Booleantest.find(true_id)
1252
- assert b_true.value?
1253
- end
1254
-
1255
- def test_new_record_returns_boolean
1256
- assert_equal Topic.new.new_record?, true
1257
- assert_equal Topic.find(1).new_record?, false
1258
- end
1259
-
1260
- def test_clone
1261
- topic = Topic.find(1)
1262
- cloned_topic = nil
1263
- assert_nothing_raised { cloned_topic = topic.clone }
1264
- assert_equal topic.title, cloned_topic.title
1265
- assert cloned_topic.new_record?
1266
-
1267
- # test if the attributes have been cloned
1268
- topic.title = "a"
1269
- cloned_topic.title = "b"
1270
- assert_equal "a", topic.title
1271
- assert_equal "b", cloned_topic.title
1272
-
1273
- # test if the attribute values have been cloned
1274
- topic.title = {"a" => "b"}
1275
- cloned_topic = topic.clone
1276
- cloned_topic.title["a"] = "c"
1277
- assert_equal "b", topic.title["a"]
1278
-
1279
- #test if attributes set as part of after_initialize are cloned correctly
1280
- assert_equal topic.author_email_address, cloned_topic.author_email_address
1281
-
1282
- # test if saved clone object differs from original
1283
- cloned_topic.save
1284
- assert !cloned_topic.new_record?
1285
- assert cloned_topic.id != topic.id
1286
- end
1287
-
1288
- def test_clone_with_aggregate_of_same_name_as_attribute
1289
- dev = DeveloperWithAggregate.find(1)
1290
- assert_kind_of DeveloperSalary, dev.salary
1291
-
1292
- clone = nil
1293
- assert_nothing_raised { clone = dev.clone }
1294
- assert_kind_of DeveloperSalary, clone.salary
1295
- assert_equal dev.salary.amount, clone.salary.amount
1296
- assert clone.new_record?
1297
-
1298
- # test if the attributes have been cloned
1299
- original_amount = clone.salary.amount
1300
- dev.salary.amount = 1
1301
- assert_equal original_amount, clone.salary.amount
1302
-
1303
- assert clone.save
1304
- assert !clone.new_record?
1305
- assert clone.id != dev.id
1306
- end
1307
-
1308
- def test_clone_preserves_subtype
1309
- clone = nil
1310
- assert_nothing_raised { clone = Company.find(3).clone }
1311
- assert_kind_of Client, clone
1312
- end
1313
-
1314
- def test_bignum
1315
- company = Company.find(1)
1316
- company.rating = 2147483647
1317
- company.save
1318
- company = Company.find(1)
1319
- assert_equal 2147483647, company.rating
1320
- end
1321
-
1322
- # TODO: extend defaults tests to other databases!
1323
- if current_adapter?(:PostgreSQLAdapter)
1324
- def test_default
1325
- default = Default.new
1326
-
1327
- # fixed dates / times
1328
- assert_equal Date.new(2004, 1, 1), default.fixed_date
1329
- assert_equal Time.local(2004, 1,1,0,0,0,0), default.fixed_time
1330
-
1331
- # char types
1332
- assert_equal 'Y', default.char1
1333
- assert_equal 'a varchar field', default.char2
1334
- assert_equal 'a text field', default.char3
1335
- end
1336
-
1337
- class Geometric < ActiveRecord::Base; end
1338
- def test_geometric_content
1339
-
1340
- # accepted format notes:
1341
- # ()'s aren't required
1342
- # values can be a mix of float or integer
1343
-
1344
- g = Geometric.new(
1345
- :a_point => '(5.0, 6.1)',
1346
- #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
1347
- :a_line_segment => '(2.0, 3), (5.5, 7.0)',
1348
- :a_box => '2.0, 3, 5.5, 7.0',
1349
- :a_path => '[(2.0, 3), (5.5, 7.0), (8.5, 11.0)]', # [ ] is an open path
1350
- :a_polygon => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))',
1351
- :a_circle => '<(5.3, 10.4), 2>'
1352
- )
1353
-
1354
- assert g.save
1355
-
1356
- # Reload and check that we have all the geometric attributes.
1357
- h = Geometric.find(g.id)
1358
-
1359
- assert_equal '(5,6.1)', h.a_point
1360
- assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
1361
- assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
1362
- assert_equal '[(2,3),(5.5,7),(8.5,11)]', h.a_path
1363
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
1364
- assert_equal '<(5.3,10.4),2>', h.a_circle
1365
-
1366
- # use a geometric function to test for an open path
1367
- objs = Geometric.find_by_sql ["select isopen(a_path) from geometrics where id = ?", g.id]
1368
- assert_equal objs[0].isopen, 't'
1369
-
1370
- # test alternate formats when defining the geometric types
1371
-
1372
- g = Geometric.new(
1373
- :a_point => '5.0, 6.1',
1374
- #:a_line => '((2.0, 3), (5.5, 7.0))' # line type is currently unsupported in postgresql
1375
- :a_line_segment => '((2.0, 3), (5.5, 7.0))',
1376
- :a_box => '(2.0, 3), (5.5, 7.0)',
1377
- :a_path => '((2.0, 3), (5.5, 7.0), (8.5, 11.0))', # ( ) is a closed path
1378
- :a_polygon => '2.0, 3, 5.5, 7.0, 8.5, 11.0',
1379
- :a_circle => '((5.3, 10.4), 2)'
1380
- )
1381
-
1382
- assert g.save
1383
-
1384
- # Reload and check that we have all the geometric attributes.
1385
- h = Geometric.find(g.id)
1386
-
1387
- assert_equal '(5,6.1)', h.a_point
1388
- assert_equal '[(2,3),(5.5,7)]', h.a_line_segment
1389
- assert_equal '(5.5,7),(2,3)', h.a_box # reordered to store upper right corner then bottom left corner
1390
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_path
1391
- assert_equal '((2,3),(5.5,7),(8.5,11))', h.a_polygon
1392
- assert_equal '<(5.3,10.4),2>', h.a_circle
1393
-
1394
- # use a geometric function to test for an closed path
1395
- objs = Geometric.find_by_sql ["select isclosed(a_path) from geometrics where id = ?", g.id]
1396
- assert_equal objs[0].isclosed, 't'
1397
- end
1398
- end
1399
-
1400
- class NumericData < ActiveRecord::Base
1401
- self.table_name = 'numeric_data'
1402
- end
1403
-
1404
- def test_numeric_fields
1405
- m = NumericData.new(
1406
- :bank_balance => 1586.43,
1407
- :big_bank_balance => BigDecimal("1000234000567.95"),
1408
- :world_population => 6000000000,
1409
- :my_house_population => 3
1410
- )
1411
- assert m.save
1412
-
1413
- m1 = NumericData.find(m.id)
1414
- assert_not_nil m1
1415
-
1416
- # As with migration_test.rb, we should make world_population >= 2**62
1417
- # to cover 64-bit platforms and test it is a Bignum, but the main thing
1418
- # is that it's an Integer.
1419
- assert_kind_of Integer, m1.world_population
1420
- assert_equal 6000000000, m1.world_population
1421
-
1422
- assert_kind_of Fixnum, m1.my_house_population
1423
- assert_equal 3, m1.my_house_population
1424
-
1425
- assert_kind_of BigDecimal, m1.bank_balance
1426
- assert_equal BigDecimal("1586.43"), m1.bank_balance
1427
-
1428
- assert_kind_of BigDecimal, m1.big_bank_balance
1429
- assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
1430
- end
1431
-
1432
- def test_auto_id
1433
- auto = AutoId.new
1434
- auto.save
1435
- assert (auto.id > 0)
1436
- end
1437
-
1438
- def quote_column_name(name)
1439
- "<#{name}>"
1440
- end
1441
-
1442
- def test_quote_keys
1443
- ar = AutoId.new
1444
- source = {"foo" => "bar", "baz" => "quux"}
1445
- actual = ar.send(:quote_columns, self, source)
1446
- inverted = actual.invert
1447
- assert_equal("<foo>", inverted["bar"])
1448
- assert_equal("<baz>", inverted["quux"])
1449
- end
1450
-
1451
- def test_sql_injection_via_find
1452
- assert_raise(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
1453
- Topic.find("123456 OR id > 0")
1454
- end
1455
- end
1456
-
1457
- def test_column_name_properly_quoted
1458
- col_record = ColumnName.new
1459
- col_record.references = 40
1460
- assert col_record.save
1461
- col_record.references = 41
1462
- assert col_record.save
1463
- assert_not_nil c2 = ColumnName.find(col_record.id)
1464
- assert_equal(41, c2.references)
1465
- end
1466
-
1467
- def test_quoting_arrays
1468
- replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
1469
- assert_equal topics(:first).replies.size, replies.size
1470
-
1471
- replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
1472
- assert_equal 0, replies.size
1473
- end
1474
-
1475
- MyObject = Struct.new :attribute1, :attribute2
1476
-
1477
- def test_serialized_attribute
1478
- myobj = MyObject.new('value1', 'value2')
1479
- topic = Topic.create("content" => myobj)
1480
- Topic.serialize("content", MyObject)
1481
- assert_equal(myobj, topic.content)
1482
- end
1483
-
1484
- def test_serialized_time_attribute
1485
- myobj = Time.local(2008,1,1,1,0)
1486
- topic = Topic.create("content" => myobj).reload
1487
- assert_equal(myobj, topic.content)
1488
- end
1489
-
1490
- def test_serialized_string_attribute
1491
- myobj = "Yes"
1492
- topic = Topic.create("content" => myobj).reload
1493
- assert_equal(myobj, topic.content)
1494
- end
1495
-
1496
- def test_nil_serialized_attribute_with_class_constraint
1497
- myobj = MyObject.new('value1', 'value2')
1498
- topic = Topic.new
1499
- assert_nil topic.content
1500
- end
1501
-
1502
- def test_should_raise_exception_on_assigning_already_serialized_content
1503
- topic = Topic.new
1504
- serialized_content = %w[foo bar].to_yaml
1505
- assert_raise(ActiveRecord::ActiveRecordError) { topic.content = serialized_content }
1506
- end
1507
-
1508
- def test_should_raise_exception_on_serialized_attribute_with_type_mismatch
1509
- myobj = MyObject.new('value1', 'value2')
1510
- topic = Topic.new(:content => myobj)
1511
- assert topic.save
1512
- Topic.serialize(:content, Hash)
1513
- assert_raise(ActiveRecord::SerializationTypeMismatch) { Topic.find(topic.id).content }
1514
- ensure
1515
- Topic.serialize(:content)
1516
- end
1517
-
1518
- def test_serialized_attribute_with_class_constraint
1519
- settings = { "color" => "blue" }
1520
- Topic.serialize(:content, Hash)
1521
- topic = Topic.new(:content => settings)
1522
- assert topic.save
1523
- assert_equal(settings, Topic.find(topic.id).content)
1524
- ensure
1525
- Topic.serialize(:content)
1526
- end
1527
-
1528
- def test_quote
1529
- author_name = "\\ \001 ' \n \\n \""
1530
- topic = Topic.create('author_name' => author_name)
1531
- assert_equal author_name, Topic.find(topic.id).author_name
1532
- end
1533
-
1534
- if RUBY_VERSION < '1.9'
1535
- def test_quote_chars
1536
- with_kcode('UTF8') do
1537
- str = 'The Narrator'
1538
- topic = Topic.create(:author_name => str)
1539
- assert_equal str, topic.author_name
1540
-
1541
- assert_kind_of ActiveSupport::Multibyte.proxy_class, str.mb_chars
1542
- topic = Topic.find_by_author_name(str.mb_chars)
1543
-
1544
- assert_kind_of Topic, topic
1545
- assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
1546
- end
1547
- end
1548
- end
1549
-
1550
- def test_class_level_destroy
1551
- should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
1552
- Topic.find(1).replies << should_be_destroyed_reply
1553
-
1554
- Topic.destroy(1)
1555
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
1556
- assert_raise(ActiveRecord::RecordNotFound) { Reply.find(should_be_destroyed_reply.id) }
1557
- end
1558
-
1559
- def test_class_level_delete
1560
- should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
1561
- Topic.find(1).replies << should_be_destroyed_reply
1562
-
1563
- Topic.delete(1)
1564
- assert_raise(ActiveRecord::RecordNotFound) { Topic.find(1) }
1565
- assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
1566
- end
1567
-
1568
- def test_increment_attribute
1569
- assert_equal 50, accounts(:signals37).credit_limit
1570
- accounts(:signals37).increment! :credit_limit
1571
- assert_equal 51, accounts(:signals37, :reload).credit_limit
1572
-
1573
- accounts(:signals37).increment(:credit_limit).increment!(:credit_limit)
1574
- assert_equal 53, accounts(:signals37, :reload).credit_limit
1575
- end
1576
-
1577
- def test_increment_nil_attribute
1578
- assert_nil topics(:first).parent_id
1579
- topics(:first).increment! :parent_id
1580
- assert_equal 1, topics(:first).parent_id
1581
- end
1582
-
1583
- def test_increment_attribute_by
1584
- assert_equal 50, accounts(:signals37).credit_limit
1585
- accounts(:signals37).increment! :credit_limit, 5
1586
- assert_equal 55, accounts(:signals37, :reload).credit_limit
1587
-
1588
- accounts(:signals37).increment(:credit_limit, 1).increment!(:credit_limit, 3)
1589
- assert_equal 59, accounts(:signals37, :reload).credit_limit
1590
- end
1591
-
1592
- def test_decrement_attribute
1593
- assert_equal 50, accounts(:signals37).credit_limit
1594
-
1595
- accounts(:signals37).decrement!(:credit_limit)
1596
- assert_equal 49, accounts(:signals37, :reload).credit_limit
1597
-
1598
- accounts(:signals37).decrement(:credit_limit).decrement!(:credit_limit)
1599
- assert_equal 47, accounts(:signals37, :reload).credit_limit
1600
- end
1601
-
1602
- def test_decrement_attribute_by
1603
- assert_equal 50, accounts(:signals37).credit_limit
1604
- accounts(:signals37).decrement! :credit_limit, 5
1605
- assert_equal 45, accounts(:signals37, :reload).credit_limit
1606
-
1607
- accounts(:signals37).decrement(:credit_limit, 1).decrement!(:credit_limit, 3)
1608
- assert_equal 41, accounts(:signals37, :reload).credit_limit
1609
- end
1610
-
1611
- def test_toggle_attribute
1612
- assert !topics(:first).approved?
1613
- topics(:first).toggle!(:approved)
1614
- assert topics(:first).approved?
1615
- topic = topics(:first)
1616
- topic.toggle(:approved)
1617
- assert !topic.approved?
1618
- topic.reload
1619
- assert topic.approved?
1620
- end
1621
-
1622
- def test_reload
1623
- t1 = Topic.find(1)
1624
- t2 = Topic.find(1)
1625
- t1.title = "something else"
1626
- t1.save
1627
- t2.reload
1628
- assert_equal t1.title, t2.title
1629
- end
1630
-
1631
- def test_reload_with_exclusive_scope
1632
- dev = DeveloperCalledDavid.first
1633
- dev.update_attributes!( :name => "NotDavid" )
1634
- assert_equal dev, dev.reload
1635
- end
1636
-
1637
- def test_define_attr_method_with_value
1638
- k = Class.new( ActiveRecord::Base )
1639
- k.send(:define_attr_method, :table_name, "foo")
1640
- assert_equal "foo", k.table_name
1641
- end
1642
-
1643
- def test_define_attr_method_with_block
1644
- k = Class.new( ActiveRecord::Base )
1645
- k.send(:define_attr_method, :primary_key) { "sys_" + original_primary_key }
1646
- assert_equal "sys_id", k.primary_key
1647
- end
1648
-
1649
- def test_set_table_name_with_value
1650
- k = Class.new( ActiveRecord::Base )
1651
- k.table_name = "foo"
1652
- assert_equal "foo", k.table_name
1653
- k.set_table_name "bar"
1654
- assert_equal "bar", k.table_name
1655
- end
1656
-
1657
- def test_set_table_name_with_block
1658
- k = Class.new( ActiveRecord::Base )
1659
- k.set_table_name { "ks" }
1660
- assert_equal "ks", k.table_name
1661
- end
1662
-
1663
- def test_set_primary_key_with_value
1664
- k = Class.new( ActiveRecord::Base )
1665
- k.primary_key = "foo"
1666
- assert_equal "foo", k.primary_key
1667
- k.set_primary_key "bar"
1668
- assert_equal "bar", k.primary_key
1669
- end
1670
-
1671
- def test_set_primary_key_with_block
1672
- k = Class.new( ActiveRecord::Base )
1673
- k.set_primary_key { "sys_" + original_primary_key }
1674
- assert_equal "sys_id", k.primary_key
1675
- end
1676
-
1677
- def test_set_inheritance_column_with_value
1678
- k = Class.new( ActiveRecord::Base )
1679
- k.inheritance_column = "foo"
1680
- assert_equal "foo", k.inheritance_column
1681
- k.set_inheritance_column "bar"
1682
- assert_equal "bar", k.inheritance_column
1683
- end
1684
-
1685
- def test_set_inheritance_column_with_block
1686
- k = Class.new( ActiveRecord::Base )
1687
- k.set_inheritance_column { original_inheritance_column + "_id" }
1688
- assert_equal "type_id", k.inheritance_column
1689
- end
1690
-
1691
- def test_count_with_join
1692
- res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
1693
-
1694
- res2 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'", :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
1695
- assert_equal res, res2
1696
-
1697
- res3 = nil
1698
- assert_nothing_raised do
1699
- res3 = Post.count(:conditions => "posts.#{QUOTED_TYPE} = 'Post'",
1700
- :joins => "LEFT JOIN comments ON posts.id=comments.post_id")
1701
- end
1702
- assert_equal res, res3
1703
-
1704
- 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"
1705
- res5 = nil
1706
- assert_nothing_raised do
1707
- res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
1708
- :joins => "p, comments co",
1709
- :select => "p.id")
1710
- end
1711
-
1712
- assert_equal res4, res5
1713
-
1714
- unless current_adapter?(:SQLite2Adapter, :DeprecatedSQLiteAdapter)
1715
- 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"
1716
- res7 = nil
1717
- assert_nothing_raised do
1718
- res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
1719
- :joins => "p, comments co",
1720
- :select => "p.id",
1721
- :distinct => true)
1722
- end
1723
- assert_equal res6, res7
1724
- end
1725
- end
1726
-
1727
- def test_clear_association_cache_stored
1728
- firm = Firm.find(1)
1729
- assert_kind_of Firm, firm
1730
-
1731
- firm.clear_association_cache
1732
- assert_equal Firm.find(1).clients.collect{ |x| x.name }.sort, firm.clients.collect{ |x| x.name }.sort
1733
- end
1734
-
1735
- def test_clear_association_cache_new_record
1736
- firm = Firm.new
1737
- client_stored = Client.find(3)
1738
- client_new = Client.new
1739
- client_new.name = "The Joneses"
1740
- clients = [ client_stored, client_new ]
1741
-
1742
- firm.clients << clients
1743
- assert_equal clients.map(&:name).to_set, firm.clients.map(&:name).to_set
1744
-
1745
- firm.clear_association_cache
1746
- assert_equal clients.map(&:name).to_set, firm.clients.map(&:name).to_set
1747
- end
1748
-
1749
- def test_interpolate_sql
1750
- assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo@bar') }
1751
- assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar) baz') }
1752
- assert_nothing_raised { Category.new.send(:interpolate_sql, 'foo bar} baz') }
1753
- end
1754
-
1755
- def test_scoped_find_conditions
1756
- scoped_developers = Developer.with_scope(:find => { :conditions => 'salary > 90000' }) do
1757
- Developer.find(:all, :conditions => 'id < 5')
1758
- end
1759
- assert !scoped_developers.include?(developers(:david)) # David's salary is less than 90,000
1760
- assert_equal 3, scoped_developers.size
1761
- end
1762
-
1763
- def test_scoped_find_limit_offset
1764
- scoped_developers = Developer.with_scope(:find => { :limit => 3, :offset => 2 }) do
1765
- Developer.find(:all, :order => 'id')
1766
- end
1767
- assert !scoped_developers.include?(developers(:david))
1768
- assert !scoped_developers.include?(developers(:jamis))
1769
- assert_equal 3, scoped_developers.size
1770
-
1771
- # Test without scoped find conditions to ensure we get the whole thing
1772
- developers = Developer.find(:all, :order => 'id')
1773
- assert_equal Developer.count, developers.size
1774
- end
1775
-
1776
- def test_scoped_find_order
1777
- # Test order in scope
1778
- scoped_developers = Developer.with_scope(:find => { :limit => 1, :order => 'salary DESC' }) do
1779
- Developer.find(:all)
1780
- end
1781
- assert_equal 'Jamis', scoped_developers.first.name
1782
- assert scoped_developers.include?(developers(:jamis))
1783
- # Test scope without order and order in find
1784
- scoped_developers = Developer.with_scope(:find => { :limit => 1 }) do
1785
- Developer.find(:all, :order => 'salary DESC')
1786
- end
1787
- # Test scope order + find order, find has priority
1788
- scoped_developers = Developer.with_scope(:find => { :limit => 3, :order => 'id DESC' }) do
1789
- Developer.find(:all, :order => 'salary ASC')
1790
- end
1791
- assert scoped_developers.include?(developers(:poor_jamis))
1792
- assert scoped_developers.include?(developers(:david))
1793
- assert scoped_developers.include?(developers(:dev_10))
1794
- # Test without scoped find conditions to ensure we get the right thing
1795
- developers = Developer.find(:all, :order => 'id', :limit => 1)
1796
- assert scoped_developers.include?(developers(:david))
1797
- end
1798
-
1799
- def test_scoped_find_limit_offset_including_has_many_association
1800
- topics = Topic.with_scope(:find => {:limit => 1, :offset => 1, :include => :replies}) do
1801
- Topic.find(:all, :order => "topics.id")
1802
- end
1803
- assert_equal 1, topics.size
1804
- assert_equal 2, topics.first.id
1805
- end
1806
-
1807
- def test_scoped_find_order_including_has_many_association
1808
- developers = Developer.with_scope(:find => { :order => 'developers.salary DESC', :include => :projects }) do
1809
- Developer.find(:all)
1810
- end
1811
- assert developers.size >= 2
1812
- for i in 1...developers.size
1813
- assert developers[i-1].salary >= developers[i].salary
1814
- end
1815
- end
1816
-
1817
- def test_scoped_find_with_group_and_having
1818
- developers = Developer.with_scope(:find => { :group => 'developers.salary', :having => "SUM(salary) > 10000", :select => "SUM(salary) as salary" }) do
1819
- Developer.find(:all)
1820
- end
1821
- assert_equal 3, developers.size
1822
- end
1823
-
1824
- def test_find_last
1825
- last = Developer.find :last
1826
- assert_equal last, Developer.find(:first, :order => 'id desc')
1827
- end
1828
-
1829
- def test_last
1830
- assert_equal Developer.find(:first, :order => 'id desc'), Developer.last
1831
- end
1832
-
1833
- def test_all_with_conditions
1834
- assert_equal Developer.find(:all, :order => 'id desc'), Developer.all(:order => 'id desc')
1835
- end
1836
-
1837
- def test_find_ordered_last
1838
- last = Developer.find :last, :order => 'developers.salary ASC'
1839
- assert_equal last, Developer.find(:all, :order => 'developers.salary ASC').last
1840
- end
1841
-
1842
- def test_find_reverse_ordered_last
1843
- last = Developer.find :last, :order => 'developers.salary DESC'
1844
- assert_equal last, Developer.find(:all, :order => 'developers.salary DESC').last
1845
- end
1846
-
1847
- def test_find_multiple_ordered_last
1848
- last = Developer.find :last, :order => 'developers.name, developers.salary DESC'
1849
- assert_equal last, Developer.find(:all, :order => 'developers.name, developers.salary DESC').last
1850
- end
1851
-
1852
- def test_find_symbol_ordered_last
1853
- last = Developer.find :last, :order => :salary
1854
- assert_equal last, Developer.find(:all, :order => :salary).last
1855
- end
1856
-
1857
- def test_find_scoped_ordered_last
1858
- last_developer = Developer.with_scope(:find => { :order => 'developers.salary ASC' }) do
1859
- Developer.find(:last)
1860
- end
1861
- assert_equal last_developer, Developer.find(:all, :order => 'developers.salary ASC').last
1862
- end
1863
-
1864
- def test_abstract_class
1865
- assert !ActiveRecord::Base.abstract_class?
1866
- assert LoosePerson.abstract_class?
1867
- assert !LooseDescendant.abstract_class?
1868
- end
1869
-
1870
- def test_base_class
1871
- assert_equal LoosePerson, LoosePerson.base_class
1872
- assert_equal LooseDescendant, LooseDescendant.base_class
1873
- assert_equal TightPerson, TightPerson.base_class
1874
- assert_equal TightPerson, TightDescendant.base_class
1875
-
1876
- assert_equal Post, Post.base_class
1877
- assert_equal Post, SpecialPost.base_class
1878
- assert_equal Post, StiPost.base_class
1879
- assert_equal SubStiPost, SubStiPost.base_class
1880
- end
1881
-
1882
- def test_descends_from_active_record
1883
- # Tries to call Object.abstract_class?
1884
- assert_raise(NoMethodError) do
1885
- ActiveRecord::Base.descends_from_active_record?
1886
- end
1887
-
1888
- # Abstract subclass of AR::Base.
1889
- assert LoosePerson.descends_from_active_record?
1890
-
1891
- # Concrete subclass of an abstract class.
1892
- assert LooseDescendant.descends_from_active_record?
1893
-
1894
- # Concrete subclass of AR::Base.
1895
- assert TightPerson.descends_from_active_record?
1896
-
1897
- # Concrete subclass of a concrete class but has no type column.
1898
- assert TightDescendant.descends_from_active_record?
1899
-
1900
- # Concrete subclass of AR::Base.
1901
- assert Post.descends_from_active_record?
1902
-
1903
- # Abstract subclass of a concrete class which has a type column.
1904
- # This is pathological, as you'll never have Sub < Abstract < Concrete.
1905
- assert !StiPost.descends_from_active_record?
1906
-
1907
- # Concrete subclasses an abstract class which has a type column.
1908
- assert !SubStiPost.descends_from_active_record?
1909
- end
1910
-
1911
- def test_find_on_abstract_base_class_doesnt_use_type_condition
1912
- old_class = LooseDescendant
1913
- Object.send :remove_const, :LooseDescendant
1914
-
1915
- descendant = old_class.create! :first_name => 'bob'
1916
- assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
1917
- ensure
1918
- unless Object.const_defined?(:LooseDescendant)
1919
- Object.const_set :LooseDescendant, old_class
1920
- end
1921
- end
1922
-
1923
- def test_assert_queries
1924
- query = lambda { ActiveRecord::Base.connection.execute 'select count(*) from developers' }
1925
- assert_queries(2) { 2.times { query.call } }
1926
- assert_queries 1, &query
1927
- assert_no_queries { assert true }
1928
- end
1929
-
1930
- def test_to_xml
1931
- xml = REXML::Document.new(topics(:first).to_xml(:indent => 0))
1932
- bonus_time_in_current_timezone = topics(:first).bonus_time.xmlschema
1933
- written_on_in_current_timezone = topics(:first).written_on.xmlschema
1934
- last_read_in_current_timezone = topics(:first).last_read.xmlschema
1935
-
1936
- assert_equal "topic", xml.root.name
1937
- assert_equal "The First Topic" , xml.elements["//title"].text
1938
- assert_equal "David" , xml.elements["//author-name"].text
1939
-
1940
- assert_equal "1", xml.elements["//id"].text
1941
- assert_equal "integer" , xml.elements["//id"].attributes['type']
1942
-
1943
- assert_equal "1", xml.elements["//replies-count"].text
1944
- assert_equal "integer" , xml.elements["//replies-count"].attributes['type']
1945
-
1946
- assert_equal written_on_in_current_timezone, xml.elements["//written-on"].text
1947
- assert_equal "datetime" , xml.elements["//written-on"].attributes['type']
1948
-
1949
- assert_equal "--- Have a nice day\n" , xml.elements["//content"].text
1950
- assert_equal "yaml" , xml.elements["//content"].attributes['type']
1951
-
1952
- assert_equal "david@loudthinking.com", xml.elements["//author-email-address"].text
1953
-
1954
- assert_equal nil, xml.elements["//parent-id"].text
1955
- assert_equal "integer", xml.elements["//parent-id"].attributes['type']
1956
- assert_equal "true", xml.elements["//parent-id"].attributes['nil']
1957
-
1958
- if current_adapter?(:SybaseAdapter, :OracleAdapter)
1959
- assert_equal last_read_in_current_timezone, xml.elements["//last-read"].text
1960
- assert_equal "datetime" , xml.elements["//last-read"].attributes['type']
1961
- else
1962
- assert_equal "2004-04-15", xml.elements["//last-read"].text
1963
- assert_equal "date" , xml.elements["//last-read"].attributes['type']
1964
- end
1965
-
1966
- # Oracle and DB2 don't have true boolean or time-only fields
1967
- unless current_adapter?(:OracleAdapter, :DB2Adapter)
1968
- assert_equal "false", xml.elements["//approved"].text
1969
- assert_equal "boolean" , xml.elements["//approved"].attributes['type']
1970
-
1971
- assert_equal bonus_time_in_current_timezone, xml.elements["//bonus-time"].text
1972
- assert_equal "datetime" , xml.elements["//bonus-time"].attributes['type']
1973
- end
1974
- end
1975
-
1976
- def test_to_xml_skipping_attributes
1977
- xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :replies_count])
1978
- assert_equal "<topic>", xml.first(7)
1979
- assert !xml.include?(%(<title>The First Topic</title>))
1980
- assert xml.include?(%(<author-name>David</author-name>))
1981
-
1982
- xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :author_name, :replies_count])
1983
- assert !xml.include?(%(<title>The First Topic</title>))
1984
- assert !xml.include?(%(<author-name>David</author-name>))
1985
- end
1986
-
1987
- def test_to_xml_including_has_many_association
1988
- xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies, :except => :replies_count)
1989
- assert_equal "<topic>", xml.first(7)
1990
- assert xml.include?(%(<replies type="array"><reply>))
1991
- assert xml.include?(%(<title>The Second Topic of the day</title>))
1992
- end
1993
-
1994
- def test_array_to_xml_including_has_many_association
1995
- xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :include => :replies)
1996
- assert xml.include?(%(<replies type="array"><reply>))
1997
- end
1998
-
1999
- def test_array_to_xml_including_methods
2000
- xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :methods => [ :topic_id ])
2001
- assert xml.include?(%(<topic-id type="integer">#{topics(:first).topic_id}</topic-id>)), xml
2002
- assert xml.include?(%(<topic-id type="integer">#{topics(:second).topic_id}</topic-id>)), xml
2003
- end
2004
-
2005
- def test_array_to_xml_including_has_one_association
2006
- xml = [ companies(:first_firm), companies(:rails_core) ].to_xml(:indent => 0, :skip_instruct => true, :include => :account)
2007
- assert xml.include?(companies(:first_firm).account.to_xml(:indent => 0, :skip_instruct => true))
2008
- assert xml.include?(companies(:rails_core).account.to_xml(:indent => 0, :skip_instruct => true))
2009
- end
2010
-
2011
- def test_array_to_xml_including_belongs_to_association
2012
- xml = [ companies(:first_client), companies(:second_client), companies(:another_client) ].to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
2013
- assert xml.include?(companies(:first_client).to_xml(:indent => 0, :skip_instruct => true))
2014
- assert xml.include?(companies(:second_client).firm.to_xml(:indent => 0, :skip_instruct => true))
2015
- assert xml.include?(companies(:another_client).firm.to_xml(:indent => 0, :skip_instruct => true))
2016
- end
2017
-
2018
- def test_to_xml_including_belongs_to_association
2019
- xml = companies(:first_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
2020
- assert !xml.include?("<firm>")
2021
-
2022
- xml = companies(:second_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
2023
- assert xml.include?("<firm>")
2024
- end
2025
-
2026
- def test_to_xml_including_multiple_associations
2027
- xml = companies(:first_firm).to_xml(:indent => 0, :skip_instruct => true, :include => [ :clients, :account ])
2028
- assert_equal "<firm>", xml.first(6)
2029
- assert xml.include?(%(<account>))
2030
- assert xml.include?(%(<clients type="array"><client>))
2031
- end
2032
-
2033
- def test_to_xml_including_multiple_associations_with_options
2034
- xml = companies(:first_firm).to_xml(
2035
- :indent => 0, :skip_instruct => true,
2036
- :include => { :clients => { :only => :name } }
2037
- )
2038
-
2039
- assert_equal "<firm>", xml.first(6)
2040
- assert xml.include?(%(<client><name>Summit</name></client>))
2041
- assert xml.include?(%(<clients type="array"><client>))
2042
- end
2043
-
2044
- def test_to_xml_including_methods
2045
- xml = Company.new.to_xml(:methods => :arbitrary_method, :skip_instruct => true)
2046
- assert_equal "<company>", xml.first(9)
2047
- assert xml.include?(%(<arbitrary-method>I am Jack's profound disappointment</arbitrary-method>))
2048
- end
2049
-
2050
- def test_to_xml_with_block
2051
- value = "Rockin' the block"
2052
- xml = Company.new.to_xml(:skip_instruct => true) do |xml|
2053
- xml.tag! "arbitrary-element", value
2054
- end
2055
- assert_equal "<company>", xml.first(9)
2056
- assert xml.include?(%(<arbitrary-element>#{value}</arbitrary-element>))
2057
- end
2058
-
2059
- def test_type_name_with_module_should_handle_beginning
2060
- assert_equal 'ActiveRecord::Person', ActiveRecord::Base.send(:type_name_with_module, 'Person')
2061
- assert_equal '::Person', ActiveRecord::Base.send(:type_name_with_module, '::Person')
2062
- end
2063
-
2064
- def test_to_param_should_return_string
2065
- assert_kind_of String, Client.find(:first).to_param
2066
- end
2067
-
2068
- def test_inspect_class
2069
- assert_equal 'ActiveRecord::Base', ActiveRecord::Base.inspect
2070
- assert_equal 'LoosePerson(abstract)', LoosePerson.inspect
2071
- assert_match(/^Topic\(id: integer, title: string/, Topic.inspect)
2072
- end
2073
-
2074
- def test_inspect_instance
2075
- topic = topics(:first)
2076
- assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil>), topic.inspect
2077
- end
2078
-
2079
- def test_inspect_new_instance
2080
- assert_match /Topic id: nil/, Topic.new.inspect
2081
- end
2082
-
2083
- def test_inspect_limited_select_instance
2084
- assert_equal %(#<Topic id: 1>), Topic.find(:first, :select => 'id', :conditions => 'id = 1').inspect
2085
- assert_equal %(#<Topic id: 1, title: "The First Topic">), Topic.find(:first, :select => 'id, title', :conditions => 'id = 1').inspect
2086
- end
2087
-
2088
- def test_inspect_class_without_table
2089
- assert_equal "NonExistentTable(Table doesn't exist)", NonExistentTable.inspect
2090
- end
2091
-
2092
- def test_attribute_for_inspect
2093
- t = topics(:first)
2094
- t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
2095
-
2096
- assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
2097
- assert_equal '"The First Topic Now Has A Title With\nNewlines And M..."', t.attribute_for_inspect(:title)
2098
- end
2099
-
2100
- def test_becomes
2101
- assert_kind_of Reply, topics(:first).becomes(Reply)
2102
- assert_equal "The First Topic", topics(:first).becomes(Reply).title
2103
- end
2104
-
2105
- def test_silence_sets_log_level_to_error_in_block
2106
- original_logger = ActiveRecord::Base.logger
2107
- log = StringIO.new
2108
- ActiveRecord::Base.logger = Logger.new(log)
2109
- ActiveRecord::Base.logger.level = Logger::DEBUG
2110
- ActiveRecord::Base.silence do
2111
- ActiveRecord::Base.logger.warn "warn"
2112
- ActiveRecord::Base.logger.error "error"
2113
- end
2114
- assert_equal "error\n", log.string
2115
- ensure
2116
- ActiveRecord::Base.logger = original_logger
2117
- end
2118
-
2119
- def test_silence_sets_log_level_back_to_level_before_yield
2120
- original_logger = ActiveRecord::Base.logger
2121
- log = StringIO.new
2122
- ActiveRecord::Base.logger = Logger.new(log)
2123
- ActiveRecord::Base.logger.level = Logger::WARN
2124
- ActiveRecord::Base.silence do
2125
- end
2126
- assert_equal Logger::WARN, ActiveRecord::Base.logger.level
2127
- ensure
2128
- ActiveRecord::Base.logger = original_logger
2129
- end
2130
-
2131
- def test_benchmark_with_log_level
2132
- original_logger = ActiveRecord::Base.logger
2133
- log = StringIO.new
2134
- ActiveRecord::Base.logger = Logger.new(log)
2135
- ActiveRecord::Base.logger.level = Logger::WARN
2136
- ActiveRecord::Base.benchmark("Debug Topic Count", Logger::DEBUG) { Topic.count }
2137
- ActiveRecord::Base.benchmark("Warn Topic Count", Logger::WARN) { Topic.count }
2138
- ActiveRecord::Base.benchmark("Error Topic Count", Logger::ERROR) { Topic.count }
2139
- assert_no_match /Debug Topic Count/, log.string
2140
- assert_match /Warn Topic Count/, log.string
2141
- assert_match /Error Topic Count/, log.string
2142
- ensure
2143
- ActiveRecord::Base.logger = original_logger
2144
- end
2145
-
2146
- def test_benchmark_with_use_silence
2147
- original_logger = ActiveRecord::Base.logger
2148
- log = StringIO.new
2149
- ActiveRecord::Base.logger = Logger.new(log)
2150
- ActiveRecord::Base.benchmark("Logging", Logger::DEBUG, true) { ActiveRecord::Base.logger.debug "Loud" }
2151
- ActiveRecord::Base.benchmark("Logging", Logger::DEBUG, false) { ActiveRecord::Base.logger.debug "Quiet" }
2152
- assert_no_match /Loud/, log.string
2153
- assert_match /Quiet/, log.string
2154
- ensure
2155
- ActiveRecord::Base.logger = original_logger
2156
- end
2157
-
2158
- def test_create_with_custom_timestamps
2159
- custom_datetime = 1.hour.ago.beginning_of_day
2160
-
2161
- %w(created_at created_on updated_at updated_on).each do |attribute|
2162
- parrot = LiveParrot.create(:name => "colombian", attribute => custom_datetime)
2163
- assert_equal custom_datetime, parrot[attribute]
2164
- end
2165
- end
2166
- end