ibm_db 3.0.4-x86-mingw32 → 3.0.5-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES +4 -1
- data/LICENSE +1 -1
- data/MANIFEST +14 -14
- data/README +225 -225
- data/ext/Makefile.nt32 +181 -181
- data/ext/Makefile.nt32.191 +212 -212
- data/ext/extconf.rb +291 -291
- data/ext/ibm_db.c +11887 -11884
- data/ext/ruby_ibm_db.h +241 -241
- data/ext/ruby_ibm_db_cli.c +866 -866
- data/ext/ruby_ibm_db_cli.h +500 -500
- data/init.rb +41 -41
- data/lib/IBM_DB.rb +27 -27
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +3177 -3177
- data/lib/active_record/connection_adapters/ibmdb_adapter.rb +1 -1
- data/lib/active_record/vendor/db2-i5-zOS.yaml +328 -328
- data/lib/mswin32/ibm_db.rb +122 -122
- data/lib/mswin32/rb21x/i386/ibm_db.so +0 -0
- data/lib/mswin32/rb22x/i386/ibm_db.so +0 -0
- data/lib/mswin32/rb23x/i386/ibm_db.so +0 -0
- data/test/active_record/connection_adapters/fake_adapter.rb +46 -46
- data/test/assets/example.log +1 -1
- data/test/assets/test.txt +1 -1
- data/test/cases/adapter_test.rb +276 -261
- data/test/cases/aggregations_test.rb +158 -158
- data/test/cases/ar_schema_test.rb +161 -161
- data/test/cases/associations/association_scope_test.rb +21 -21
- data/test/cases/associations/belongs_to_associations_test.rb +1029 -1029
- data/test/cases/associations/callbacks_test.rb +192 -192
- data/test/cases/associations/cascaded_eager_loading_test.rb +188 -188
- data/test/cases/associations/deprecated_counter_cache_on_has_many_through_test.rb +26 -26
- data/test/cases/associations/eager_load_includes_full_sti_class_test.rb +36 -36
- data/test/cases/associations/eager_load_nested_include_test.rb +128 -128
- data/test/cases/associations/eager_singularization_test.rb +148 -148
- data/test/cases/associations/eager_test.rb +1429 -1411
- data/test/cases/associations/extension_test.rb +82 -82
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +972 -932
- data/test/cases/associations/has_many_associations_test.rb +2182 -2162
- data/test/cases/associations/has_many_through_associations_test.rb +1204 -1204
- data/test/cases/associations/has_one_associations_test.rb +610 -610
- data/test/cases/associations/has_one_through_associations_test.rb +380 -380
- data/test/cases/associations/inner_join_association_test.rb +139 -139
- data/test/cases/associations/inverse_associations_test.rb +706 -693
- data/test/cases/associations/join_model_test.rb +754 -754
- data/test/cases/associations/nested_through_associations_test.rb +579 -579
- data/test/cases/associations/required_test.rb +82 -82
- data/test/cases/associations_test.rb +380 -380
- data/test/cases/attribute_decorators_test.rb +125 -125
- data/test/cases/attribute_methods/read_test.rb +60 -60
- data/test/cases/attribute_methods/serialization_test.rb +29 -29
- data/test/cases/attribute_methods_test.rb +952 -952
- data/test/cases/attribute_set_test.rb +210 -200
- data/test/cases/attribute_test.rb +180 -180
- data/test/cases/attributes_test.rb +136 -136
- data/test/cases/autosave_association_test.rb +1595 -1595
- data/test/cases/base_test.rb +1664 -1638
- data/test/cases/batches_test.rb +212 -212
- data/test/cases/binary_test.rb +52 -52
- data/test/cases/bind_parameter_test.rb +100 -100
- data/test/cases/calculations_test.rb +646 -646
- data/test/cases/callbacks_test.rb +543 -543
- data/test/cases/clone_test.rb +40 -40
- data/test/cases/coders/yaml_column_test.rb +63 -63
- data/test/cases/column_alias_test.rb +17 -17
- data/test/cases/column_definition_test.rb +123 -123
- data/test/cases/connection_adapters/adapter_leasing_test.rb +54 -54
- data/test/cases/connection_adapters/connection_handler_test.rb +53 -53
- data/test/cases/connection_adapters/connection_specification_test.rb +12 -12
- data/test/cases/connection_adapters/merge_and_resolve_default_url_config_test.rb +293 -293
- data/test/cases/connection_adapters/mysql_type_lookup_test.rb +65 -65
- data/test/cases/connection_adapters/quoting_test.rb +13 -13
- data/test/cases/connection_adapters/schema_cache_test.rb +56 -56
- data/test/cases/connection_adapters/type_lookup_test.rb +110 -110
- data/test/cases/connection_management_test.rb +122 -122
- data/test/cases/connection_pool_test.rb +346 -346
- data/test/cases/connection_specification/resolver_test.rb +116 -116
- data/test/cases/core_test.rb +112 -112
- data/test/cases/counter_cache_test.rb +209 -209
- data/test/cases/custom_locking_test.rb +17 -17
- data/test/cases/database_statements_test.rb +19 -19
- data/test/cases/date_time_test.rb +61 -61
- data/test/cases/defaults_test.rb +223 -223
- data/test/cases/dirty_test.rb +785 -775
- data/test/cases/disconnected_test.rb +28 -28
- data/test/cases/dup_test.rb +157 -157
- data/test/cases/enum_test.rb +290 -290
- data/test/cases/explain_subscriber_test.rb +64 -64
- data/test/cases/explain_test.rb +76 -76
- data/test/cases/finder_respond_to_test.rb +60 -60
- data/test/cases/finder_test.rb +1169 -1166
- data/test/cases/fixture_set/file_test.rb +138 -138
- data/test/cases/fixtures_test.rb +908 -897
- data/test/cases/forbidden_attributes_protection_test.rb +99 -99
- data/test/cases/habtm_destroy_order_test.rb +61 -61
- data/test/cases/helper.rb +210 -210
- data/test/cases/hot_compatibility_test.rb +54 -54
- data/test/cases/i18n_test.rb +45 -45
- data/test/cases/inheritance_test.rb +375 -375
- data/test/cases/integration_test.rb +139 -139
- data/test/cases/invalid_connection_test.rb +22 -22
- data/test/cases/invalid_date_test.rb +32 -32
- data/test/cases/invertible_migration_test.rb +295 -295
- data/test/cases/json_serialization_test.rb +302 -302
- data/test/cases/locking_test.rb +477 -477
- data/test/cases/log_subscriber_test.rb +136 -136
- data/test/cases/migration/change_schema_test - Copy.rb +448 -448
- data/test/cases/migration/change_schema_test.rb +512 -472
- data/test/cases/migration/change_table_test.rb +224 -224
- data/test/cases/migration/column_attributes_test.rb +192 -192
- data/test/cases/migration/column_positioning_test.rb +56 -56
- data/test/cases/migration/columns_test.rb +304 -304
- data/test/cases/migration/command_recorder_test.rb +305 -305
- data/test/cases/migration/create_join_table_test.rb +148 -148
- data/test/cases/migration/foreign_key_test - Changed.rb +325 -325
- data/test/cases/migration/foreign_key_test.rb +328 -360
- data/test/cases/migration/helper.rb +39 -39
- data/test/cases/migration/index_test.rb +216 -216
- data/test/cases/migration/logger_test.rb +36 -36
- data/test/cases/migration/pending_migrations_test.rb +53 -53
- data/test/cases/migration/references_foreign_key_test.rb +169 -214
- data/test/cases/migration/references_index_test.rb +101 -101
- data/test/cases/migration/references_statements_test.rb +116 -116
- data/test/cases/migration/rename_table_test.rb +93 -93
- data/test/cases/migration/table_and_index_test.rb +24 -24
- data/test/cases/migration_test.rb +959 -959
- data/test/cases/migrator_test.rb +388 -388
- data/test/cases/mixin_test.rb +70 -70
- data/test/cases/modules_test.rb +173 -173
- data/test/cases/multiparameter_attributes_test.rb +350 -350
- data/test/cases/multiple_db_test.rb +115 -115
- data/test/cases/nested_attributes_test.rb +1070 -1057
- data/test/cases/nested_attributes_with_callbacks_test.rb +144 -144
- data/test/cases/persistence_test.rb +909 -909
- data/test/cases/pooled_connections_test.rb +81 -81
- data/test/cases/primary_keys_test.rb +237 -237
- data/test/cases/query_cache_test.rb +326 -326
- data/test/cases/quoting_test.rb +156 -156
- data/test/cases/readonly_test.rb +118 -118
- data/test/cases/reaper_test.rb +85 -85
- data/test/cases/reflection_test.rb +463 -454
- data/test/cases/relation/delegation_test.rb +68 -68
- data/test/cases/relation/merging_test.rb +161 -161
- data/test/cases/relation/mutation_test.rb +165 -165
- data/test/cases/relation/predicate_builder_test.rb +14 -14
- data/test/cases/relation/where_chain_test.rb +181 -181
- data/test/cases/relation/where_test.rb +300 -300
- data/test/cases/relation/where_test2.rb +36 -36
- data/test/cases/relation_test.rb +319 -297
- data/test/cases/relations_test.rb +1815 -1815
- data/test/cases/reload_models_test.rb +22 -22
- data/test/cases/result_test.rb +80 -80
- data/test/cases/sanitize_test.rb +83 -83
- data/test/cases/schema_dumper_test.rb +463 -463
- data/test/cases/scoping/default_scoping_test.rb +454 -454
- data/test/cases/scoping/named_scoping_test.rb +524 -524
- data/test/cases/scoping/relation_scoping_test.rb +357 -357
- data/test/cases/serialization_test.rb +104 -104
- data/test/cases/serialized_attribute_test.rb +277 -277
- data/test/cases/statement_cache_test.rb +98 -98
- data/test/cases/store_test.rb +194 -194
- data/test/cases/tasks/database_tasks_test.rb +398 -396
- data/test/cases/tasks/mysql_rake_test.rb +324 -311
- data/test/cases/tasks/postgresql_rake_test.rb +250 -245
- data/test/cases/tasks/sqlite_rake_test.rb +193 -193
- data/test/cases/test_case.rb +123 -123
- data/test/cases/timestamp_test.rb +467 -468
- data/test/cases/transaction_callbacks_test.rb +452 -452
- data/test/cases/transaction_isolation_test.rb +106 -106
- data/test/cases/transactions_test.rb +817 -817
- data/test/cases/type/decimal_test.rb +56 -51
- data/test/cases/type/integer_test.rb +121 -121
- data/test/cases/type/string_test.rb +36 -36
- data/test/cases/type/type_map_test.rb +177 -177
- data/test/cases/type/unsigned_integer_test.rb +18 -18
- data/test/cases/types_test.rb +141 -141
- data/test/cases/unconnected_test.rb +33 -33
- data/test/cases/validations/association_validation_test.rb +86 -86
- data/test/cases/validations/i18n_generate_message_validation_test.rb +84 -84
- data/test/cases/validations/i18n_validation_test.rb +90 -90
- data/test/cases/validations/length_validation_test.rb +47 -47
- data/test/cases/validations/presence_validation_test.rb +68 -68
- data/test/cases/validations/uniqueness_validation_test.rb +457 -434
- data/test/cases/validations_repair_helper.rb +23 -23
- data/test/cases/validations_test.rb +165 -165
- data/test/cases/view_test.rb +119 -113
- data/test/cases/xml_serialization_test.rb +457 -457
- data/test/cases/yaml_serialization_test.rb +126 -86
- data/test/config.rb +5 -5
- data/test/config.yml +154 -154
- data/test/connections/native_ibm_db/connection.rb +43 -43
- data/test/fixtures/accounts.yml +29 -29
- data/test/fixtures/admin/accounts.yml +2 -2
- data/test/fixtures/admin/randomly_named_a9.yml +7 -7
- data/test/fixtures/admin/randomly_named_b0.yml +7 -7
- data/test/fixtures/admin/users.yml +10 -10
- data/test/fixtures/author_addresses.yml +17 -17
- data/test/fixtures/author_favorites.yml +3 -3
- data/test/fixtures/authors.yml +23 -23
- data/test/fixtures/binaries.yml +133 -133
- data/test/fixtures/books.yml +11 -11
- data/test/fixtures/bulbs.yml +5 -5
- data/test/fixtures/cars.yml +9 -9
- data/test/fixtures/categories.yml +19 -19
- data/test/fixtures/categories/special_categories.yml +9 -9
- data/test/fixtures/categories/subsubdir/arbitrary_filename.yml +4 -4
- data/test/fixtures/categories_ordered.yml +7 -7
- data/test/fixtures/categories_posts.yml +31 -31
- data/test/fixtures/categorizations.yml +23 -23
- data/test/fixtures/clubs.yml +8 -8
- data/test/fixtures/collections.yml +3 -3
- data/test/fixtures/colleges.yml +3 -3
- data/test/fixtures/comments.yml +65 -65
- data/test/fixtures/companies.yml +67 -67
- data/test/fixtures/computers.yml +10 -10
- data/test/fixtures/courses.yml +8 -8
- data/test/fixtures/customers.yml +25 -25
- data/test/fixtures/dashboards.yml +6 -6
- data/test/fixtures/developers.yml +21 -21
- data/test/fixtures/developers_projects.yml +16 -16
- data/test/fixtures/dog_lovers.yml +7 -7
- data/test/fixtures/dogs.yml +4 -4
- data/test/fixtures/doubloons.yml +3 -3
- data/test/fixtures/edges.yml +5 -5
- data/test/fixtures/entrants.yml +14 -14
- data/test/fixtures/essays.yml +6 -6
- data/test/fixtures/faces.yml +11 -11
- data/test/fixtures/fk_test_has_fk.yml +3 -3
- data/test/fixtures/fk_test_has_pk.yml +1 -1
- data/test/fixtures/friendships.yml +4 -4
- data/test/fixtures/funny_jokes.yml +10 -10
- data/test/fixtures/interests.yml +33 -33
- data/test/fixtures/items.yml +3 -3
- data/test/fixtures/jobs.yml +7 -7
- data/test/fixtures/legacy_things.yml +3 -3
- data/test/fixtures/mateys.yml +4 -4
- data/test/fixtures/member_details.yml +8 -8
- data/test/fixtures/member_types.yml +6 -6
- data/test/fixtures/members.yml +11 -11
- data/test/fixtures/memberships.yml +34 -34
- data/test/fixtures/men.yml +5 -5
- data/test/fixtures/minimalistics.yml +2 -2
- data/test/fixtures/minivans.yml +5 -5
- data/test/fixtures/mixed_case_monkeys.yml +6 -6
- data/test/fixtures/mixins.yml +29 -29
- data/test/fixtures/movies.yml +7 -7
- data/test/fixtures/naked/csv/accounts.csv +1 -1
- data/test/fixtures/naked/yml/accounts.yml +1 -1
- data/test/fixtures/naked/yml/companies.yml +1 -1
- data/test/fixtures/naked/yml/courses.yml +1 -1
- data/test/fixtures/organizations.yml +5 -5
- data/test/fixtures/other_topics.yml +42 -42
- data/test/fixtures/owners.yml +9 -9
- data/test/fixtures/parrots.yml +27 -27
- data/test/fixtures/parrots_pirates.yml +7 -7
- data/test/fixtures/people.yml +24 -24
- data/test/fixtures/peoples_treasures.yml +3 -3
- data/test/fixtures/pets.yml +19 -19
- data/test/fixtures/pirates.yml +12 -12
- data/test/fixtures/posts.yml +80 -80
- data/test/fixtures/price_estimates.yml +7 -7
- data/test/fixtures/products.yml +4 -4
- data/test/fixtures/projects.yml +7 -7
- data/test/fixtures/randomly_named_a9.yml +7 -7
- data/test/fixtures/ratings.yml +14 -14
- data/test/fixtures/readers.yml +11 -11
- data/test/fixtures/references.yml +17 -17
- data/test/fixtures/reserved_words/distinct.yml +5 -5
- data/test/fixtures/reserved_words/distinct_select.yml +11 -11
- data/test/fixtures/reserved_words/group.yml +14 -14
- data/test/fixtures/reserved_words/select.yml +8 -8
- data/test/fixtures/reserved_words/values.yml +7 -7
- data/test/fixtures/ships.yml +6 -6
- data/test/fixtures/speedometers.yml +8 -8
- data/test/fixtures/sponsors.yml +12 -12
- data/test/fixtures/string_key_objects.yml +7 -7
- data/test/fixtures/subscribers.yml +10 -10
- data/test/fixtures/subscriptions.yml +12 -12
- data/test/fixtures/taggings.yml +78 -78
- data/test/fixtures/tags.yml +11 -11
- data/test/fixtures/tasks.yml +7 -7
- data/test/fixtures/teapots.yml +3 -3
- data/test/fixtures/to_be_linked/accounts.yml +2 -2
- data/test/fixtures/to_be_linked/users.yml +10 -10
- data/test/fixtures/topics.yml +49 -49
- data/test/fixtures/toys.yml +14 -14
- data/test/fixtures/traffic_lights.yml +9 -9
- data/test/fixtures/treasures.yml +10 -10
- data/test/fixtures/uuid_children.yml +3 -3
- data/test/fixtures/uuid_parents.yml +2 -2
- data/test/fixtures/variants.yml +4 -4
- data/test/fixtures/vegetables.yml +19 -19
- data/test/fixtures/vertices.yml +3 -3
- data/test/fixtures/warehouse_things.yml +2 -2
- data/test/fixtures/zines.yml +5 -5
- data/test/ibm_db_test.rb +24 -24
- data/test/migrations/10_urban/9_add_expressions.rb +11 -11
- data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -15
- data/test/migrations/magic/1_currencies_have_symbols.rb +12 -12
- data/test/migrations/missing/1000_people_have_middle_names.rb +8 -8
- data/test/migrations/missing/1_people_have_last_names.rb +8 -8
- data/test/migrations/missing/3_we_need_reminders.rb +11 -11
- data/test/migrations/missing/4_innocent_jointable.rb +11 -11
- data/test/migrations/rename/1_we_need_things.rb +10 -10
- data/test/migrations/rename/2_rename_things.rb +8 -8
- data/test/migrations/to_copy/1_people_have_hobbies.rb +9 -9
- data/test/migrations/to_copy/2_people_have_descriptions.rb +9 -9
- data/test/migrations/to_copy2/1_create_articles.rb +7 -7
- data/test/migrations/to_copy2/2_create_comments.rb +7 -7
- data/test/migrations/to_copy_with_name_collision/1_people_have_hobbies.rb +9 -9
- data/test/migrations/to_copy_with_timestamps/20090101010101_people_have_hobbies.rb +9 -9
- data/test/migrations/to_copy_with_timestamps/20090101010202_people_have_descriptions.rb +9 -9
- data/test/migrations/to_copy_with_timestamps2/20090101010101_create_articles.rb +7 -7
- data/test/migrations/to_copy_with_timestamps2/20090101010202_create_comments.rb +7 -7
- data/test/migrations/valid/1_valid_people_have_last_names.rb +9 -9
- data/test/migrations/valid/2_we_need_reminders.rb +11 -11
- data/test/migrations/valid/3_innocent_jointable.rb +11 -11
- data/test/migrations/valid_with_subdirectories/1_valid_people_have_last_names.rb +9 -9
- data/test/migrations/valid_with_subdirectories/sub/2_we_need_reminders.rb +11 -11
- data/test/migrations/valid_with_subdirectories/sub1/3_innocent_jointable.rb +11 -11
- data/test/migrations/valid_with_timestamps/20100101010101_valid_with_timestamps_people_have_last_names.rb +9 -9
- data/test/migrations/valid_with_timestamps/20100201010101_valid_with_timestamps_we_need_reminders.rb +12 -12
- data/test/migrations/valid_with_timestamps/20100301010101_valid_with_timestamps_innocent_jointable.rb +12 -12
- data/test/migrations/version_check/20131219224947_migration_version_check.rb +8 -8
- data/test/models/admin.rb +4 -4
- data/test/models/admin/account.rb +2 -2
- data/test/models/admin/randomly_named_c1.rb +3 -3
- data/test/models/admin/user.rb +40 -40
- data/test/models/aircraft.rb +4 -4
- data/test/models/arunit2_model.rb +3 -3
- data/test/models/author.rb +212 -212
- data/test/models/auto_id.rb +4 -4
- data/test/models/autoloadable/extra_firm.rb +2 -2
- data/test/models/binary.rb +1 -1
- data/test/models/bird.rb +12 -12
- data/test/models/book.rb +18 -18
- data/test/models/boolean.rb +2 -2
- data/test/models/bulb.rb +51 -51
- data/test/models/cake_designer.rb +3 -3
- data/test/models/car.rb +26 -26
- data/test/models/carrier.rb +2 -2
- data/test/models/categorization.rb +19 -19
- data/test/models/category.rb +35 -35
- data/test/models/chef.rb +7 -3
- data/test/models/citation.rb +3 -3
- data/test/models/club.rb +23 -23
- data/test/models/college.rb +10 -10
- data/test/models/column.rb +3 -3
- data/test/models/column_name.rb +3 -3
- data/test/models/comment.rb +64 -64
- data/test/models/company.rb +228 -225
- data/test/models/company_in_module.rb +98 -98
- data/test/models/computer.rb +3 -3
- data/test/models/contact.rb +41 -41
- data/test/models/contract.rb +20 -20
- data/test/models/country.rb +7 -7
- data/test/models/course.rb +6 -6
- data/test/models/customer.rb +77 -77
- data/test/models/customer_carrier.rb +14 -14
- data/test/models/dashboard.rb +3 -3
- data/test/models/default.rb +2 -2
- data/test/models/department.rb +4 -4
- data/test/models/developer.rb +255 -252
- data/test/models/dog.rb +5 -5
- data/test/models/dog_lover.rb +5 -5
- data/test/models/doubloon.rb +12 -12
- data/test/models/drink_designer.rb +3 -3
- data/test/models/edge.rb +5 -5
- data/test/models/electron.rb +5 -5
- data/test/models/engine.rb +4 -4
- data/test/models/entrant.rb +3 -3
- data/test/models/essay.rb +5 -5
- data/test/models/event.rb +2 -2
- data/test/models/eye.rb +37 -37
- data/test/models/face.rb +9 -9
- data/test/models/friendship.rb +6 -6
- data/test/models/guid.rb +1 -1
- data/test/models/hotel.rb +9 -6
- data/test/models/image.rb +3 -3
- data/test/models/interest.rb +5 -5
- data/test/models/invoice.rb +4 -4
- data/test/models/item.rb +7 -7
- data/test/models/job.rb +7 -7
- data/test/models/joke.rb +7 -7
- data/test/models/keyboard.rb +3 -3
- data/test/models/legacy_thing.rb +3 -3
- data/test/models/lesson.rb +11 -11
- data/test/models/line_item.rb +3 -3
- data/test/models/liquid.rb +4 -4
- data/test/models/man.rb +11 -11
- data/test/models/matey.rb +4 -4
- data/test/models/member.rb +41 -41
- data/test/models/member_detail.rb +7 -7
- data/test/models/member_type.rb +3 -3
- data/test/models/membership.rb +35 -35
- data/test/models/minimalistic.rb +2 -2
- data/test/models/minivan.rb +9 -9
- data/test/models/mixed_case_monkey.rb +3 -3
- data/test/models/molecule.rb +6 -6
- data/test/models/movie.rb +5 -5
- data/test/models/order.rb +4 -4
- data/test/models/organization.rb +14 -14
- data/test/models/owner.rb +34 -34
- data/test/models/parrot.rb +29 -29
- data/test/models/person.rb +143 -143
- data/test/models/personal_legacy_thing.rb +4 -4
- data/test/models/pet.rb +15 -15
- data/test/models/pirate.rb +92 -92
- data/test/models/possession.rb +3 -3
- data/test/models/post.rb +264 -264
- data/test/models/price_estimate.rb +4 -4
- data/test/models/professor.rb +5 -5
- data/test/models/project.rb +31 -29
- data/test/models/publisher.rb +2 -2
- data/test/models/publisher/article.rb +4 -4
- data/test/models/publisher/magazine.rb +3 -3
- data/test/models/randomly_named_c1.rb +3 -3
- data/test/models/rating.rb +4 -4
- data/test/models/reader.rb +23 -23
- data/test/models/record.rb +2 -2
- data/test/models/reference.rb +22 -22
- data/test/models/reply.rb +61 -61
- data/test/models/ship.rb +33 -33
- data/test/models/ship_part.rb +7 -7
- data/test/models/shop.rb +17 -17
- data/test/models/shop_account.rb +6 -6
- data/test/models/speedometer.rb +6 -6
- data/test/models/sponsor.rb +7 -7
- data/test/models/string_key_object.rb +3 -3
- data/test/models/student.rb +4 -4
- data/test/models/subject.rb +16 -16
- data/test/models/subscriber.rb +8 -8
- data/test/models/subscription.rb +4 -4
- data/test/models/tag.rb +7 -7
- data/test/models/tagging.rb +13 -13
- data/test/models/task.rb +5 -5
- data/test/models/topic.rb +124 -124
- data/test/models/toy.rb +6 -6
- data/test/models/traffic_light.rb +4 -4
- data/test/models/treasure.rb +14 -14
- data/test/models/treaty.rb +7 -7
- data/test/models/tyre.rb +11 -11
- data/test/models/uuid_child.rb +3 -3
- data/test/models/uuid_parent.rb +3 -3
- data/test/models/vegetables.rb +24 -24
- data/test/models/vehicle.rb +6 -6
- data/test/models/vertex.rb +9 -9
- data/test/models/warehouse_thing.rb +5 -5
- data/test/models/wheel.rb +3 -3
- data/test/models/without_table.rb +3 -3
- data/test/models/zine.rb +3 -3
- data/test/schema/mysql2_specific_schema.rb +58 -58
- data/test/schema/mysql_specific_schema.rb +70 -70
- data/test/schema/oracle_specific_schema.rb +43 -43
- data/test/schema/postgresql_specific_schema.rb +202 -202
- data/test/schema/schema.rb +952 -938
- data/test/schema/sqlite_specific_schema.rb +21 -21
- data/test/support/config.rb +43 -43
- data/test/support/connection.rb +22 -22
- data/test/support/connection_helper.rb +14 -14
- data/test/support/ddl_helper.rb +8 -8
- data/test/support/schema_dumping_helper.rb +20 -20
- metadata +2 -2
@@ -1,125 +1,125 @@
|
|
1
|
-
require 'cases/helper'
|
2
|
-
|
3
|
-
module ActiveRecord
|
4
|
-
class AttributeDecoratorsTest < ActiveRecord::TestCase
|
5
|
-
class Model < ActiveRecord::Base
|
6
|
-
self.table_name = 'attribute_decorators_model'
|
7
|
-
end
|
8
|
-
|
9
|
-
class StringDecorator < SimpleDelegator
|
10
|
-
def initialize(delegate, decoration = "decorated!")
|
11
|
-
@decoration = decoration
|
12
|
-
super(delegate)
|
13
|
-
end
|
14
|
-
|
15
|
-
def type_cast_from_user(value)
|
16
|
-
"#{super} #{@decoration}"
|
17
|
-
end
|
18
|
-
|
19
|
-
alias type_cast_from_database type_cast_from_user
|
20
|
-
end
|
21
|
-
|
22
|
-
setup do
|
23
|
-
@connection = ActiveRecord::Base.connection
|
24
|
-
@connection.create_table :attribute_decorators_model, force: true do |t|
|
25
|
-
t.string :a_string
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
teardown do
|
30
|
-
return unless @connection
|
31
|
-
@connection.drop_table 'attribute_decorators_model' if @connection.table_exists? 'attribute_decorators_model'
|
32
|
-
Model.attribute_type_decorations.clear
|
33
|
-
Model.reset_column_information
|
34
|
-
end
|
35
|
-
|
36
|
-
test "attributes can be decorated" do
|
37
|
-
model = Model.new(a_string: 'Hello')
|
38
|
-
assert_equal 'Hello', model.a_string
|
39
|
-
|
40
|
-
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
41
|
-
|
42
|
-
model = Model.new(a_string: 'Hello')
|
43
|
-
assert_equal 'Hello decorated!', model.a_string
|
44
|
-
end
|
45
|
-
|
46
|
-
test "decoration does not eagerly load existing columns" do
|
47
|
-
Model.reset_column_information
|
48
|
-
assert_no_queries do
|
49
|
-
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
test "undecorated columns are not touched" do
|
54
|
-
Model.attribute :another_string, Type::String.new, default: 'something or other'
|
55
|
-
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
56
|
-
|
57
|
-
assert_equal 'something or other', Model.new.another_string
|
58
|
-
end
|
59
|
-
|
60
|
-
test "decorators can be chained" do
|
61
|
-
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
62
|
-
Model.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) }
|
63
|
-
|
64
|
-
model = Model.new(a_string: 'Hello!')
|
65
|
-
|
66
|
-
assert_equal 'Hello! decorated! decorated!', model.a_string
|
67
|
-
end
|
68
|
-
|
69
|
-
test "decoration of the same type multiple times is idempotent" do
|
70
|
-
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
71
|
-
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
72
|
-
|
73
|
-
model = Model.new(a_string: 'Hello')
|
74
|
-
assert_equal 'Hello decorated!', model.a_string
|
75
|
-
end
|
76
|
-
|
77
|
-
test "decorations occur in order of declaration" do
|
78
|
-
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
79
|
-
Model.decorate_attribute_type(:a_string, :other) do |type|
|
80
|
-
StringDecorator.new(type, 'decorated again!')
|
81
|
-
end
|
82
|
-
|
83
|
-
model = Model.new(a_string: 'Hello!')
|
84
|
-
|
85
|
-
assert_equal 'Hello! decorated! decorated again!', model.a_string
|
86
|
-
end
|
87
|
-
|
88
|
-
test "decorating attributes does not modify parent classes" do
|
89
|
-
Model.attribute :another_string, Type::String.new, default: 'whatever'
|
90
|
-
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
91
|
-
child_class = Class.new(Model)
|
92
|
-
child_class.decorate_attribute_type(:another_string, :test) { |t| StringDecorator.new(t) }
|
93
|
-
child_class.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) }
|
94
|
-
|
95
|
-
model = Model.new(a_string: 'Hello!')
|
96
|
-
child = child_class.new(a_string: 'Hello!')
|
97
|
-
|
98
|
-
assert_equal 'Hello! decorated!', model.a_string
|
99
|
-
assert_equal 'whatever', model.another_string
|
100
|
-
assert_equal 'Hello! decorated! decorated!', child.a_string
|
101
|
-
assert_equal 'whatever decorated!', child.another_string
|
102
|
-
end
|
103
|
-
|
104
|
-
class Multiplier < SimpleDelegator
|
105
|
-
def type_cast_from_user(value)
|
106
|
-
return if value.nil?
|
107
|
-
value * 2
|
108
|
-
end
|
109
|
-
alias type_cast_from_database type_cast_from_user
|
110
|
-
end
|
111
|
-
|
112
|
-
test "decorating with a proc" do
|
113
|
-
Model.attribute :an_int, Type::Integer.new
|
114
|
-
type_is_integer = proc { |_, type| type.type == :integer }
|
115
|
-
Model.decorate_matching_attribute_types type_is_integer, :multiplier do |type|
|
116
|
-
Multiplier.new(type)
|
117
|
-
end
|
118
|
-
|
119
|
-
model = Model.new(a_string: 'whatever', an_int: 1)
|
120
|
-
|
121
|
-
assert_equal 'whatever', model.a_string
|
122
|
-
assert_equal 2, model.an_int
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
1
|
+
require 'cases/helper'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
class AttributeDecoratorsTest < ActiveRecord::TestCase
|
5
|
+
class Model < ActiveRecord::Base
|
6
|
+
self.table_name = 'attribute_decorators_model'
|
7
|
+
end
|
8
|
+
|
9
|
+
class StringDecorator < SimpleDelegator
|
10
|
+
def initialize(delegate, decoration = "decorated!")
|
11
|
+
@decoration = decoration
|
12
|
+
super(delegate)
|
13
|
+
end
|
14
|
+
|
15
|
+
def type_cast_from_user(value)
|
16
|
+
"#{super} #{@decoration}"
|
17
|
+
end
|
18
|
+
|
19
|
+
alias type_cast_from_database type_cast_from_user
|
20
|
+
end
|
21
|
+
|
22
|
+
setup do
|
23
|
+
@connection = ActiveRecord::Base.connection
|
24
|
+
@connection.create_table :attribute_decorators_model, force: true do |t|
|
25
|
+
t.string :a_string
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
teardown do
|
30
|
+
return unless @connection
|
31
|
+
@connection.drop_table 'attribute_decorators_model' if @connection.table_exists? 'attribute_decorators_model'
|
32
|
+
Model.attribute_type_decorations.clear
|
33
|
+
Model.reset_column_information
|
34
|
+
end
|
35
|
+
|
36
|
+
test "attributes can be decorated" do
|
37
|
+
model = Model.new(a_string: 'Hello')
|
38
|
+
assert_equal 'Hello', model.a_string
|
39
|
+
|
40
|
+
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
41
|
+
|
42
|
+
model = Model.new(a_string: 'Hello')
|
43
|
+
assert_equal 'Hello decorated!', model.a_string
|
44
|
+
end
|
45
|
+
|
46
|
+
test "decoration does not eagerly load existing columns" do
|
47
|
+
Model.reset_column_information
|
48
|
+
assert_no_queries do
|
49
|
+
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
test "undecorated columns are not touched" do
|
54
|
+
Model.attribute :another_string, Type::String.new, default: 'something or other'
|
55
|
+
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
56
|
+
|
57
|
+
assert_equal 'something or other', Model.new.another_string
|
58
|
+
end
|
59
|
+
|
60
|
+
test "decorators can be chained" do
|
61
|
+
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
62
|
+
Model.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) }
|
63
|
+
|
64
|
+
model = Model.new(a_string: 'Hello!')
|
65
|
+
|
66
|
+
assert_equal 'Hello! decorated! decorated!', model.a_string
|
67
|
+
end
|
68
|
+
|
69
|
+
test "decoration of the same type multiple times is idempotent" do
|
70
|
+
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
71
|
+
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
72
|
+
|
73
|
+
model = Model.new(a_string: 'Hello')
|
74
|
+
assert_equal 'Hello decorated!', model.a_string
|
75
|
+
end
|
76
|
+
|
77
|
+
test "decorations occur in order of declaration" do
|
78
|
+
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
79
|
+
Model.decorate_attribute_type(:a_string, :other) do |type|
|
80
|
+
StringDecorator.new(type, 'decorated again!')
|
81
|
+
end
|
82
|
+
|
83
|
+
model = Model.new(a_string: 'Hello!')
|
84
|
+
|
85
|
+
assert_equal 'Hello! decorated! decorated again!', model.a_string
|
86
|
+
end
|
87
|
+
|
88
|
+
test "decorating attributes does not modify parent classes" do
|
89
|
+
Model.attribute :another_string, Type::String.new, default: 'whatever'
|
90
|
+
Model.decorate_attribute_type(:a_string, :test) { |t| StringDecorator.new(t) }
|
91
|
+
child_class = Class.new(Model)
|
92
|
+
child_class.decorate_attribute_type(:another_string, :test) { |t| StringDecorator.new(t) }
|
93
|
+
child_class.decorate_attribute_type(:a_string, :other) { |t| StringDecorator.new(t) }
|
94
|
+
|
95
|
+
model = Model.new(a_string: 'Hello!')
|
96
|
+
child = child_class.new(a_string: 'Hello!')
|
97
|
+
|
98
|
+
assert_equal 'Hello! decorated!', model.a_string
|
99
|
+
assert_equal 'whatever', model.another_string
|
100
|
+
assert_equal 'Hello! decorated! decorated!', child.a_string
|
101
|
+
assert_equal 'whatever decorated!', child.another_string
|
102
|
+
end
|
103
|
+
|
104
|
+
class Multiplier < SimpleDelegator
|
105
|
+
def type_cast_from_user(value)
|
106
|
+
return if value.nil?
|
107
|
+
value * 2
|
108
|
+
end
|
109
|
+
alias type_cast_from_database type_cast_from_user
|
110
|
+
end
|
111
|
+
|
112
|
+
test "decorating with a proc" do
|
113
|
+
Model.attribute :an_int, Type::Integer.new
|
114
|
+
type_is_integer = proc { |_, type| type.type == :integer }
|
115
|
+
Model.decorate_matching_attribute_types type_is_integer, :multiplier do |type|
|
116
|
+
Multiplier.new(type)
|
117
|
+
end
|
118
|
+
|
119
|
+
model = Model.new(a_string: 'whatever', an_int: 1)
|
120
|
+
|
121
|
+
assert_equal 'whatever', model.a_string
|
122
|
+
assert_equal 2, model.an_int
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -1,60 +1,60 @@
|
|
1
|
-
require "cases/helper"
|
2
|
-
require 'thread'
|
3
|
-
|
4
|
-
module ActiveRecord
|
5
|
-
module AttributeMethods
|
6
|
-
class ReadTest < ActiveRecord::TestCase
|
7
|
-
class FakeColumn < Struct.new(:name)
|
8
|
-
def type; :integer; end
|
9
|
-
end
|
10
|
-
|
11
|
-
def setup
|
12
|
-
@klass = Class.new do
|
13
|
-
def self.superclass; Base; end
|
14
|
-
def self.base_class; self; end
|
15
|
-
def self.decorate_matching_attribute_types(*); end
|
16
|
-
def self.initialize_generated_modules; end
|
17
|
-
|
18
|
-
include ActiveRecord::AttributeMethods
|
19
|
-
|
20
|
-
def self.column_names
|
21
|
-
%w{ one two three }
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.primary_key
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.columns
|
28
|
-
column_names.map { FakeColumn.new(name) }
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.columns_hash
|
32
|
-
Hash[column_names.map { |name|
|
33
|
-
[name, FakeColumn.new(name)]
|
34
|
-
}]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_define_attribute_methods
|
40
|
-
instance = @klass.new
|
41
|
-
|
42
|
-
@klass.column_names.each do |name|
|
43
|
-
assert !instance.methods.map(&:to_s).include?(name)
|
44
|
-
end
|
45
|
-
|
46
|
-
@klass.define_attribute_methods
|
47
|
-
|
48
|
-
@klass.column_names.each do |name|
|
49
|
-
assert instance.methods.map(&:to_s).include?(name), "#{name} is not defined"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def test_attribute_methods_generated?
|
54
|
-
assert_not @klass.method_defined?(:one)
|
55
|
-
@klass.define_attribute_methods
|
56
|
-
assert @klass.method_defined?(:one)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
1
|
+
require "cases/helper"
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module AttributeMethods
|
6
|
+
class ReadTest < ActiveRecord::TestCase
|
7
|
+
class FakeColumn < Struct.new(:name)
|
8
|
+
def type; :integer; end
|
9
|
+
end
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@klass = Class.new do
|
13
|
+
def self.superclass; Base; end
|
14
|
+
def self.base_class; self; end
|
15
|
+
def self.decorate_matching_attribute_types(*); end
|
16
|
+
def self.initialize_generated_modules; end
|
17
|
+
|
18
|
+
include ActiveRecord::AttributeMethods
|
19
|
+
|
20
|
+
def self.column_names
|
21
|
+
%w{ one two three }
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.primary_key
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.columns
|
28
|
+
column_names.map { FakeColumn.new(name) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.columns_hash
|
32
|
+
Hash[column_names.map { |name|
|
33
|
+
[name, FakeColumn.new(name)]
|
34
|
+
}]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_define_attribute_methods
|
40
|
+
instance = @klass.new
|
41
|
+
|
42
|
+
@klass.column_names.each do |name|
|
43
|
+
assert !instance.methods.map(&:to_s).include?(name)
|
44
|
+
end
|
45
|
+
|
46
|
+
@klass.define_attribute_methods
|
47
|
+
|
48
|
+
@klass.column_names.each do |name|
|
49
|
+
assert instance.methods.map(&:to_s).include?(name), "#{name} is not defined"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_attribute_methods_generated?
|
54
|
+
assert_not @klass.method_defined?(:one)
|
55
|
+
@klass.define_attribute_methods
|
56
|
+
assert @klass.method_defined?(:one)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,29 +1,29 @@
|
|
1
|
-
require "cases/helper"
|
2
|
-
|
3
|
-
module ActiveRecord
|
4
|
-
module AttributeMethods
|
5
|
-
class SerializationTest < ActiveSupport::TestCase
|
6
|
-
class FakeColumn < Struct.new(:name)
|
7
|
-
def type; :integer; end
|
8
|
-
def type_cast(s); "#{s}!"; end
|
9
|
-
end
|
10
|
-
|
11
|
-
class NullCoder
|
12
|
-
def load(v); v; end
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_type_cast_serialized_value
|
16
|
-
value = Serialization::Attribute.new(NullCoder.new, "Hello world", :serialized)
|
17
|
-
type = Serialization::Type.new(FakeColumn.new)
|
18
|
-
assert_equal "Hello world!", type.type_cast(value)
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_type_cast_unserialized_value
|
22
|
-
value = Serialization::Attribute.new(nil, "Hello world", :unserialized)
|
23
|
-
type = Serialization::Type.new(FakeColumn.new)
|
24
|
-
type.type_cast(value)
|
25
|
-
assert_equal "Hello world", type.type_cast(value)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
1
|
+
require "cases/helper"
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module AttributeMethods
|
5
|
+
class SerializationTest < ActiveSupport::TestCase
|
6
|
+
class FakeColumn < Struct.new(:name)
|
7
|
+
def type; :integer; end
|
8
|
+
def type_cast(s); "#{s}!"; end
|
9
|
+
end
|
10
|
+
|
11
|
+
class NullCoder
|
12
|
+
def load(v); v; end
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_type_cast_serialized_value
|
16
|
+
value = Serialization::Attribute.new(NullCoder.new, "Hello world", :serialized)
|
17
|
+
type = Serialization::Type.new(FakeColumn.new)
|
18
|
+
assert_equal "Hello world!", type.type_cast(value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_type_cast_unserialized_value
|
22
|
+
value = Serialization::Attribute.new(nil, "Hello world", :unserialized)
|
23
|
+
type = Serialization::Type.new(FakeColumn.new)
|
24
|
+
type.type_cast(value)
|
25
|
+
assert_equal "Hello world", type.type_cast(value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,952 +1,952 @@
|
|
1
|
-
require "cases/helper"
|
2
|
-
require 'models/minimalistic'
|
3
|
-
require 'models/developer'
|
4
|
-
require 'models/computer'
|
5
|
-
require 'models/auto_id'
|
6
|
-
require 'models/boolean'
|
7
|
-
require 'models/computer'
|
8
|
-
require 'models/topic'
|
9
|
-
require 'models/company'
|
10
|
-
require 'models/category'
|
11
|
-
require 'models/reply'
|
12
|
-
require 'models/contact'
|
13
|
-
require 'models/keyboard'
|
14
|
-
|
15
|
-
class AttributeMethodsTest < ActiveRecord::TestCase
|
16
|
-
include InTimeZone
|
17
|
-
|
18
|
-
fixtures :topics, :developers, :companies, :computers
|
19
|
-
|
20
|
-
def setup
|
21
|
-
@old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
|
22
|
-
@target = Class.new(ActiveRecord::Base)
|
23
|
-
@target.table_name = 'topics'
|
24
|
-
end
|
25
|
-
|
26
|
-
teardown do
|
27
|
-
ActiveRecord::Base.send(:attribute_method_matchers).clear
|
28
|
-
ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_attribute_for_inspect
|
32
|
-
t = topics(:first)
|
33
|
-
t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
|
34
|
-
|
35
|
-
assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
|
36
|
-
assert_equal '"The First Topic Now Has A Title With\nNewlines And ..."', t.attribute_for_inspect(:title)
|
37
|
-
end
|
38
|
-
|
39
|
-
def test_attribute_present
|
40
|
-
t = Topic.new
|
41
|
-
t.title = "hello there!"
|
42
|
-
t.written_on = Time.now
|
43
|
-
t.author_name = ""
|
44
|
-
assert t.attribute_present?("title")
|
45
|
-
assert t.attribute_present?("written_on")
|
46
|
-
assert !t.attribute_present?("content")
|
47
|
-
assert !t.attribute_present?("author_name")
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_attribute_present_with_booleans
|
51
|
-
b1 = Boolean.new
|
52
|
-
b1.value = false
|
53
|
-
assert b1.attribute_present?(:value)
|
54
|
-
|
55
|
-
b2 = Boolean.new
|
56
|
-
b2.value = true
|
57
|
-
assert b2.attribute_present?(:value)
|
58
|
-
|
59
|
-
b3 = Boolean.new
|
60
|
-
assert !b3.attribute_present?(:value)
|
61
|
-
|
62
|
-
b4 = Boolean.new
|
63
|
-
b4.value = false
|
64
|
-
b4.save!
|
65
|
-
assert Boolean.find(b4.id).attribute_present?(:value)
|
66
|
-
end
|
67
|
-
|
68
|
-
def test_caching_nil_primary_key
|
69
|
-
klass = Class.new(Minimalistic)
|
70
|
-
klass.expects(:reset_primary_key).returns(nil).once
|
71
|
-
2.times { klass.primary_key }
|
72
|
-
end
|
73
|
-
|
74
|
-
def test_attribute_keys_on_new_instance
|
75
|
-
t = Topic.new
|
76
|
-
assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
|
77
|
-
assert_raise(NoMethodError) { t.title2 }
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_boolean_attributes
|
81
|
-
assert !Topic.find(1).approved?
|
82
|
-
assert Topic.find(2).approved?
|
83
|
-
end
|
84
|
-
|
85
|
-
def test_set_attributes
|
86
|
-
topic = Topic.find(1)
|
87
|
-
topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
|
88
|
-
topic.save
|
89
|
-
assert_equal("Budget", topic.title)
|
90
|
-
assert_equal("Jason", topic.author_name)
|
91
|
-
assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
|
92
|
-
end
|
93
|
-
|
94
|
-
def test_set_attributes_without_hash
|
95
|
-
topic = Topic.new
|
96
|
-
assert_raise(ArgumentError) { topic.attributes = '' }
|
97
|
-
end
|
98
|
-
|
99
|
-
def test_integers_as_nil
|
100
|
-
test = AutoId.create('value' => '')
|
101
|
-
assert_nil AutoId.find(test.id).value
|
102
|
-
end
|
103
|
-
|
104
|
-
def test_set_attributes_with_block
|
105
|
-
topic = Topic.new do |t|
|
106
|
-
t.title = "Budget"
|
107
|
-
t.author_name = "Jason"
|
108
|
-
end
|
109
|
-
|
110
|
-
assert_equal("Budget", topic.title)
|
111
|
-
assert_equal("Jason", topic.author_name)
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_respond_to?
|
115
|
-
topic = Topic.find(1)
|
116
|
-
assert_respond_to topic, "title"
|
117
|
-
assert_respond_to topic, "title?"
|
118
|
-
assert_respond_to topic, "title="
|
119
|
-
assert_respond_to topic, :title
|
120
|
-
assert_respond_to topic, :title?
|
121
|
-
assert_respond_to topic, :title=
|
122
|
-
assert_respond_to topic, "author_name"
|
123
|
-
assert_respond_to topic, "attribute_names"
|
124
|
-
assert !topic.respond_to?("nothingness")
|
125
|
-
assert !topic.respond_to?(:nothingness)
|
126
|
-
end
|
127
|
-
|
128
|
-
def test_respond_to_with_custom_primary_key
|
129
|
-
keyboard = Keyboard.create
|
130
|
-
assert_not_nil keyboard.key_number
|
131
|
-
assert_equal keyboard.key_number, keyboard.id
|
132
|
-
assert keyboard.respond_to?('key_number')
|
133
|
-
assert keyboard.respond_to?('id')
|
134
|
-
end
|
135
|
-
|
136
|
-
def test_id_before_type_cast_with_custom_primary_key
|
137
|
-
keyboard = Keyboard.create
|
138
|
-
keyboard.key_number = '10'
|
139
|
-
assert_equal '10', keyboard.id_before_type_cast
|
140
|
-
assert_equal nil, keyboard.read_attribute_before_type_cast('id')
|
141
|
-
assert_equal '10', keyboard.read_attribute_before_type_cast('key_number')
|
142
|
-
assert_equal '10', keyboard.read_attribute_before_type_cast(:key_number)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Syck calls respond_to? before actually calling initialize
|
146
|
-
def test_respond_to_with_allocated_object
|
147
|
-
klass = Class.new(ActiveRecord::Base) do
|
148
|
-
self.table_name = 'topics'
|
149
|
-
end
|
150
|
-
|
151
|
-
topic = klass.allocate
|
152
|
-
assert !topic.respond_to?("nothingness")
|
153
|
-
assert !topic.respond_to?(:nothingness)
|
154
|
-
assert_respond_to topic, "title"
|
155
|
-
assert_respond_to topic, :title
|
156
|
-
end
|
157
|
-
|
158
|
-
# IRB inspects the return value of "MyModel.allocate".
|
159
|
-
def test_allocated_object_can_be_inspected
|
160
|
-
topic = Topic.allocate
|
161
|
-
assert_equal "#<Topic not initialized>", topic.inspect
|
162
|
-
end
|
163
|
-
|
164
|
-
def test_array_content
|
165
|
-
topic = Topic.new
|
166
|
-
topic.content = %w( one two three )
|
167
|
-
topic.save
|
168
|
-
|
169
|
-
assert_equal(%w( one two three ), Topic.find(topic.id).content)
|
170
|
-
end
|
171
|
-
|
172
|
-
def test_read_attributes_before_type_cast
|
173
|
-
category = Category.new({:name=>"Test category", :type => nil})
|
174
|
-
category_attrs = {"name"=>"Test category", "id" => nil, "type" => nil, "categorizations_count" => nil}
|
175
|
-
assert_equal category_attrs , category.attributes_before_type_cast
|
176
|
-
end
|
177
|
-
|
178
|
-
if current_adapter?(:MysqlAdapter)
|
179
|
-
def test_read_attributes_before_type_cast_on_boolean
|
180
|
-
bool = Boolean.create({ "value" => false })
|
181
|
-
if RUBY_PLATFORM =~ /java/
|
182
|
-
# JRuby will return the value before typecast as string
|
183
|
-
assert_equal "0", bool.reload.attributes_before_type_cast["value"]
|
184
|
-
else
|
185
|
-
assert_equal 0, bool.reload.attributes_before_type_cast["value"]
|
186
|
-
end
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
def test_read_attributes_before_type_cast_on_datetime
|
191
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
192
|
-
record = @target.new
|
193
|
-
|
194
|
-
record.written_on = "345643456"
|
195
|
-
assert_equal "345643456", record.written_on_before_type_cast
|
196
|
-
assert_equal nil, record.written_on
|
197
|
-
|
198
|
-
record.written_on = "2009-10-11 12:13:14"
|
199
|
-
assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast
|
200
|
-
assert_equal Time.zone.parse("2009-10-11 12:13:14"), record.written_on
|
201
|
-
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def test_read_attributes_after_type_cast_on_datetime
|
206
|
-
tz = "Pacific Time (US & Canada)"
|
207
|
-
|
208
|
-
in_time_zone tz do
|
209
|
-
record = @target.new
|
210
|
-
|
211
|
-
date_string = "2011-03-24"
|
212
|
-
time = Time.zone.parse date_string
|
213
|
-
|
214
|
-
record.written_on = date_string
|
215
|
-
assert_equal date_string, record.written_on_before_type_cast
|
216
|
-
assert_equal time, record.written_on
|
217
|
-
assert_equal ActiveSupport::TimeZone[tz], record.written_on.time_zone
|
218
|
-
|
219
|
-
record.save
|
220
|
-
record.reload
|
221
|
-
|
222
|
-
assert_equal time, record.written_on
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def test_hash_content
|
227
|
-
topic = Topic.new
|
228
|
-
topic.content = { "one" => 1, "two" => 2 }
|
229
|
-
topic.save
|
230
|
-
|
231
|
-
assert_equal 2, Topic.find(topic.id).content["two"]
|
232
|
-
|
233
|
-
topic.content_will_change!
|
234
|
-
topic.content["three"] = 3
|
235
|
-
topic.save
|
236
|
-
|
237
|
-
assert_equal 3, Topic.find(topic.id).content["three"]
|
238
|
-
end
|
239
|
-
|
240
|
-
def test_update_array_content
|
241
|
-
topic = Topic.new
|
242
|
-
topic.content = %w( one two three )
|
243
|
-
|
244
|
-
topic.content.push "four"
|
245
|
-
assert_equal(%w( one two three four ), topic.content)
|
246
|
-
|
247
|
-
topic.save
|
248
|
-
|
249
|
-
topic = Topic.find(topic.id)
|
250
|
-
topic.content << "five"
|
251
|
-
assert_equal(%w( one two three four five ), topic.content)
|
252
|
-
end
|
253
|
-
|
254
|
-
def test_case_sensitive_attributes_hash
|
255
|
-
# DB2 is not case-sensitive
|
256
|
-
return true if current_adapter?(:DB2Adapter) || current_adapter?(:IBM_DBAdapter)
|
257
|
-
|
258
|
-
assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.first.attributes
|
259
|
-
end
|
260
|
-
|
261
|
-
def test_attributes_without_primary_key
|
262
|
-
klass = Class.new(ActiveRecord::Base) do
|
263
|
-
self.table_name = 'developers_projects'
|
264
|
-
end
|
265
|
-
|
266
|
-
assert_equal klass.column_names, klass.new.attributes.keys
|
267
|
-
assert_not klass.new.has_attribute?('id')
|
268
|
-
end
|
269
|
-
|
270
|
-
def test_hashes_not_mangled
|
271
|
-
new_topic = { :title => "New Topic" }
|
272
|
-
new_topic_values = { :title => "AnotherTopic" }
|
273
|
-
|
274
|
-
topic = Topic.new(new_topic)
|
275
|
-
assert_equal new_topic[:title], topic.title
|
276
|
-
|
277
|
-
topic.attributes= new_topic_values
|
278
|
-
assert_equal new_topic_values[:title], topic.title
|
279
|
-
end
|
280
|
-
|
281
|
-
def test_create_through_factory
|
282
|
-
topic = Topic.create("title" => "New Topic")
|
283
|
-
topicReloaded = Topic.find(topic.id)
|
284
|
-
assert_equal(topic, topicReloaded)
|
285
|
-
end
|
286
|
-
|
287
|
-
def test_write_attribute
|
288
|
-
topic = Topic.new
|
289
|
-
topic.send(:write_attribute, :title, "Still another topic")
|
290
|
-
assert_equal "Still another topic", topic.title
|
291
|
-
|
292
|
-
topic[:title] = "Still another topic: part 2"
|
293
|
-
assert_equal "Still another topic: part 2", topic.title
|
294
|
-
|
295
|
-
topic.send(:write_attribute, "title", "Still another topic: part 3")
|
296
|
-
assert_equal "Still another topic: part 3", topic.title
|
297
|
-
|
298
|
-
topic["title"] = "Still another topic: part 4"
|
299
|
-
assert_equal "Still another topic: part 4", topic.title
|
300
|
-
end
|
301
|
-
|
302
|
-
def test_read_attribute
|
303
|
-
topic = Topic.new
|
304
|
-
topic.title = "Don't change the topic"
|
305
|
-
assert_equal "Don't change the topic", topic.read_attribute("title")
|
306
|
-
assert_equal "Don't change the topic", topic["title"]
|
307
|
-
|
308
|
-
assert_equal "Don't change the topic", topic.read_attribute(:title)
|
309
|
-
assert_equal "Don't change the topic", topic[:title]
|
310
|
-
end
|
311
|
-
|
312
|
-
def test_read_attribute_raises_missing_attribute_error_when_not_exists
|
313
|
-
computer = Computer.select('id').first
|
314
|
-
assert_raises(ActiveModel::MissingAttributeError) { computer[:developer] }
|
315
|
-
assert_raises(ActiveModel::MissingAttributeError) { computer[:extendedWarranty] }
|
316
|
-
assert_raises(ActiveModel::MissingAttributeError) { computer[:no_column_exists] = 'Hello!' }
|
317
|
-
assert_nothing_raised { computer[:developer] = 'Hello!' }
|
318
|
-
end
|
319
|
-
|
320
|
-
def test_read_attribute_when_false
|
321
|
-
topic = topics(:first)
|
322
|
-
topic.approved = false
|
323
|
-
assert !topic.approved?, "approved should be false"
|
324
|
-
topic.approved = "false"
|
325
|
-
assert !topic.approved?, "approved should be false"
|
326
|
-
end
|
327
|
-
|
328
|
-
def test_read_attribute_when_true
|
329
|
-
topic = topics(:first)
|
330
|
-
topic.approved = true
|
331
|
-
assert topic.approved?, "approved should be true"
|
332
|
-
topic.approved = "true"
|
333
|
-
assert topic.approved?, "approved should be true"
|
334
|
-
end
|
335
|
-
|
336
|
-
def test_read_write_boolean_attribute
|
337
|
-
topic = Topic.new
|
338
|
-
topic.approved = "false"
|
339
|
-
assert !topic.approved?, "approved should be false"
|
340
|
-
|
341
|
-
topic.approved = "false"
|
342
|
-
assert !topic.approved?, "approved should be false"
|
343
|
-
|
344
|
-
topic.approved = "true"
|
345
|
-
assert topic.approved?, "approved should be true"
|
346
|
-
|
347
|
-
topic.approved = "true"
|
348
|
-
assert topic.approved?, "approved should be true"
|
349
|
-
end
|
350
|
-
|
351
|
-
def test_overridden_write_attribute
|
352
|
-
topic = Topic.new
|
353
|
-
def topic.write_attribute(attr_name, value)
|
354
|
-
super(attr_name, value.downcase)
|
355
|
-
end
|
356
|
-
|
357
|
-
topic.send(:write_attribute, :title, "Yet another topic")
|
358
|
-
assert_equal "yet another topic", topic.title
|
359
|
-
|
360
|
-
topic[:title] = "Yet another topic: part 2"
|
361
|
-
assert_equal "yet another topic: part 2", topic.title
|
362
|
-
|
363
|
-
topic.send(:write_attribute, "title", "Yet another topic: part 3")
|
364
|
-
assert_equal "yet another topic: part 3", topic.title
|
365
|
-
|
366
|
-
topic["title"] = "Yet another topic: part 4"
|
367
|
-
assert_equal "yet another topic: part 4", topic.title
|
368
|
-
end
|
369
|
-
|
370
|
-
def test_overridden_read_attribute
|
371
|
-
topic = Topic.new
|
372
|
-
topic.title = "Stop changing the topic"
|
373
|
-
def topic.read_attribute(attr_name)
|
374
|
-
super(attr_name).upcase
|
375
|
-
end
|
376
|
-
|
377
|
-
assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute("title")
|
378
|
-
assert_equal "STOP CHANGING THE TOPIC", topic["title"]
|
379
|
-
|
380
|
-
assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute(:title)
|
381
|
-
assert_equal "STOP CHANGING THE TOPIC", topic[:title]
|
382
|
-
end
|
383
|
-
|
384
|
-
def test_read_overridden_attribute
|
385
|
-
topic = Topic.new(:title => 'a')
|
386
|
-
def topic.title() 'b' end
|
387
|
-
assert_equal 'a', topic[:title]
|
388
|
-
end
|
389
|
-
|
390
|
-
def test_query_attribute_string
|
391
|
-
[nil, "", " "].each do |value|
|
392
|
-
assert_equal false, Topic.new(:author_name => value).author_name?
|
393
|
-
end
|
394
|
-
|
395
|
-
assert_equal true, Topic.new(:author_name => "Name").author_name?
|
396
|
-
end
|
397
|
-
|
398
|
-
def test_query_attribute_number
|
399
|
-
[nil, 0, "0"].each do |value|
|
400
|
-
assert_equal false, Developer.new(:salary => value).salary?
|
401
|
-
end
|
402
|
-
|
403
|
-
assert_equal true, Developer.new(:salary => 1).salary?
|
404
|
-
assert_equal true, Developer.new(:salary => "1").salary?
|
405
|
-
end
|
406
|
-
|
407
|
-
def test_query_attribute_boolean
|
408
|
-
[nil, "", false, "false", "f", 0].each do |value|
|
409
|
-
assert_equal false, Topic.new(:approved => value).approved?
|
410
|
-
end
|
411
|
-
|
412
|
-
[true, "true", "1", 1].each do |value|
|
413
|
-
assert_equal true, Topic.new(:approved => value).approved?
|
414
|
-
end
|
415
|
-
end
|
416
|
-
|
417
|
-
def test_query_attribute_with_custom_fields
|
418
|
-
object = Company.find_by_sql(<<-SQL).first
|
419
|
-
SELECT c1.*, c2.type as string_value, c2.rating as int_value
|
420
|
-
FROM companies c1, companies c2
|
421
|
-
WHERE c1.firm_id = c2.id
|
422
|
-
AND c1.id = 2
|
423
|
-
SQL
|
424
|
-
|
425
|
-
assert_equal "Firm", object.string_value
|
426
|
-
assert object.string_value?
|
427
|
-
|
428
|
-
object.string_value = " "
|
429
|
-
assert !object.string_value?
|
430
|
-
|
431
|
-
assert_equal 1, object.int_value.to_i
|
432
|
-
assert object.int_value?
|
433
|
-
|
434
|
-
object.int_value = "0"
|
435
|
-
assert !object.int_value?
|
436
|
-
end
|
437
|
-
|
438
|
-
def test_non_attribute_access_and_assignment
|
439
|
-
topic = Topic.new
|
440
|
-
assert !topic.respond_to?("mumbo")
|
441
|
-
assert_raise(NoMethodError) { topic.mumbo }
|
442
|
-
assert_raise(NoMethodError) { topic.mumbo = 5 }
|
443
|
-
end
|
444
|
-
|
445
|
-
def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing
|
446
|
-
topic = @target.new(:title => 'Budget')
|
447
|
-
assert topic.respond_to?('title')
|
448
|
-
assert_equal 'Budget', topic.title
|
449
|
-
assert !topic.respond_to?('title_hello_world')
|
450
|
-
assert_raise(NoMethodError) { topic.title_hello_world }
|
451
|
-
end
|
452
|
-
|
453
|
-
def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing
|
454
|
-
topic = @target.new(:title => 'Budget')
|
455
|
-
%w(default_ title_).each do |prefix|
|
456
|
-
@target.class_eval "def #{prefix}attribute(*args) args end"
|
457
|
-
@target.attribute_method_prefix prefix
|
458
|
-
|
459
|
-
meth = "#{prefix}title"
|
460
|
-
assert topic.respond_to?(meth)
|
461
|
-
assert_equal ['title'], topic.send(meth)
|
462
|
-
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
463
|
-
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
464
|
-
end
|
465
|
-
end
|
466
|
-
|
467
|
-
def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing
|
468
|
-
%w(_default _title_default _it! _candidate= able?).each do |suffix|
|
469
|
-
@target.class_eval "def attribute#{suffix}(*args) args end"
|
470
|
-
@target.attribute_method_suffix suffix
|
471
|
-
topic = @target.new(:title => 'Budget')
|
472
|
-
|
473
|
-
meth = "title#{suffix}"
|
474
|
-
assert topic.respond_to?(meth)
|
475
|
-
assert_equal ['title'], topic.send(meth)
|
476
|
-
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
477
|
-
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
478
|
-
end
|
479
|
-
end
|
480
|
-
|
481
|
-
def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing
|
482
|
-
[['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix|
|
483
|
-
@target.class_eval "def #{prefix}attribute#{suffix}(*args) args end"
|
484
|
-
@target.attribute_method_affix({ :prefix => prefix, :suffix => suffix })
|
485
|
-
topic = @target.new(:title => 'Budget')
|
486
|
-
|
487
|
-
meth = "#{prefix}title#{suffix}"
|
488
|
-
assert topic.respond_to?(meth)
|
489
|
-
assert_equal ['title'], topic.send(meth)
|
490
|
-
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
491
|
-
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
492
|
-
end
|
493
|
-
end
|
494
|
-
|
495
|
-
def test_should_unserialize_attributes_for_frozen_records
|
496
|
-
myobj = {:value1 => :value2}
|
497
|
-
topic = Topic.create("content" => myobj)
|
498
|
-
topic.freeze
|
499
|
-
assert_equal myobj, topic.content
|
500
|
-
end
|
501
|
-
|
502
|
-
def test_typecast_attribute_from_select_to_false
|
503
|
-
Topic.create(:title => 'Budget')
|
504
|
-
# Oracle does not support boolean expressions in SELECT
|
505
|
-
if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
|
506
|
-
topic = Topic.all.merge!(:select => "topics.*, 0 as is_test").first
|
507
|
-
else
|
508
|
-
topic = Topic.all.merge!(:select => "topics.*, 1=2 as is_test").first
|
509
|
-
end
|
510
|
-
assert !topic.is_test?
|
511
|
-
end
|
512
|
-
|
513
|
-
def test_typecast_attribute_from_select_to_true
|
514
|
-
Topic.create(:title => 'Budget')
|
515
|
-
# Oracle does not support boolean expressions in SELECT
|
516
|
-
if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
|
517
|
-
topic = Topic.all.merge!(:select => "topics.*, 1 as is_test").first
|
518
|
-
else
|
519
|
-
topic = Topic.all.merge!(:select => "topics.*, 2=2 as is_test").first
|
520
|
-
end
|
521
|
-
assert topic.is_test?
|
522
|
-
end
|
523
|
-
|
524
|
-
def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
|
525
|
-
%w(save create_or_update).each do |method|
|
526
|
-
klass = Class.new ActiveRecord::Base
|
527
|
-
klass.class_eval "def #{method}() 'defined #{method}' end"
|
528
|
-
assert_raise ActiveRecord::DangerousAttributeError do
|
529
|
-
klass.instance_method_already_implemented?(method)
|
530
|
-
end
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
def test_deprecated_cache_attributes
|
535
|
-
assert_deprecated do
|
536
|
-
Topic.cache_attributes :replies_count
|
537
|
-
end
|
538
|
-
|
539
|
-
assert_deprecated do
|
540
|
-
Topic.cached_attributes
|
541
|
-
end
|
542
|
-
|
543
|
-
assert_deprecated do
|
544
|
-
Topic.cache_attribute? :replies_count
|
545
|
-
end
|
546
|
-
end
|
547
|
-
|
548
|
-
def test_converted_values_are_returned_after_assignment
|
549
|
-
developer = Developer.new(name: 1337, salary: "50000")
|
550
|
-
|
551
|
-
assert_equal "50000", developer.salary_before_type_cast
|
552
|
-
assert_equal 1337, developer.name_before_type_cast
|
553
|
-
|
554
|
-
assert_equal 50000, developer.salary
|
555
|
-
assert_equal "1337", developer.name
|
556
|
-
|
557
|
-
developer.save!
|
558
|
-
|
559
|
-
assert_equal "50000", developer.salary_before_type_cast
|
560
|
-
assert_equal 1337, developer.name_before_type_cast
|
561
|
-
|
562
|
-
assert_equal 50000, developer.salary
|
563
|
-
assert_equal "1337", developer.name
|
564
|
-
end
|
565
|
-
|
566
|
-
def test_write_nil_to_time_attributes
|
567
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
568
|
-
record = @target.new
|
569
|
-
record.written_on = nil
|
570
|
-
assert_nil record.written_on
|
571
|
-
end
|
572
|
-
end
|
573
|
-
|
574
|
-
def test_write_time_to_date_attributes
|
575
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
576
|
-
record = @target.new
|
577
|
-
record.last_read = Time.utc(2010, 1, 1, 10)
|
578
|
-
assert_equal Date.civil(2010, 1, 1), record.last_read
|
579
|
-
end
|
580
|
-
end
|
581
|
-
|
582
|
-
def test_time_attributes_are_retrieved_in_current_time_zone
|
583
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
584
|
-
utc_time = Time.utc(2008, 1, 1)
|
585
|
-
record = @target.new
|
586
|
-
record[:written_on] = utc_time
|
587
|
-
assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
|
588
|
-
assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
|
589
|
-
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
|
590
|
-
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
|
591
|
-
end
|
592
|
-
end
|
593
|
-
|
594
|
-
def test_setting_time_zone_aware_attribute_to_utc
|
595
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
596
|
-
utc_time = Time.utc(2008, 1, 1)
|
597
|
-
record = @target.new
|
598
|
-
record.written_on = utc_time
|
599
|
-
assert_equal utc_time, record.written_on
|
600
|
-
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
601
|
-
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
602
|
-
end
|
603
|
-
end
|
604
|
-
|
605
|
-
def test_setting_time_zone_aware_attribute_in_other_time_zone
|
606
|
-
utc_time = Time.utc(2008, 1, 1)
|
607
|
-
cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
|
608
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
609
|
-
record = @target.new
|
610
|
-
record.written_on = cst_time
|
611
|
-
assert_equal utc_time, record.written_on
|
612
|
-
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
613
|
-
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
614
|
-
end
|
615
|
-
end
|
616
|
-
|
617
|
-
def test_setting_time_zone_aware_read_attribute
|
618
|
-
utc_time = Time.utc(2008, 1, 1)
|
619
|
-
cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
|
620
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
621
|
-
record = @target.create(:written_on => cst_time).reload
|
622
|
-
assert_equal utc_time, record[:written_on]
|
623
|
-
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record[:written_on].time_zone
|
624
|
-
assert_equal Time.utc(2007, 12, 31, 16), record[:written_on].time
|
625
|
-
end
|
626
|
-
end
|
627
|
-
|
628
|
-
def test_setting_time_zone_aware_attribute_with_string
|
629
|
-
utc_time = Time.utc(2008, 1, 1)
|
630
|
-
(-11..13).each do |timezone_offset|
|
631
|
-
time_string = utc_time.in_time_zone(timezone_offset).to_s
|
632
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
633
|
-
record = @target.new
|
634
|
-
record.written_on = time_string
|
635
|
-
assert_equal Time.zone.parse(time_string), record.written_on
|
636
|
-
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
637
|
-
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
638
|
-
end
|
639
|
-
end
|
640
|
-
end
|
641
|
-
|
642
|
-
def test_time_zone_aware_attribute_saved
|
643
|
-
in_time_zone 1 do
|
644
|
-
record = @target.create(:written_on => '2012-02-20 10:00')
|
645
|
-
|
646
|
-
record.written_on = '2012-02-20 09:00'
|
647
|
-
record.save
|
648
|
-
assert_equal Time.zone.local(2012, 02, 20, 9), record.reload.written_on
|
649
|
-
end
|
650
|
-
end
|
651
|
-
|
652
|
-
def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
|
653
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
654
|
-
record = @target.new
|
655
|
-
record.written_on = ' '
|
656
|
-
assert_nil record.written_on
|
657
|
-
assert_nil record[:written_on]
|
658
|
-
end
|
659
|
-
end
|
660
|
-
|
661
|
-
def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
|
662
|
-
time_string = 'Tue Jan 01 00:00:00 2008'
|
663
|
-
(-11..13).each do |timezone_offset|
|
664
|
-
in_time_zone timezone_offset do
|
665
|
-
record = @target.new
|
666
|
-
record.written_on = time_string
|
667
|
-
assert_equal Time.zone.parse(time_string), record.written_on
|
668
|
-
assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
|
669
|
-
assert_equal Time.utc(2008, 1, 1), record.written_on.time
|
670
|
-
end
|
671
|
-
end
|
672
|
-
end
|
673
|
-
|
674
|
-
def test_setting_time_zone_aware_attribute_in_current_time_zone
|
675
|
-
utc_time = Time.utc(2008, 1, 1)
|
676
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
677
|
-
record = @target.new
|
678
|
-
record.written_on = utc_time.in_time_zone
|
679
|
-
assert_equal utc_time, record.written_on
|
680
|
-
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
681
|
-
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
682
|
-
end
|
683
|
-
end
|
684
|
-
|
685
|
-
def test_yaml_dumping_record_with_time_zone_aware_attribute
|
686
|
-
in_time_zone "Pacific Time (US & Canada)" do
|
687
|
-
record = Topic.new(id: 1)
|
688
|
-
record.written_on = "Jan 01 00:00:00 2014"
|
689
|
-
assert_equal record, YAML.load(YAML.dump(record))
|
690
|
-
end
|
691
|
-
end
|
692
|
-
|
693
|
-
def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
|
694
|
-
Topic.skip_time_zone_conversion_for_attributes = [:field_a]
|
695
|
-
Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
|
696
|
-
|
697
|
-
assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
|
698
|
-
assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
|
699
|
-
end
|
700
|
-
|
701
|
-
def test_read_attributes_respect_access_control
|
702
|
-
privatize("title")
|
703
|
-
|
704
|
-
topic = @target.new(:title => "The pros and cons of programming naked.")
|
705
|
-
assert !topic.respond_to?(:title)
|
706
|
-
exception = assert_raise(NoMethodError) { topic.title }
|
707
|
-
assert exception.message.include?("private method")
|
708
|
-
assert_equal "I'm private", topic.send(:title)
|
709
|
-
end
|
710
|
-
|
711
|
-
def test_write_attributes_respect_access_control
|
712
|
-
privatize("title=(value)")
|
713
|
-
|
714
|
-
topic = @target.new
|
715
|
-
assert !topic.respond_to?(:title=)
|
716
|
-
exception = assert_raise(NoMethodError) { topic.title = "Pants"}
|
717
|
-
assert exception.message.include?("private method")
|
718
|
-
topic.send(:title=, "Very large pants")
|
719
|
-
end
|
720
|
-
|
721
|
-
def test_question_attributes_respect_access_control
|
722
|
-
privatize("title?")
|
723
|
-
|
724
|
-
topic = @target.new(:title => "Isaac Newton's pants")
|
725
|
-
assert !topic.respond_to?(:title?)
|
726
|
-
exception = assert_raise(NoMethodError) { topic.title? }
|
727
|
-
assert exception.message.include?("private method")
|
728
|
-
assert topic.send(:title?)
|
729
|
-
end
|
730
|
-
|
731
|
-
def test_bulk_update_respects_access_control
|
732
|
-
privatize("title=(value)")
|
733
|
-
|
734
|
-
assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(:title => "Rants about pants") }
|
735
|
-
assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
|
736
|
-
end
|
737
|
-
|
738
|
-
def test_bulk_update_raise_unknown_attribute_error
|
739
|
-
error = assert_raises(ActiveRecord::UnknownAttributeError) {
|
740
|
-
Topic.new(hello: "world")
|
741
|
-
}
|
742
|
-
assert_instance_of Topic, error.record
|
743
|
-
assert_equal "hello", error.attribute
|
744
|
-
assert_equal "unknown attribute 'hello' for Topic.", error.message
|
745
|
-
end
|
746
|
-
|
747
|
-
# This test is related to a bug in Ruby 2.2.1.
|
748
|
-
# It can be safely removed once that bug is fixed.
|
749
|
-
#
|
750
|
-
# xref: https://bugs.ruby-lang.org/issues/10969
|
751
|
-
def test_bulk_does_not_raise_name_error
|
752
|
-
nope rescue nil # necessary to trigger the bug
|
753
|
-
assert_raises(ActiveRecord::UnknownAttributeError) {
|
754
|
-
Topic.new(hello: "world")
|
755
|
-
}
|
756
|
-
end
|
757
|
-
|
758
|
-
def test_methods_override_in_multi_level_subclass
|
759
|
-
klass = Class.new(Developer) do
|
760
|
-
def name
|
761
|
-
"dev:#{read_attribute(:name)}"
|
762
|
-
end
|
763
|
-
end
|
764
|
-
|
765
|
-
2.times { klass = Class.new klass }
|
766
|
-
dev = klass.new(name: 'arthurnn')
|
767
|
-
dev.save!
|
768
|
-
assert_equal 'dev:arthurnn', dev.reload.name
|
769
|
-
end
|
770
|
-
|
771
|
-
def test_global_methods_are_overwritten
|
772
|
-
klass = Class.new(ActiveRecord::Base) do
|
773
|
-
self.table_name = 'computers'
|
774
|
-
end
|
775
|
-
|
776
|
-
assert !klass.instance_method_already_implemented?(:system)
|
777
|
-
computer = klass.new
|
778
|
-
assert_nil computer.system
|
779
|
-
end
|
780
|
-
|
781
|
-
def test_global_methods_are_overwritte_when_subclassing
|
782
|
-
klass = Class.new(ActiveRecord::Base) { self.abstract_class = true }
|
783
|
-
|
784
|
-
subklass = Class.new(klass) do
|
785
|
-
self.table_name = 'computers'
|
786
|
-
end
|
787
|
-
|
788
|
-
assert !klass.instance_method_already_implemented?(:system)
|
789
|
-
assert !subklass.instance_method_already_implemented?(:system)
|
790
|
-
computer = subklass.new
|
791
|
-
assert_nil computer.system
|
792
|
-
end
|
793
|
-
|
794
|
-
def test_instance_method_should_be_defined_on_the_base_class
|
795
|
-
subklass = Class.new(Topic)
|
796
|
-
|
797
|
-
Topic.define_attribute_methods
|
798
|
-
|
799
|
-
instance = subklass.new
|
800
|
-
instance.id = 5
|
801
|
-
assert_equal 5, instance.id
|
802
|
-
assert subklass.method_defined?(:id), "subklass is missing id method"
|
803
|
-
|
804
|
-
Topic.undefine_attribute_methods
|
805
|
-
|
806
|
-
assert_equal 5, instance.id
|
807
|
-
assert subklass.method_defined?(:id), "subklass is missing id method"
|
808
|
-
end
|
809
|
-
|
810
|
-
def test_read_attribute_with_nil_should_not_asplode
|
811
|
-
assert_equal nil, Topic.new.read_attribute(nil)
|
812
|
-
end
|
813
|
-
|
814
|
-
# If B < A, and A defines an accessor for 'foo', we don't want to override
|
815
|
-
# that by defining a 'foo' method in the generated methods module for B.
|
816
|
-
# (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].)
|
817
|
-
def test_inherited_custom_accessors
|
818
|
-
klass = new_topic_like_ar_class do
|
819
|
-
self.abstract_class = true
|
820
|
-
def title; "omg"; end
|
821
|
-
def title=(val); self.author_name = val; end
|
822
|
-
end
|
823
|
-
subklass = Class.new(klass)
|
824
|
-
[klass, subklass].each(&:define_attribute_methods)
|
825
|
-
|
826
|
-
topic = subklass.find(1)
|
827
|
-
assert_equal "omg", topic.title
|
828
|
-
|
829
|
-
topic.title = "lol"
|
830
|
-
assert_equal "lol", topic.author_name
|
831
|
-
end
|
832
|
-
|
833
|
-
def test_inherited_custom_accessors_with_reserved_names
|
834
|
-
klass = Class.new(ActiveRecord::Base) do
|
835
|
-
self.table_name = 'computers'
|
836
|
-
self.abstract_class = true
|
837
|
-
def system; "omg"; end
|
838
|
-
def system=(val); self.developer = val; end
|
839
|
-
end
|
840
|
-
|
841
|
-
subklass = Class.new(klass)
|
842
|
-
[klass, subklass].each(&:define_attribute_methods)
|
843
|
-
|
844
|
-
computer = subklass.find(1)
|
845
|
-
assert_equal "omg", computer.system
|
846
|
-
|
847
|
-
computer.developer = 99
|
848
|
-
assert_equal 99, computer.developer
|
849
|
-
end
|
850
|
-
|
851
|
-
def test_on_the_fly_super_invokable_generated_attribute_methods_via_method_missing
|
852
|
-
klass = new_topic_like_ar_class do
|
853
|
-
def title
|
854
|
-
super + '!'
|
855
|
-
end
|
856
|
-
end
|
857
|
-
|
858
|
-
real_topic = topics(:first)
|
859
|
-
assert_equal real_topic.title + '!', klass.find(real_topic.id).title
|
860
|
-
end
|
861
|
-
|
862
|
-
def test_on_the_fly_super_invokable_generated_predicate_attribute_methods_via_method_missing
|
863
|
-
klass = new_topic_like_ar_class do
|
864
|
-
def title?
|
865
|
-
!super
|
866
|
-
end
|
867
|
-
end
|
868
|
-
|
869
|
-
real_topic = topics(:first)
|
870
|
-
assert_equal !real_topic.title?, klass.find(real_topic.id).title?
|
871
|
-
end
|
872
|
-
|
873
|
-
def test_calling_super_when_parent_does_not_define_method_raises_error
|
874
|
-
klass = new_topic_like_ar_class do
|
875
|
-
def some_method_that_is_not_on_super
|
876
|
-
super
|
877
|
-
end
|
878
|
-
end
|
879
|
-
|
880
|
-
assert_raise(NoMethodError) do
|
881
|
-
klass.new.some_method_that_is_not_on_super
|
882
|
-
end
|
883
|
-
end
|
884
|
-
|
885
|
-
def test_attribute_method?
|
886
|
-
assert @target.attribute_method?(:title)
|
887
|
-
assert @target.attribute_method?(:title=)
|
888
|
-
assert_not @target.attribute_method?(:wibble)
|
889
|
-
end
|
890
|
-
|
891
|
-
def test_attribute_method_returns_false_if_table_does_not_exist
|
892
|
-
@target.table_name = 'wibble'
|
893
|
-
assert_not @target.attribute_method?(:title)
|
894
|
-
end
|
895
|
-
|
896
|
-
def test_attribute_names_on_new_record
|
897
|
-
model = @target.new
|
898
|
-
|
899
|
-
assert_equal @target.column_names, model.attribute_names
|
900
|
-
end
|
901
|
-
|
902
|
-
def test_attribute_names_on_queried_record
|
903
|
-
model = @target.last!
|
904
|
-
|
905
|
-
assert_equal @target.column_names, model.attribute_names
|
906
|
-
end
|
907
|
-
|
908
|
-
def test_attribute_names_with_custom_select
|
909
|
-
model = @target.select('id').last!
|
910
|
-
|
911
|
-
assert_equal ['id'], model.attribute_names
|
912
|
-
# Sanity check, make sure other columns exist
|
913
|
-
assert_not_equal ['id'], @target.column_names
|
914
|
-
end
|
915
|
-
|
916
|
-
def test_came_from_user
|
917
|
-
model = @target.first
|
918
|
-
|
919
|
-
assert_not model.id_came_from_user?
|
920
|
-
model.id = "omg"
|
921
|
-
assert model.id_came_from_user?
|
922
|
-
end
|
923
|
-
|
924
|
-
private
|
925
|
-
|
926
|
-
def new_topic_like_ar_class(&block)
|
927
|
-
klass = Class.new(ActiveRecord::Base) do
|
928
|
-
self.table_name = 'topics'
|
929
|
-
class_eval(&block)
|
930
|
-
end
|
931
|
-
|
932
|
-
assert_empty klass.generated_attribute_methods.instance_methods(false)
|
933
|
-
klass
|
934
|
-
end
|
935
|
-
|
936
|
-
def cached_columns
|
937
|
-
Topic.columns.map(&:name)
|
938
|
-
end
|
939
|
-
|
940
|
-
def time_related_columns_on_topic
|
941
|
-
Topic.columns.select { |c| [:time, :date, :datetime, :timestamp].include?(c.type) }
|
942
|
-
end
|
943
|
-
|
944
|
-
def privatize(method_signature)
|
945
|
-
@target.class_eval(<<-private_method, __FILE__, __LINE__ + 1)
|
946
|
-
private
|
947
|
-
def #{method_signature}
|
948
|
-
"I'm private"
|
949
|
-
end
|
950
|
-
private_method
|
951
|
-
end
|
952
|
-
end
|
1
|
+
require "cases/helper"
|
2
|
+
require 'models/minimalistic'
|
3
|
+
require 'models/developer'
|
4
|
+
require 'models/computer'
|
5
|
+
require 'models/auto_id'
|
6
|
+
require 'models/boolean'
|
7
|
+
require 'models/computer'
|
8
|
+
require 'models/topic'
|
9
|
+
require 'models/company'
|
10
|
+
require 'models/category'
|
11
|
+
require 'models/reply'
|
12
|
+
require 'models/contact'
|
13
|
+
require 'models/keyboard'
|
14
|
+
|
15
|
+
class AttributeMethodsTest < ActiveRecord::TestCase
|
16
|
+
include InTimeZone
|
17
|
+
|
18
|
+
fixtures :topics, :developers, :companies, :computers
|
19
|
+
|
20
|
+
def setup
|
21
|
+
@old_matchers = ActiveRecord::Base.send(:attribute_method_matchers).dup
|
22
|
+
@target = Class.new(ActiveRecord::Base)
|
23
|
+
@target.table_name = 'topics'
|
24
|
+
end
|
25
|
+
|
26
|
+
teardown do
|
27
|
+
ActiveRecord::Base.send(:attribute_method_matchers).clear
|
28
|
+
ActiveRecord::Base.send(:attribute_method_matchers).concat(@old_matchers)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_attribute_for_inspect
|
32
|
+
t = topics(:first)
|
33
|
+
t.title = "The First Topic Now Has A Title With\nNewlines And More Than 50 Characters"
|
34
|
+
|
35
|
+
assert_equal %("#{t.written_on.to_s(:db)}"), t.attribute_for_inspect(:written_on)
|
36
|
+
assert_equal '"The First Topic Now Has A Title With\nNewlines And ..."', t.attribute_for_inspect(:title)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_attribute_present
|
40
|
+
t = Topic.new
|
41
|
+
t.title = "hello there!"
|
42
|
+
t.written_on = Time.now
|
43
|
+
t.author_name = ""
|
44
|
+
assert t.attribute_present?("title")
|
45
|
+
assert t.attribute_present?("written_on")
|
46
|
+
assert !t.attribute_present?("content")
|
47
|
+
assert !t.attribute_present?("author_name")
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_attribute_present_with_booleans
|
51
|
+
b1 = Boolean.new
|
52
|
+
b1.value = false
|
53
|
+
assert b1.attribute_present?(:value)
|
54
|
+
|
55
|
+
b2 = Boolean.new
|
56
|
+
b2.value = true
|
57
|
+
assert b2.attribute_present?(:value)
|
58
|
+
|
59
|
+
b3 = Boolean.new
|
60
|
+
assert !b3.attribute_present?(:value)
|
61
|
+
|
62
|
+
b4 = Boolean.new
|
63
|
+
b4.value = false
|
64
|
+
b4.save!
|
65
|
+
assert Boolean.find(b4.id).attribute_present?(:value)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_caching_nil_primary_key
|
69
|
+
klass = Class.new(Minimalistic)
|
70
|
+
klass.expects(:reset_primary_key).returns(nil).once
|
71
|
+
2.times { klass.primary_key }
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_attribute_keys_on_new_instance
|
75
|
+
t = Topic.new
|
76
|
+
assert_equal nil, t.title, "The topics table has a title column, so it should be nil"
|
77
|
+
assert_raise(NoMethodError) { t.title2 }
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_boolean_attributes
|
81
|
+
assert !Topic.find(1).approved?
|
82
|
+
assert Topic.find(2).approved?
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_set_attributes
|
86
|
+
topic = Topic.find(1)
|
87
|
+
topic.attributes = { "title" => "Budget", "author_name" => "Jason" }
|
88
|
+
topic.save
|
89
|
+
assert_equal("Budget", topic.title)
|
90
|
+
assert_equal("Jason", topic.author_name)
|
91
|
+
assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_set_attributes_without_hash
|
95
|
+
topic = Topic.new
|
96
|
+
assert_raise(ArgumentError) { topic.attributes = '' }
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_integers_as_nil
|
100
|
+
test = AutoId.create('value' => '')
|
101
|
+
assert_nil AutoId.find(test.id).value
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_set_attributes_with_block
|
105
|
+
topic = Topic.new do |t|
|
106
|
+
t.title = "Budget"
|
107
|
+
t.author_name = "Jason"
|
108
|
+
end
|
109
|
+
|
110
|
+
assert_equal("Budget", topic.title)
|
111
|
+
assert_equal("Jason", topic.author_name)
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_respond_to?
|
115
|
+
topic = Topic.find(1)
|
116
|
+
assert_respond_to topic, "title"
|
117
|
+
assert_respond_to topic, "title?"
|
118
|
+
assert_respond_to topic, "title="
|
119
|
+
assert_respond_to topic, :title
|
120
|
+
assert_respond_to topic, :title?
|
121
|
+
assert_respond_to topic, :title=
|
122
|
+
assert_respond_to topic, "author_name"
|
123
|
+
assert_respond_to topic, "attribute_names"
|
124
|
+
assert !topic.respond_to?("nothingness")
|
125
|
+
assert !topic.respond_to?(:nothingness)
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_respond_to_with_custom_primary_key
|
129
|
+
keyboard = Keyboard.create
|
130
|
+
assert_not_nil keyboard.key_number
|
131
|
+
assert_equal keyboard.key_number, keyboard.id
|
132
|
+
assert keyboard.respond_to?('key_number')
|
133
|
+
assert keyboard.respond_to?('id')
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_id_before_type_cast_with_custom_primary_key
|
137
|
+
keyboard = Keyboard.create
|
138
|
+
keyboard.key_number = '10'
|
139
|
+
assert_equal '10', keyboard.id_before_type_cast
|
140
|
+
assert_equal nil, keyboard.read_attribute_before_type_cast('id')
|
141
|
+
assert_equal '10', keyboard.read_attribute_before_type_cast('key_number')
|
142
|
+
assert_equal '10', keyboard.read_attribute_before_type_cast(:key_number)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Syck calls respond_to? before actually calling initialize
|
146
|
+
def test_respond_to_with_allocated_object
|
147
|
+
klass = Class.new(ActiveRecord::Base) do
|
148
|
+
self.table_name = 'topics'
|
149
|
+
end
|
150
|
+
|
151
|
+
topic = klass.allocate
|
152
|
+
assert !topic.respond_to?("nothingness")
|
153
|
+
assert !topic.respond_to?(:nothingness)
|
154
|
+
assert_respond_to topic, "title"
|
155
|
+
assert_respond_to topic, :title
|
156
|
+
end
|
157
|
+
|
158
|
+
# IRB inspects the return value of "MyModel.allocate".
|
159
|
+
def test_allocated_object_can_be_inspected
|
160
|
+
topic = Topic.allocate
|
161
|
+
assert_equal "#<Topic not initialized>", topic.inspect
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_array_content
|
165
|
+
topic = Topic.new
|
166
|
+
topic.content = %w( one two three )
|
167
|
+
topic.save
|
168
|
+
|
169
|
+
assert_equal(%w( one two three ), Topic.find(topic.id).content)
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_read_attributes_before_type_cast
|
173
|
+
category = Category.new({:name=>"Test category", :type => nil})
|
174
|
+
category_attrs = {"name"=>"Test category", "id" => nil, "type" => nil, "categorizations_count" => nil}
|
175
|
+
assert_equal category_attrs , category.attributes_before_type_cast
|
176
|
+
end
|
177
|
+
|
178
|
+
if current_adapter?(:MysqlAdapter)
|
179
|
+
def test_read_attributes_before_type_cast_on_boolean
|
180
|
+
bool = Boolean.create({ "value" => false })
|
181
|
+
if RUBY_PLATFORM =~ /java/
|
182
|
+
# JRuby will return the value before typecast as string
|
183
|
+
assert_equal "0", bool.reload.attributes_before_type_cast["value"]
|
184
|
+
else
|
185
|
+
assert_equal 0, bool.reload.attributes_before_type_cast["value"]
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_read_attributes_before_type_cast_on_datetime
|
191
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
192
|
+
record = @target.new
|
193
|
+
|
194
|
+
record.written_on = "345643456"
|
195
|
+
assert_equal "345643456", record.written_on_before_type_cast
|
196
|
+
assert_equal nil, record.written_on
|
197
|
+
|
198
|
+
record.written_on = "2009-10-11 12:13:14"
|
199
|
+
assert_equal "2009-10-11 12:13:14", record.written_on_before_type_cast
|
200
|
+
assert_equal Time.zone.parse("2009-10-11 12:13:14"), record.written_on
|
201
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_read_attributes_after_type_cast_on_datetime
|
206
|
+
tz = "Pacific Time (US & Canada)"
|
207
|
+
|
208
|
+
in_time_zone tz do
|
209
|
+
record = @target.new
|
210
|
+
|
211
|
+
date_string = "2011-03-24"
|
212
|
+
time = Time.zone.parse date_string
|
213
|
+
|
214
|
+
record.written_on = date_string
|
215
|
+
assert_equal date_string, record.written_on_before_type_cast
|
216
|
+
assert_equal time, record.written_on
|
217
|
+
assert_equal ActiveSupport::TimeZone[tz], record.written_on.time_zone
|
218
|
+
|
219
|
+
record.save
|
220
|
+
record.reload
|
221
|
+
|
222
|
+
assert_equal time, record.written_on
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_hash_content
|
227
|
+
topic = Topic.new
|
228
|
+
topic.content = { "one" => 1, "two" => 2 }
|
229
|
+
topic.save
|
230
|
+
|
231
|
+
assert_equal 2, Topic.find(topic.id).content["two"]
|
232
|
+
|
233
|
+
topic.content_will_change!
|
234
|
+
topic.content["three"] = 3
|
235
|
+
topic.save
|
236
|
+
|
237
|
+
assert_equal 3, Topic.find(topic.id).content["three"]
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_update_array_content
|
241
|
+
topic = Topic.new
|
242
|
+
topic.content = %w( one two three )
|
243
|
+
|
244
|
+
topic.content.push "four"
|
245
|
+
assert_equal(%w( one two three four ), topic.content)
|
246
|
+
|
247
|
+
topic.save
|
248
|
+
|
249
|
+
topic = Topic.find(topic.id)
|
250
|
+
topic.content << "five"
|
251
|
+
assert_equal(%w( one two three four five ), topic.content)
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_case_sensitive_attributes_hash
|
255
|
+
# DB2 is not case-sensitive
|
256
|
+
return true if current_adapter?(:DB2Adapter) || current_adapter?(:IBM_DBAdapter)
|
257
|
+
|
258
|
+
assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.first.attributes
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_attributes_without_primary_key
|
262
|
+
klass = Class.new(ActiveRecord::Base) do
|
263
|
+
self.table_name = 'developers_projects'
|
264
|
+
end
|
265
|
+
|
266
|
+
assert_equal klass.column_names, klass.new.attributes.keys
|
267
|
+
assert_not klass.new.has_attribute?('id')
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_hashes_not_mangled
|
271
|
+
new_topic = { :title => "New Topic" }
|
272
|
+
new_topic_values = { :title => "AnotherTopic" }
|
273
|
+
|
274
|
+
topic = Topic.new(new_topic)
|
275
|
+
assert_equal new_topic[:title], topic.title
|
276
|
+
|
277
|
+
topic.attributes= new_topic_values
|
278
|
+
assert_equal new_topic_values[:title], topic.title
|
279
|
+
end
|
280
|
+
|
281
|
+
def test_create_through_factory
|
282
|
+
topic = Topic.create("title" => "New Topic")
|
283
|
+
topicReloaded = Topic.find(topic.id)
|
284
|
+
assert_equal(topic, topicReloaded)
|
285
|
+
end
|
286
|
+
|
287
|
+
def test_write_attribute
|
288
|
+
topic = Topic.new
|
289
|
+
topic.send(:write_attribute, :title, "Still another topic")
|
290
|
+
assert_equal "Still another topic", topic.title
|
291
|
+
|
292
|
+
topic[:title] = "Still another topic: part 2"
|
293
|
+
assert_equal "Still another topic: part 2", topic.title
|
294
|
+
|
295
|
+
topic.send(:write_attribute, "title", "Still another topic: part 3")
|
296
|
+
assert_equal "Still another topic: part 3", topic.title
|
297
|
+
|
298
|
+
topic["title"] = "Still another topic: part 4"
|
299
|
+
assert_equal "Still another topic: part 4", topic.title
|
300
|
+
end
|
301
|
+
|
302
|
+
def test_read_attribute
|
303
|
+
topic = Topic.new
|
304
|
+
topic.title = "Don't change the topic"
|
305
|
+
assert_equal "Don't change the topic", topic.read_attribute("title")
|
306
|
+
assert_equal "Don't change the topic", topic["title"]
|
307
|
+
|
308
|
+
assert_equal "Don't change the topic", topic.read_attribute(:title)
|
309
|
+
assert_equal "Don't change the topic", topic[:title]
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_read_attribute_raises_missing_attribute_error_when_not_exists
|
313
|
+
computer = Computer.select('id').first
|
314
|
+
assert_raises(ActiveModel::MissingAttributeError) { computer[:developer] }
|
315
|
+
assert_raises(ActiveModel::MissingAttributeError) { computer[:extendedWarranty] }
|
316
|
+
assert_raises(ActiveModel::MissingAttributeError) { computer[:no_column_exists] = 'Hello!' }
|
317
|
+
assert_nothing_raised { computer[:developer] = 'Hello!' }
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_read_attribute_when_false
|
321
|
+
topic = topics(:first)
|
322
|
+
topic.approved = false
|
323
|
+
assert !topic.approved?, "approved should be false"
|
324
|
+
topic.approved = "false"
|
325
|
+
assert !topic.approved?, "approved should be false"
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_read_attribute_when_true
|
329
|
+
topic = topics(:first)
|
330
|
+
topic.approved = true
|
331
|
+
assert topic.approved?, "approved should be true"
|
332
|
+
topic.approved = "true"
|
333
|
+
assert topic.approved?, "approved should be true"
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_read_write_boolean_attribute
|
337
|
+
topic = Topic.new
|
338
|
+
topic.approved = "false"
|
339
|
+
assert !topic.approved?, "approved should be false"
|
340
|
+
|
341
|
+
topic.approved = "false"
|
342
|
+
assert !topic.approved?, "approved should be false"
|
343
|
+
|
344
|
+
topic.approved = "true"
|
345
|
+
assert topic.approved?, "approved should be true"
|
346
|
+
|
347
|
+
topic.approved = "true"
|
348
|
+
assert topic.approved?, "approved should be true"
|
349
|
+
end
|
350
|
+
|
351
|
+
def test_overridden_write_attribute
|
352
|
+
topic = Topic.new
|
353
|
+
def topic.write_attribute(attr_name, value)
|
354
|
+
super(attr_name, value.downcase)
|
355
|
+
end
|
356
|
+
|
357
|
+
topic.send(:write_attribute, :title, "Yet another topic")
|
358
|
+
assert_equal "yet another topic", topic.title
|
359
|
+
|
360
|
+
topic[:title] = "Yet another topic: part 2"
|
361
|
+
assert_equal "yet another topic: part 2", topic.title
|
362
|
+
|
363
|
+
topic.send(:write_attribute, "title", "Yet another topic: part 3")
|
364
|
+
assert_equal "yet another topic: part 3", topic.title
|
365
|
+
|
366
|
+
topic["title"] = "Yet another topic: part 4"
|
367
|
+
assert_equal "yet another topic: part 4", topic.title
|
368
|
+
end
|
369
|
+
|
370
|
+
def test_overridden_read_attribute
|
371
|
+
topic = Topic.new
|
372
|
+
topic.title = "Stop changing the topic"
|
373
|
+
def topic.read_attribute(attr_name)
|
374
|
+
super(attr_name).upcase
|
375
|
+
end
|
376
|
+
|
377
|
+
assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute("title")
|
378
|
+
assert_equal "STOP CHANGING THE TOPIC", topic["title"]
|
379
|
+
|
380
|
+
assert_equal "STOP CHANGING THE TOPIC", topic.read_attribute(:title)
|
381
|
+
assert_equal "STOP CHANGING THE TOPIC", topic[:title]
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_read_overridden_attribute
|
385
|
+
topic = Topic.new(:title => 'a')
|
386
|
+
def topic.title() 'b' end
|
387
|
+
assert_equal 'a', topic[:title]
|
388
|
+
end
|
389
|
+
|
390
|
+
def test_query_attribute_string
|
391
|
+
[nil, "", " "].each do |value|
|
392
|
+
assert_equal false, Topic.new(:author_name => value).author_name?
|
393
|
+
end
|
394
|
+
|
395
|
+
assert_equal true, Topic.new(:author_name => "Name").author_name?
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_query_attribute_number
|
399
|
+
[nil, 0, "0"].each do |value|
|
400
|
+
assert_equal false, Developer.new(:salary => value).salary?
|
401
|
+
end
|
402
|
+
|
403
|
+
assert_equal true, Developer.new(:salary => 1).salary?
|
404
|
+
assert_equal true, Developer.new(:salary => "1").salary?
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_query_attribute_boolean
|
408
|
+
[nil, "", false, "false", "f", 0].each do |value|
|
409
|
+
assert_equal false, Topic.new(:approved => value).approved?
|
410
|
+
end
|
411
|
+
|
412
|
+
[true, "true", "1", 1].each do |value|
|
413
|
+
assert_equal true, Topic.new(:approved => value).approved?
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def test_query_attribute_with_custom_fields
|
418
|
+
object = Company.find_by_sql(<<-SQL).first
|
419
|
+
SELECT c1.*, c2.type as string_value, c2.rating as int_value
|
420
|
+
FROM companies c1, companies c2
|
421
|
+
WHERE c1.firm_id = c2.id
|
422
|
+
AND c1.id = 2
|
423
|
+
SQL
|
424
|
+
|
425
|
+
assert_equal "Firm", object.string_value
|
426
|
+
assert object.string_value?
|
427
|
+
|
428
|
+
object.string_value = " "
|
429
|
+
assert !object.string_value?
|
430
|
+
|
431
|
+
assert_equal 1, object.int_value.to_i
|
432
|
+
assert object.int_value?
|
433
|
+
|
434
|
+
object.int_value = "0"
|
435
|
+
assert !object.int_value?
|
436
|
+
end
|
437
|
+
|
438
|
+
def test_non_attribute_access_and_assignment
|
439
|
+
topic = Topic.new
|
440
|
+
assert !topic.respond_to?("mumbo")
|
441
|
+
assert_raise(NoMethodError) { topic.mumbo }
|
442
|
+
assert_raise(NoMethodError) { topic.mumbo = 5 }
|
443
|
+
end
|
444
|
+
|
445
|
+
def test_undeclared_attribute_method_does_not_affect_respond_to_and_method_missing
|
446
|
+
topic = @target.new(:title => 'Budget')
|
447
|
+
assert topic.respond_to?('title')
|
448
|
+
assert_equal 'Budget', topic.title
|
449
|
+
assert !topic.respond_to?('title_hello_world')
|
450
|
+
assert_raise(NoMethodError) { topic.title_hello_world }
|
451
|
+
end
|
452
|
+
|
453
|
+
def test_declared_prefixed_attribute_method_affects_respond_to_and_method_missing
|
454
|
+
topic = @target.new(:title => 'Budget')
|
455
|
+
%w(default_ title_).each do |prefix|
|
456
|
+
@target.class_eval "def #{prefix}attribute(*args) args end"
|
457
|
+
@target.attribute_method_prefix prefix
|
458
|
+
|
459
|
+
meth = "#{prefix}title"
|
460
|
+
assert topic.respond_to?(meth)
|
461
|
+
assert_equal ['title'], topic.send(meth)
|
462
|
+
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
463
|
+
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
def test_declared_suffixed_attribute_method_affects_respond_to_and_method_missing
|
468
|
+
%w(_default _title_default _it! _candidate= able?).each do |suffix|
|
469
|
+
@target.class_eval "def attribute#{suffix}(*args) args end"
|
470
|
+
@target.attribute_method_suffix suffix
|
471
|
+
topic = @target.new(:title => 'Budget')
|
472
|
+
|
473
|
+
meth = "title#{suffix}"
|
474
|
+
assert topic.respond_to?(meth)
|
475
|
+
assert_equal ['title'], topic.send(meth)
|
476
|
+
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
477
|
+
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
def test_declared_affixed_attribute_method_affects_respond_to_and_method_missing
|
482
|
+
[['mark_', '_for_update'], ['reset_', '!'], ['default_', '_value?']].each do |prefix, suffix|
|
483
|
+
@target.class_eval "def #{prefix}attribute#{suffix}(*args) args end"
|
484
|
+
@target.attribute_method_affix({ :prefix => prefix, :suffix => suffix })
|
485
|
+
topic = @target.new(:title => 'Budget')
|
486
|
+
|
487
|
+
meth = "#{prefix}title#{suffix}"
|
488
|
+
assert topic.respond_to?(meth)
|
489
|
+
assert_equal ['title'], topic.send(meth)
|
490
|
+
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
491
|
+
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
def test_should_unserialize_attributes_for_frozen_records
|
496
|
+
myobj = {:value1 => :value2}
|
497
|
+
topic = Topic.create("content" => myobj)
|
498
|
+
topic.freeze
|
499
|
+
assert_equal myobj, topic.content
|
500
|
+
end
|
501
|
+
|
502
|
+
def test_typecast_attribute_from_select_to_false
|
503
|
+
Topic.create(:title => 'Budget')
|
504
|
+
# Oracle does not support boolean expressions in SELECT
|
505
|
+
if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
|
506
|
+
topic = Topic.all.merge!(:select => "topics.*, 0 as is_test").first
|
507
|
+
else
|
508
|
+
topic = Topic.all.merge!(:select => "topics.*, 1=2 as is_test").first
|
509
|
+
end
|
510
|
+
assert !topic.is_test?
|
511
|
+
end
|
512
|
+
|
513
|
+
def test_typecast_attribute_from_select_to_true
|
514
|
+
Topic.create(:title => 'Budget')
|
515
|
+
# Oracle does not support boolean expressions in SELECT
|
516
|
+
if current_adapter?(:OracleAdapter) || current_adapter?(:IBM_DBAdapter)
|
517
|
+
topic = Topic.all.merge!(:select => "topics.*, 1 as is_test").first
|
518
|
+
else
|
519
|
+
topic = Topic.all.merge!(:select => "topics.*, 2=2 as is_test").first
|
520
|
+
end
|
521
|
+
assert topic.is_test?
|
522
|
+
end
|
523
|
+
|
524
|
+
def test_raises_dangerous_attribute_error_when_defining_activerecord_method_in_model
|
525
|
+
%w(save create_or_update).each do |method|
|
526
|
+
klass = Class.new ActiveRecord::Base
|
527
|
+
klass.class_eval "def #{method}() 'defined #{method}' end"
|
528
|
+
assert_raise ActiveRecord::DangerousAttributeError do
|
529
|
+
klass.instance_method_already_implemented?(method)
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
def test_deprecated_cache_attributes
|
535
|
+
assert_deprecated do
|
536
|
+
Topic.cache_attributes :replies_count
|
537
|
+
end
|
538
|
+
|
539
|
+
assert_deprecated do
|
540
|
+
Topic.cached_attributes
|
541
|
+
end
|
542
|
+
|
543
|
+
assert_deprecated do
|
544
|
+
Topic.cache_attribute? :replies_count
|
545
|
+
end
|
546
|
+
end
|
547
|
+
|
548
|
+
def test_converted_values_are_returned_after_assignment
|
549
|
+
developer = Developer.new(name: 1337, salary: "50000")
|
550
|
+
|
551
|
+
assert_equal "50000", developer.salary_before_type_cast
|
552
|
+
assert_equal 1337, developer.name_before_type_cast
|
553
|
+
|
554
|
+
assert_equal 50000, developer.salary
|
555
|
+
assert_equal "1337", developer.name
|
556
|
+
|
557
|
+
developer.save!
|
558
|
+
|
559
|
+
assert_equal "50000", developer.salary_before_type_cast
|
560
|
+
assert_equal 1337, developer.name_before_type_cast
|
561
|
+
|
562
|
+
assert_equal 50000, developer.salary
|
563
|
+
assert_equal "1337", developer.name
|
564
|
+
end
|
565
|
+
|
566
|
+
def test_write_nil_to_time_attributes
|
567
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
568
|
+
record = @target.new
|
569
|
+
record.written_on = nil
|
570
|
+
assert_nil record.written_on
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
def test_write_time_to_date_attributes
|
575
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
576
|
+
record = @target.new
|
577
|
+
record.last_read = Time.utc(2010, 1, 1, 10)
|
578
|
+
assert_equal Date.civil(2010, 1, 1), record.last_read
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
def test_time_attributes_are_retrieved_in_current_time_zone
|
583
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
584
|
+
utc_time = Time.utc(2008, 1, 1)
|
585
|
+
record = @target.new
|
586
|
+
record[:written_on] = utc_time
|
587
|
+
assert_equal utc_time, record.written_on # record.written on is equal to (i.e., simultaneous with) utc_time
|
588
|
+
assert_kind_of ActiveSupport::TimeWithZone, record.written_on # but is a TimeWithZone
|
589
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone # and is in the current Time.zone
|
590
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time # and represents time values adjusted accordingly
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
def test_setting_time_zone_aware_attribute_to_utc
|
595
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
596
|
+
utc_time = Time.utc(2008, 1, 1)
|
597
|
+
record = @target.new
|
598
|
+
record.written_on = utc_time
|
599
|
+
assert_equal utc_time, record.written_on
|
600
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
601
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
def test_setting_time_zone_aware_attribute_in_other_time_zone
|
606
|
+
utc_time = Time.utc(2008, 1, 1)
|
607
|
+
cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
|
608
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
609
|
+
record = @target.new
|
610
|
+
record.written_on = cst_time
|
611
|
+
assert_equal utc_time, record.written_on
|
612
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
613
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
def test_setting_time_zone_aware_read_attribute
|
618
|
+
utc_time = Time.utc(2008, 1, 1)
|
619
|
+
cst_time = utc_time.in_time_zone("Central Time (US & Canada)")
|
620
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
621
|
+
record = @target.create(:written_on => cst_time).reload
|
622
|
+
assert_equal utc_time, record[:written_on]
|
623
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record[:written_on].time_zone
|
624
|
+
assert_equal Time.utc(2007, 12, 31, 16), record[:written_on].time
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
def test_setting_time_zone_aware_attribute_with_string
|
629
|
+
utc_time = Time.utc(2008, 1, 1)
|
630
|
+
(-11..13).each do |timezone_offset|
|
631
|
+
time_string = utc_time.in_time_zone(timezone_offset).to_s
|
632
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
633
|
+
record = @target.new
|
634
|
+
record.written_on = time_string
|
635
|
+
assert_equal Time.zone.parse(time_string), record.written_on
|
636
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
637
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
638
|
+
end
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
def test_time_zone_aware_attribute_saved
|
643
|
+
in_time_zone 1 do
|
644
|
+
record = @target.create(:written_on => '2012-02-20 10:00')
|
645
|
+
|
646
|
+
record.written_on = '2012-02-20 09:00'
|
647
|
+
record.save
|
648
|
+
assert_equal Time.zone.local(2012, 02, 20, 9), record.reload.written_on
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
def test_setting_time_zone_aware_attribute_to_blank_string_returns_nil
|
653
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
654
|
+
record = @target.new
|
655
|
+
record.written_on = ' '
|
656
|
+
assert_nil record.written_on
|
657
|
+
assert_nil record[:written_on]
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
def test_setting_time_zone_aware_attribute_interprets_time_zone_unaware_string_in_time_zone
|
662
|
+
time_string = 'Tue Jan 01 00:00:00 2008'
|
663
|
+
(-11..13).each do |timezone_offset|
|
664
|
+
in_time_zone timezone_offset do
|
665
|
+
record = @target.new
|
666
|
+
record.written_on = time_string
|
667
|
+
assert_equal Time.zone.parse(time_string), record.written_on
|
668
|
+
assert_equal ActiveSupport::TimeZone[timezone_offset], record.written_on.time_zone
|
669
|
+
assert_equal Time.utc(2008, 1, 1), record.written_on.time
|
670
|
+
end
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
674
|
+
def test_setting_time_zone_aware_attribute_in_current_time_zone
|
675
|
+
utc_time = Time.utc(2008, 1, 1)
|
676
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
677
|
+
record = @target.new
|
678
|
+
record.written_on = utc_time.in_time_zone
|
679
|
+
assert_equal utc_time, record.written_on
|
680
|
+
assert_equal ActiveSupport::TimeZone["Pacific Time (US & Canada)"], record.written_on.time_zone
|
681
|
+
assert_equal Time.utc(2007, 12, 31, 16), record.written_on.time
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
def test_yaml_dumping_record_with_time_zone_aware_attribute
|
686
|
+
in_time_zone "Pacific Time (US & Canada)" do
|
687
|
+
record = Topic.new(id: 1)
|
688
|
+
record.written_on = "Jan 01 00:00:00 2014"
|
689
|
+
assert_equal record, YAML.load(YAML.dump(record))
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
def test_setting_time_zone_conversion_for_attributes_should_write_value_on_class_variable
|
694
|
+
Topic.skip_time_zone_conversion_for_attributes = [:field_a]
|
695
|
+
Minimalistic.skip_time_zone_conversion_for_attributes = [:field_b]
|
696
|
+
|
697
|
+
assert_equal [:field_a], Topic.skip_time_zone_conversion_for_attributes
|
698
|
+
assert_equal [:field_b], Minimalistic.skip_time_zone_conversion_for_attributes
|
699
|
+
end
|
700
|
+
|
701
|
+
def test_read_attributes_respect_access_control
|
702
|
+
privatize("title")
|
703
|
+
|
704
|
+
topic = @target.new(:title => "The pros and cons of programming naked.")
|
705
|
+
assert !topic.respond_to?(:title)
|
706
|
+
exception = assert_raise(NoMethodError) { topic.title }
|
707
|
+
assert exception.message.include?("private method")
|
708
|
+
assert_equal "I'm private", topic.send(:title)
|
709
|
+
end
|
710
|
+
|
711
|
+
def test_write_attributes_respect_access_control
|
712
|
+
privatize("title=(value)")
|
713
|
+
|
714
|
+
topic = @target.new
|
715
|
+
assert !topic.respond_to?(:title=)
|
716
|
+
exception = assert_raise(NoMethodError) { topic.title = "Pants"}
|
717
|
+
assert exception.message.include?("private method")
|
718
|
+
topic.send(:title=, "Very large pants")
|
719
|
+
end
|
720
|
+
|
721
|
+
def test_question_attributes_respect_access_control
|
722
|
+
privatize("title?")
|
723
|
+
|
724
|
+
topic = @target.new(:title => "Isaac Newton's pants")
|
725
|
+
assert !topic.respond_to?(:title?)
|
726
|
+
exception = assert_raise(NoMethodError) { topic.title? }
|
727
|
+
assert exception.message.include?("private method")
|
728
|
+
assert topic.send(:title?)
|
729
|
+
end
|
730
|
+
|
731
|
+
def test_bulk_update_respects_access_control
|
732
|
+
privatize("title=(value)")
|
733
|
+
|
734
|
+
assert_raise(ActiveRecord::UnknownAttributeError) { @target.new(:title => "Rants about pants") }
|
735
|
+
assert_raise(ActiveRecord::UnknownAttributeError) { @target.new.attributes = { :title => "Ants in pants" } }
|
736
|
+
end
|
737
|
+
|
738
|
+
def test_bulk_update_raise_unknown_attribute_error
|
739
|
+
error = assert_raises(ActiveRecord::UnknownAttributeError) {
|
740
|
+
Topic.new(hello: "world")
|
741
|
+
}
|
742
|
+
assert_instance_of Topic, error.record
|
743
|
+
assert_equal "hello", error.attribute
|
744
|
+
assert_equal "unknown attribute 'hello' for Topic.", error.message
|
745
|
+
end
|
746
|
+
|
747
|
+
# This test is related to a bug in Ruby 2.2.1.
|
748
|
+
# It can be safely removed once that bug is fixed.
|
749
|
+
#
|
750
|
+
# xref: https://bugs.ruby-lang.org/issues/10969
|
751
|
+
def test_bulk_does_not_raise_name_error
|
752
|
+
nope rescue nil # necessary to trigger the bug
|
753
|
+
assert_raises(ActiveRecord::UnknownAttributeError) {
|
754
|
+
Topic.new(hello: "world")
|
755
|
+
}
|
756
|
+
end
|
757
|
+
|
758
|
+
def test_methods_override_in_multi_level_subclass
|
759
|
+
klass = Class.new(Developer) do
|
760
|
+
def name
|
761
|
+
"dev:#{read_attribute(:name)}"
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
765
|
+
2.times { klass = Class.new klass }
|
766
|
+
dev = klass.new(name: 'arthurnn')
|
767
|
+
dev.save!
|
768
|
+
assert_equal 'dev:arthurnn', dev.reload.name
|
769
|
+
end
|
770
|
+
|
771
|
+
def test_global_methods_are_overwritten
|
772
|
+
klass = Class.new(ActiveRecord::Base) do
|
773
|
+
self.table_name = 'computers'
|
774
|
+
end
|
775
|
+
|
776
|
+
assert !klass.instance_method_already_implemented?(:system)
|
777
|
+
computer = klass.new
|
778
|
+
assert_nil computer.system
|
779
|
+
end
|
780
|
+
|
781
|
+
def test_global_methods_are_overwritte_when_subclassing
|
782
|
+
klass = Class.new(ActiveRecord::Base) { self.abstract_class = true }
|
783
|
+
|
784
|
+
subklass = Class.new(klass) do
|
785
|
+
self.table_name = 'computers'
|
786
|
+
end
|
787
|
+
|
788
|
+
assert !klass.instance_method_already_implemented?(:system)
|
789
|
+
assert !subklass.instance_method_already_implemented?(:system)
|
790
|
+
computer = subklass.new
|
791
|
+
assert_nil computer.system
|
792
|
+
end
|
793
|
+
|
794
|
+
def test_instance_method_should_be_defined_on_the_base_class
|
795
|
+
subklass = Class.new(Topic)
|
796
|
+
|
797
|
+
Topic.define_attribute_methods
|
798
|
+
|
799
|
+
instance = subklass.new
|
800
|
+
instance.id = 5
|
801
|
+
assert_equal 5, instance.id
|
802
|
+
assert subklass.method_defined?(:id), "subklass is missing id method"
|
803
|
+
|
804
|
+
Topic.undefine_attribute_methods
|
805
|
+
|
806
|
+
assert_equal 5, instance.id
|
807
|
+
assert subklass.method_defined?(:id), "subklass is missing id method"
|
808
|
+
end
|
809
|
+
|
810
|
+
def test_read_attribute_with_nil_should_not_asplode
|
811
|
+
assert_equal nil, Topic.new.read_attribute(nil)
|
812
|
+
end
|
813
|
+
|
814
|
+
# If B < A, and A defines an accessor for 'foo', we don't want to override
|
815
|
+
# that by defining a 'foo' method in the generated methods module for B.
|
816
|
+
# (That module will be inserted between the two, e.g. [B, <GeneratedAttributes>, A].)
|
817
|
+
def test_inherited_custom_accessors
|
818
|
+
klass = new_topic_like_ar_class do
|
819
|
+
self.abstract_class = true
|
820
|
+
def title; "omg"; end
|
821
|
+
def title=(val); self.author_name = val; end
|
822
|
+
end
|
823
|
+
subklass = Class.new(klass)
|
824
|
+
[klass, subklass].each(&:define_attribute_methods)
|
825
|
+
|
826
|
+
topic = subklass.find(1)
|
827
|
+
assert_equal "omg", topic.title
|
828
|
+
|
829
|
+
topic.title = "lol"
|
830
|
+
assert_equal "lol", topic.author_name
|
831
|
+
end
|
832
|
+
|
833
|
+
def test_inherited_custom_accessors_with_reserved_names
|
834
|
+
klass = Class.new(ActiveRecord::Base) do
|
835
|
+
self.table_name = 'computers'
|
836
|
+
self.abstract_class = true
|
837
|
+
def system; "omg"; end
|
838
|
+
def system=(val); self.developer = val; end
|
839
|
+
end
|
840
|
+
|
841
|
+
subklass = Class.new(klass)
|
842
|
+
[klass, subklass].each(&:define_attribute_methods)
|
843
|
+
|
844
|
+
computer = subklass.find(1)
|
845
|
+
assert_equal "omg", computer.system
|
846
|
+
|
847
|
+
computer.developer = 99
|
848
|
+
assert_equal 99, computer.developer
|
849
|
+
end
|
850
|
+
|
851
|
+
def test_on_the_fly_super_invokable_generated_attribute_methods_via_method_missing
|
852
|
+
klass = new_topic_like_ar_class do
|
853
|
+
def title
|
854
|
+
super + '!'
|
855
|
+
end
|
856
|
+
end
|
857
|
+
|
858
|
+
real_topic = topics(:first)
|
859
|
+
assert_equal real_topic.title + '!', klass.find(real_topic.id).title
|
860
|
+
end
|
861
|
+
|
862
|
+
def test_on_the_fly_super_invokable_generated_predicate_attribute_methods_via_method_missing
|
863
|
+
klass = new_topic_like_ar_class do
|
864
|
+
def title?
|
865
|
+
!super
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
real_topic = topics(:first)
|
870
|
+
assert_equal !real_topic.title?, klass.find(real_topic.id).title?
|
871
|
+
end
|
872
|
+
|
873
|
+
def test_calling_super_when_parent_does_not_define_method_raises_error
|
874
|
+
klass = new_topic_like_ar_class do
|
875
|
+
def some_method_that_is_not_on_super
|
876
|
+
super
|
877
|
+
end
|
878
|
+
end
|
879
|
+
|
880
|
+
assert_raise(NoMethodError) do
|
881
|
+
klass.new.some_method_that_is_not_on_super
|
882
|
+
end
|
883
|
+
end
|
884
|
+
|
885
|
+
def test_attribute_method?
|
886
|
+
assert @target.attribute_method?(:title)
|
887
|
+
assert @target.attribute_method?(:title=)
|
888
|
+
assert_not @target.attribute_method?(:wibble)
|
889
|
+
end
|
890
|
+
|
891
|
+
def test_attribute_method_returns_false_if_table_does_not_exist
|
892
|
+
@target.table_name = 'wibble'
|
893
|
+
assert_not @target.attribute_method?(:title)
|
894
|
+
end
|
895
|
+
|
896
|
+
def test_attribute_names_on_new_record
|
897
|
+
model = @target.new
|
898
|
+
|
899
|
+
assert_equal @target.column_names, model.attribute_names
|
900
|
+
end
|
901
|
+
|
902
|
+
def test_attribute_names_on_queried_record
|
903
|
+
model = @target.last!
|
904
|
+
|
905
|
+
assert_equal @target.column_names, model.attribute_names
|
906
|
+
end
|
907
|
+
|
908
|
+
def test_attribute_names_with_custom_select
|
909
|
+
model = @target.select('id').last!
|
910
|
+
|
911
|
+
assert_equal ['id'], model.attribute_names
|
912
|
+
# Sanity check, make sure other columns exist
|
913
|
+
assert_not_equal ['id'], @target.column_names
|
914
|
+
end
|
915
|
+
|
916
|
+
def test_came_from_user
|
917
|
+
model = @target.first
|
918
|
+
|
919
|
+
assert_not model.id_came_from_user?
|
920
|
+
model.id = "omg"
|
921
|
+
assert model.id_came_from_user?
|
922
|
+
end
|
923
|
+
|
924
|
+
private
|
925
|
+
|
926
|
+
def new_topic_like_ar_class(&block)
|
927
|
+
klass = Class.new(ActiveRecord::Base) do
|
928
|
+
self.table_name = 'topics'
|
929
|
+
class_eval(&block)
|
930
|
+
end
|
931
|
+
|
932
|
+
assert_empty klass.generated_attribute_methods.instance_methods(false)
|
933
|
+
klass
|
934
|
+
end
|
935
|
+
|
936
|
+
def cached_columns
|
937
|
+
Topic.columns.map(&:name)
|
938
|
+
end
|
939
|
+
|
940
|
+
def time_related_columns_on_topic
|
941
|
+
Topic.columns.select { |c| [:time, :date, :datetime, :timestamp].include?(c.type) }
|
942
|
+
end
|
943
|
+
|
944
|
+
def privatize(method_signature)
|
945
|
+
@target.class_eval(<<-private_method, __FILE__, __LINE__ + 1)
|
946
|
+
private
|
947
|
+
def #{method_signature}
|
948
|
+
"I'm private"
|
949
|
+
end
|
950
|
+
private_method
|
951
|
+
end
|
952
|
+
end
|