From eb23754ebbfbf2d465cc0f900720704fb3703633 Mon Sep 17 00:00:00 2001 From: Piotr Sarnacki Date: Wed, 17 Apr 2013 00:06:11 +0200 Subject: Move template tests from actionpack to actionview --- actionview/test/abstract_unit.rb | 382 +++ actionview/test/active_record_unit.rb | 91 + .../test/activerecord/controller_runtime_test.rb | 95 + .../activerecord/form_helper_activerecord_test.rb | 91 + .../test/activerecord/polymorphic_routes_test.rb | 546 ++++ ...nder_partial_with_record_identification_test.rb | 210 ++ .../test/fixtures/_top_level_partial.html.erb | 1 + .../test/fixtures/_top_level_partial_only.erb | 1 + .../test/fixtures/alternate_helpers/foo_helper.rb | 3 + .../fixtures/bad_customers/_bad_customer.html.erb | 1 + actionview/test/fixtures/blog_public/.gitignore | 1 + actionview/test/fixtures/blog_public/blog.html | 1 + actionview/test/fixtures/blog_public/index.html | 1 + .../test/fixtures/blog_public/subdir/index.html | 1 + .../test/fixtures/comments/empty.de.html.erb | 1 + .../test/fixtures/comments/empty.html.builder | 1 + actionview/test/fixtures/comments/empty.html.erb | 1 + actionview/test/fixtures/comments/empty.xml.erb | 1 + actionview/test/fixtures/companies.yml | 24 + actionview/test/fixtures/company.rb | 9 + .../test/fixtures/custom_pattern/another.html.erb | 1 + .../test/fixtures/custom_pattern/html/another.erb | 1 + .../test/fixtures/custom_pattern/html/path.erb | 1 + .../test/fixtures/customers/_customer.html.erb | 1 + actionview/test/fixtures/db_definitions/sqlite.sql | 49 + actionview/test/fixtures/developer.rb | 10 + actionview/test/fixtures/developers.yml | 21 + actionview/test/fixtures/developers/_developer.erb | 1 + actionview/test/fixtures/developers_projects.yml | 13 + .../fixtures/digestor/comments/_comment.html.erb | 1 + .../fixtures/digestor/comments/_comments.html.erb | 1 + .../test/fixtures/digestor/events/_event.html.erb | 0 .../fixtures/digestor/level/below/_header.html.erb | 0 .../fixtures/digestor/level/below/index.html.erb | 1 + .../test/fixtures/digestor/messages/_form.html.erb | 0 .../fixtures/digestor/messages/_header.html.erb | 0 .../fixtures/digestor/messages/_message.html.erb | 1 + .../digestor/messages/actions/_move.html.erb | 0 .../test/fixtures/digestor/messages/edit.html.erb | 5 + .../test/fixtures/digestor/messages/index.html.erb | 2 + .../test/fixtures/digestor/messages/show.html.erb | 13 + .../filter_test/implicit_actions/edit.html.erb | 1 + .../filter_test/implicit_actions/show.html.erb | 1 + actionview/test/fixtures/fun/games/_form.erb | 1 + actionview/test/fixtures/fun/games/_game.erb | 1 + actionview/test/fixtures/fun/games/hello_world.erb | 1 + .../test/fixtures/fun/serious/games/_game.erb | 1 + .../test/fixtures/functional_caching/_partial.erb | 3 + .../formatted_fragment_cached.html.erb | 3 + .../formatted_fragment_cached.xml.builder | 5 + .../functional_caching/fragment_cached.html.erb | 3 + .../fragment_cached_without_digest.html.erb | 3 + .../html_fragment_cached_with_partial.html.erb | 1 + .../inline_fragment_cached.html.erb | 2 + actionview/test/fixtures/games/_game.erb | 1 + .../good_customers/_good_customer.html.erb | 1 + .../happy_path/render_action/hello_world.erb | 1 + actionview/test/fixtures/hello.html | 1 + actionview/test/fixtures/helpers/abc_helper.rb | 5 + .../test/fixtures/helpers/fun/games_helper.rb | 5 + actionview/test/fixtures/helpers/fun/pdf_helper.rb | 5 + .../test/fixtures/helpers/helpery_test_helper.rb | 5 + actionview/test/fixtures/helpers/just_me_helper.rb | 3 + actionview/test/fixtures/helpers/me_too_helper.rb | 3 + .../test/fixtures/helpers1_pack/pack1_helper.rb | 5 + .../test/fixtures/helpers2_pack/pack2_helper.rb | 5 + .../test/fixtures/layout_tests/alt/hello.erb | 1 + .../test/fixtures/layout_tests/alt/layouts/alt.erb | 0 .../layouts/controller_name_space/nested.erb | 1 + .../test/fixtures/layout_tests/layouts/item.erb | 1 + .../fixtures/layout_tests/layouts/layout_test.erb | 1 + .../layouts/multiple_extensions.html.erb | 1 + .../test/fixtures/layout_tests/layouts/symlinked | 1 + .../layouts/third_party_template_library.mab | 1 + .../test/fixtures/layout_tests/views/goodbye.erb | 1 + .../test/fixtures/layout_tests/views/hello.erb | 1 + actionview/test/fixtures/layouts/_column.html.erb | 2 + actionview/test/fixtures/layouts/_customers.erb | 1 + .../test/fixtures/layouts/_partial_and_yield.erb | 2 + actionview/test/fixtures/layouts/_yield_only.erb | 1 + .../test/fixtures/layouts/_yield_with_params.erb | 1 + .../test/fixtures/layouts/block_with_layout.erb | 3 + actionview/test/fixtures/layouts/builder.builder | 3 + .../test/fixtures/layouts/partial_with_layout.erb | 3 + actionview/test/fixtures/layouts/standard.html.erb | 1 + actionview/test/fixtures/layouts/streaming.erb | 4 + .../test/fixtures/layouts/talk_from_action.erb | 2 + .../fixtures/layouts/with_html_partial.html.erb | 1 + actionview/test/fixtures/layouts/xhr.html.erb | 2 + actionview/test/fixtures/layouts/yield.erb | 2 + .../layouts/yield_with_render_inline_inside.erb | 2 + .../layouts/yield_with_render_partial_inside.erb | 2 + .../test/fixtures/localized/hello_world.de.html | 1 + .../test/fixtures/localized/hello_world.en.html | 1 + actionview/test/fixtures/mascot.rb | 3 + actionview/test/fixtures/mascots.yml | 4 + actionview/test/fixtures/mascots/_mascot.html.erb | 1 + actionview/test/fixtures/multipart/binary_file | Bin 0 -> 19820 bytes .../test/fixtures/multipart/boundary_problem_file | 10 + actionview/test/fixtures/multipart/bracketed_param | 5 + .../test/fixtures/multipart/bracketed_utf8_param | 5 + actionview/test/fixtures/multipart/empty | 10 + actionview/test/fixtures/multipart/hello.txt | 1 + actionview/test/fixtures/multipart/large_text_file | 10 + actionview/test/fixtures/multipart/mixed_files | Bin 0 -> 19937 bytes actionview/test/fixtures/multipart/mona_lisa.jpg | Bin 0 -> 159528 bytes actionview/test/fixtures/multipart/none | 9 + .../test/fixtures/multipart/single_parameter | 5 + .../test/fixtures/multipart/single_utf8_param | 5 + actionview/test/fixtures/multipart/text_file | 10 + ...er_default_content_types_for_respond_to.xml.erb | 1 + .../render_default_for_builder.builder | 1 + .../old_content_type/render_default_for_erb.erb | 1 + .../test/fixtures/override/test/hello_world.erb | 1 + .../test/fixtures/override2/layouts/test/sub.erb | 1 + actionview/test/fixtures/plain_text.raw | 1 + .../test/fixtures/plain_text_with_characters.raw | 1 + .../test/fixtures/post_test/layouts/post.html.erb | 1 + .../post_test/layouts/super_post.iphone.erb | 1 + .../test/fixtures/post_test/post/index.html.erb | 1 + .../test/fixtures/post_test/post/index.iphone.erb | 1 + .../fixtures/post_test/super_post/index.html.erb | 1 + .../fixtures/post_test/super_post/index.iphone.erb | 1 + actionview/test/fixtures/project.rb | 3 + actionview/test/fixtures/projects.yml | 7 + actionview/test/fixtures/projects/_project.erb | 1 + actionview/test/fixtures/public/.gitignore | 1 + actionview/test/fixtures/public/404.html | 1 + actionview/test/fixtures/public/500.da.html | 1 + actionview/test/fixtures/public/500.html | 1 + actionview/test/fixtures/public/elsewhere/cools.js | 1 + actionview/test/fixtures/public/elsewhere/file.css | 1 + actionview/test/fixtures/public/foo/bar.html | 1 + actionview/test/fixtures/public/foo/baz.css | 3 + actionview/test/fixtures/public/foo/index.html | 1 + ...2\223\343\201\253\343\201\241\343\201\257.html" | 1 + actionview/test/fixtures/public/index.html | 1 + .../fixtures/public/javascripts/application.js | 1 + .../test/fixtures/public/javascripts/bank.js | 1 + .../fixtures/public/javascripts/common.javascript | 1 + .../test/fixtures/public/javascripts/controls.js | 1 + .../test/fixtures/public/javascripts/dragdrop.js | 1 + .../test/fixtures/public/javascripts/effects.js | 1 + .../test/fixtures/public/javascripts/prototype.js | 1 + .../test/fixtures/public/javascripts/robber.js | 1 + .../fixtures/public/javascripts/subdir/subdir.js | 1 + .../fixtures/public/javascripts/version.1.0.js | 1 + .../test/fixtures/public/stylesheets/bank.css | 1 + .../test/fixtures/public/stylesheets/random.styles | 1 + .../test/fixtures/public/stylesheets/robber.css | 1 + .../fixtures/public/stylesheets/subdir/subdir.css | 1 + .../fixtures/public/stylesheets/version.1.0.css | 1 + .../fixtures/quiz/questions/_question.html.erb | 1 + actionview/test/fixtures/replies.yml | 15 + actionview/test/fixtures/replies/_reply.erb | 1 + actionview/test/fixtures/reply.rb | 7 + .../respond_to/all_types_with_layout.html.erb | 1 + ...stom_constant_handling_without_block.mobile.erb | 1 + .../iphone_with_html_response_type.html.erb | 1 + .../iphone_with_html_response_type.iphone.erb | 1 + .../fixtures/respond_to/layouts/missing.html.erb | 1 + .../fixtures/respond_to/layouts/standard.html.erb | 1 + .../respond_to/layouts/standard.iphone.erb | 1 + .../fixtures/respond_to/using_defaults.html.erb | 1 + .../fixtures/respond_to/using_defaults.xml.builder | 1 + .../respond_to/using_defaults_with_all.html.erb | 1 + .../using_defaults_with_type_list.html.erb | 1 + .../using_defaults_with_type_list.xml.builder | 1 + .../test/fixtures/respond_with/edit.html.erb | 1 + actionview/test/fixtures/respond_with/new.html.erb | 1 + .../using_invalid_resource_with_template.xml.erb | 1 + .../using_options_with_template.xml.erb | 1 + .../fixtures/respond_with/using_resource.js.erb | 1 + .../using_resource_with_block.html.erb | 1 + actionview/test/fixtures/ruby_template.ruby | 2 + actionview/test/fixtures/scope/test/modgreet.erb | 1 + .../session_autoload_test/foo.rb | 10 + actionview/test/fixtures/shared.html.erb | 1 + .../test/fixtures/star_star_mime/index.js.erb | 1 + .../fixtures/symlink_parent/symlinked_layout.erb | 5 + actionview/test/fixtures/test/_200.html.erb | 1 + .../fixtures/test/_b_layout_for_partial.html.erb | 1 + .../_b_layout_for_partial_with_object.html.erb | 1 + ...layout_for_partial_with_object_counter.html.erb | 1 + .../test/fixtures/test/_changing_priority.html.erb | 1 + .../test/fixtures/test/_changing_priority.json.erb | 1 + .../test/_content_tag_nested_in_content_tag.erb | 3 + actionview/test/fixtures/test/_counter.html.erb | 1 + actionview/test/fixtures/test/_customer.erb | 1 + .../test/fixtures/test/_customer_counter.erb | 1 + .../fixtures/test/_customer_counter_with_as.erb | 1 + .../test/fixtures/test/_customer_greeting.erb | 1 + .../test/fixtures/test/_customer_with_var.erb | 1 + .../test/_directory/_partial_with_locales.html.erb | 1 + .../fixtures/test/_first_json_partial.json.erb | 1 + actionview/test/fixtures/test/_form.erb | 1 + actionview/test/fixtures/test/_from_helper.erb | 1 + actionview/test/fixtures/test/_hash_greeting.erb | 1 + actionview/test/fixtures/test/_hash_object.erb | 2 + actionview/test/fixtures/test/_hello.builder | 1 + .../fixtures/test/_json_change_priority.json.erb | 0 .../test/fixtures/test/_label_with_block.erb | 4 + actionview/test/fixtures/test/_labelling_form.erb | 1 + .../test/_layout_for_block_with_args.html.erb | 3 + .../fixtures/test/_layout_for_partial.html.erb | 3 + .../test/_layout_with_partial_and_yield.html.erb | 4 + .../test/fixtures/test/_local_inspector.html.erb | 1 + .../test/fixtures/test/_object_inspector.erb | 1 + actionview/test/fixtures/test/_one.html.erb | 1 + actionview/test/fixtures/test/_partial.erb | 1 + actionview/test/fixtures/test/_partial.html.erb | 1 + actionview/test/fixtures/test/_partial.js.erb | 1 + .../test/_partial_for_use_in_layout.html.erb | 1 + .../test/fixtures/test/_partial_html_erb.html.erb | 1 + .../fixtures/test/_partial_name_local_variable.erb | 1 + actionview/test/fixtures/test/_partial_only.erb | 1 + .../test/fixtures/test/_partial_only_html.html | 1 + .../test/fixtures/test/_partial_with_layout.erb | 2 + .../test/_partial_with_layout_block_content.erb | 4 + .../test/_partial_with_layout_block_partial.erb | 4 + .../test/_partial_with_only_html_version.html.erb | 1 + .../test/fixtures/test/_partial_with_partial.erb | 2 + actionview/test/fixtures/test/_person.erb | 2 + actionview/test/fixtures/test/_raise.html.erb | 1 + .../test/fixtures/test/_raise_indentation.html.erb | 13 + .../fixtures/test/_second_json_partial.json.erb | 1 + actionview/test/fixtures/test/_two.html.erb | 1 + .../test/fixtures/test/_utf8_partial.html.erb | 1 + .../fixtures/test/_utf8_partial_magic.html.erb | 2 + .../test/fixtures/test/action_talk_to_layout.erb | 2 + actionview/test/fixtures/test/basic.html.erb | 1 + .../test/calling_partial_with_layout.html.erb | 1 + actionview/test/fixtures/test/capturing.erb | 4 + .../test/fixtures/test/change_priority.html.erb | 2 + actionview/test/fixtures/test/content_for.erb | 1 + .../fixtures/test/content_for_concatenated.erb | 3 + .../fixtures/test/content_for_with_parameter.erb | 2 + actionview/test/fixtures/test/dont_pick_me | 1 + .../test/dot.directory/render_file_with_ivar.erb | 1 + .../test/fixtures/test/formatted_html_erb.html.erb | 1 + .../test/fixtures/test/formatted_xml_erb.builder | 1 + .../test/fixtures/test/formatted_xml_erb.html.erb | 1 + .../test/fixtures/test/formatted_xml_erb.xml.erb | 1 + actionview/test/fixtures/test/greeting.html.erb | 1 + actionview/test/fixtures/test/greeting.xml.erb | 1 + actionview/test/fixtures/test/hello,world.erb | 1 + actionview/test/fixtures/test/hello.builder | 4 + actionview/test/fixtures/test/hello/hello.erb | 1 + .../test/fixtures/test/hello_world.da.html.erb | 1 + actionview/test/fixtures/test/hello_world.erb | 1 + .../test/fixtures/test/hello_world.pt-BR.html.erb | 1 + .../fixtures/test/hello_world_container.builder | 3 + .../fixtures/test/hello_world_from_rxml.builder | 3 + .../test/hello_world_with_layout_false.erb | 1 + .../test/hello_world_with_partial.html.erb | 2 + .../test/fixtures/test/hello_xml_world.builder | 11 + .../test/fixtures/test/html_template.html.erb | 1 + actionview/test/fixtures/test/hyphen-ated.erb | 1 + .../test/implicit_content_type.atom.builder | 2 + .../test/fixtures/test/layout_render_file.erb | 2 + .../test/fixtures/test/layout_render_object.erb | 1 + actionview/test/fixtures/test/list.erb | 1 + actionview/test/fixtures/test/nested_layout.erb | 3 + actionview/test/fixtures/test/nested_streaming.erb | 3 + .../test/non_erb_block_content_for.builder | 4 + actionview/test/fixtures/test/one.html.erb | 1 + .../test/fixtures/test/potential_conflicts.erb | 4 + .../test/fixtures/test/proper_block_detection.erb | 1 + .../test/render_file_from_template.html.erb | 1 + .../test/fixtures/test/render_file_with_ivar.erb | 1 + .../test/fixtures/test/render_file_with_locals.erb | 1 + .../test/render_file_with_locals_and_default.erb | 1 + ...icit_html_template_from_xhr_request.da.html.erb | 1 + ...mplicit_html_template_from_xhr_request.html.erb | 1 + ...nder_implicit_js_template_without_layout.js.erb | 1 + .../test/render_partial_inside_directory.html.erb | 1 + .../test/fixtures/test/render_to_string_test.erb | 1 + .../fixtures/test/render_two_partials.html.erb | 2 + actionview/test/fixtures/test/streaming.erb | 3 + actionview/test/fixtures/test/streaming_buster.erb | 3 + .../test/fixtures/test/sub_template_raise.html.erb | 1 + actionview/test/fixtures/test/template.erb | 1 + .../fixtures/test/update_element_with_capture.erb | 9 + .../test/using_layout_around_block.html.erb | 1 + actionview/test/fixtures/test/utf8.html.erb | 4 + actionview/test/fixtures/test/utf8_magic.html.erb | 5 + .../test/utf8_magic_with_bare_partial.html.erb | 5 + .../test/fixtures/test/with_html_partial.html.erb | 1 + .../test/fixtures/test/with_partial.html.erb | 1 + .../test/fixtures/test/with_partial.text.erb | 1 + .../test/fixtures/test/with_xml_template.html.erb | 1 + actionview/test/fixtures/topic.rb | 3 + actionview/test/fixtures/topics.yml | 22 + actionview/test/fixtures/topics/_topic.html.erb | 1 + .../test/fixtures/translations/templates/array.erb | 1 + .../fixtures/translations/templates/default.erb | 1 + .../test/fixtures/translations/templates/found.erb | 1 + .../fixtures/translations/templates/missing.erb | 1 + actionview/test/fixtures/with_format.json.erb | 1 + actionview/test/lib/controller/fake_controllers.rb | 35 + actionview/test/lib/controller/fake_models.rb | 219 ++ .../test/template/active_model_helper_test.rb | 99 + actionview/test/template/asset_tag_helper_test.rb | 762 +++++ actionview/test/template/atom_feed_helper_test.rb | 349 +++ actionview/test/template/capture_helper_test.rb | 242 ++ .../test/template/compiled_templates_test.rb | 63 + actionview/test/template/date_helper_i18n_test.rb | 148 + actionview/test/template/date_helper_test.rb | 3199 ++++++++++++++++++++ actionview/test/template/debug_helper_test.rb | 8 + .../test/template/dependency_tracker_test.rb | 74 + actionview/test/template/digestor_test.rb | 197 ++ actionview/test/template/erb/form_for_test.rb | 11 + actionview/test/template/erb/helper.rb | 24 + actionview/test/template/erb/tag_helper_test.rb | 30 + actionview/test/template/erb_util_test.rb | 60 + .../test/template/form_collections_helper_test.rb | 358 +++ actionview/test/template/form_helper_test.rb | 2959 ++++++++++++++++++ .../test/template/form_options_helper_i18n_test.rb | 27 + .../test/template/form_options_helper_test.rb | 1304 ++++++++ actionview/test/template/form_tag_helper_test.rb | 614 ++++ .../test/template/html-scanner/cdata_node_test.rb | 15 + .../test/template/html-scanner/document_test.rb | 148 + actionview/test/template/html-scanner/node_test.rb | 89 + .../test/template/html-scanner/sanitizer_test.rb | 330 ++ .../test/template/html-scanner/tag_node_test.rb | 243 ++ .../test/template/html-scanner/text_node_test.rb | 50 + .../test/template/html-scanner/tokenizer_test.rb | 131 + actionview/test/template/javascript_helper_test.rb | 62 + actionview/test/template/log_subscriber_test.rb | 91 + actionview/test/template/lookup_context_test.rb | 263 ++ actionview/test/template/number_helper_test.rb | 151 + actionview/test/template/output_buffer_test.rb | 59 + .../test/template/output_safety_helper_test.rb | 28 + actionview/test/template/record_identifier_test.rb | 49 + actionview/test/template/record_tag_helper_test.rb | 117 + actionview/test/template/render_test.rb | 537 ++++ actionview/test/template/resolver_patterns_test.rb | 31 + actionview/test/template/sanitize_helper_test.rb | 51 + actionview/test/template/streaming_render_test.rb | 109 + actionview/test/template/tag_helper_test.rb | 130 + actionview/test/template/template_error_test.rb | 13 + actionview/test/template/template_test.rb | 200 ++ actionview/test/template/test_case_test.rb | 367 +++ actionview/test/template/test_test.rb | 80 + .../test/template/testing/fixture_resolver_test.rb | 18 + .../test/template/testing/null_resolver_test.rb | 12 + actionview/test/template/text_helper_test.rb | 467 +++ .../test/template/translation_helper_test.rb | 138 + actionview/test/template/url_helper_test.rb | 759 +++++ 349 files changed, 17643 insertions(+) create mode 100644 actionview/test/abstract_unit.rb create mode 100644 actionview/test/active_record_unit.rb create mode 100644 actionview/test/activerecord/controller_runtime_test.rb create mode 100644 actionview/test/activerecord/form_helper_activerecord_test.rb create mode 100644 actionview/test/activerecord/polymorphic_routes_test.rb create mode 100644 actionview/test/activerecord/render_partial_with_record_identification_test.rb create mode 100644 actionview/test/fixtures/_top_level_partial.html.erb create mode 100644 actionview/test/fixtures/_top_level_partial_only.erb create mode 100644 actionview/test/fixtures/alternate_helpers/foo_helper.rb create mode 100644 actionview/test/fixtures/bad_customers/_bad_customer.html.erb create mode 100644 actionview/test/fixtures/blog_public/.gitignore create mode 100644 actionview/test/fixtures/blog_public/blog.html create mode 100644 actionview/test/fixtures/blog_public/index.html create mode 100644 actionview/test/fixtures/blog_public/subdir/index.html create mode 100644 actionview/test/fixtures/comments/empty.de.html.erb create mode 100644 actionview/test/fixtures/comments/empty.html.builder create mode 100644 actionview/test/fixtures/comments/empty.html.erb create mode 100644 actionview/test/fixtures/comments/empty.xml.erb create mode 100644 actionview/test/fixtures/companies.yml create mode 100644 actionview/test/fixtures/company.rb create mode 100644 actionview/test/fixtures/custom_pattern/another.html.erb create mode 100644 actionview/test/fixtures/custom_pattern/html/another.erb create mode 100644 actionview/test/fixtures/custom_pattern/html/path.erb create mode 100644 actionview/test/fixtures/customers/_customer.html.erb create mode 100644 actionview/test/fixtures/db_definitions/sqlite.sql create mode 100644 actionview/test/fixtures/developer.rb create mode 100644 actionview/test/fixtures/developers.yml create mode 100644 actionview/test/fixtures/developers/_developer.erb create mode 100644 actionview/test/fixtures/developers_projects.yml create mode 100644 actionview/test/fixtures/digestor/comments/_comment.html.erb create mode 100644 actionview/test/fixtures/digestor/comments/_comments.html.erb create mode 100644 actionview/test/fixtures/digestor/events/_event.html.erb create mode 100644 actionview/test/fixtures/digestor/level/below/_header.html.erb create mode 100644 actionview/test/fixtures/digestor/level/below/index.html.erb create mode 100644 actionview/test/fixtures/digestor/messages/_form.html.erb create mode 100644 actionview/test/fixtures/digestor/messages/_header.html.erb create mode 100644 actionview/test/fixtures/digestor/messages/_message.html.erb create mode 100644 actionview/test/fixtures/digestor/messages/actions/_move.html.erb create mode 100644 actionview/test/fixtures/digestor/messages/edit.html.erb create mode 100644 actionview/test/fixtures/digestor/messages/index.html.erb create mode 100644 actionview/test/fixtures/digestor/messages/show.html.erb create mode 100644 actionview/test/fixtures/filter_test/implicit_actions/edit.html.erb create mode 100644 actionview/test/fixtures/filter_test/implicit_actions/show.html.erb create mode 100644 actionview/test/fixtures/fun/games/_form.erb create mode 100644 actionview/test/fixtures/fun/games/_game.erb create mode 100644 actionview/test/fixtures/fun/games/hello_world.erb create mode 100644 actionview/test/fixtures/fun/serious/games/_game.erb create mode 100644 actionview/test/fixtures/functional_caching/_partial.erb create mode 100644 actionview/test/fixtures/functional_caching/formatted_fragment_cached.html.erb create mode 100644 actionview/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder create mode 100644 actionview/test/fixtures/functional_caching/fragment_cached.html.erb create mode 100644 actionview/test/fixtures/functional_caching/fragment_cached_without_digest.html.erb create mode 100644 actionview/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb create mode 100644 actionview/test/fixtures/functional_caching/inline_fragment_cached.html.erb create mode 100644 actionview/test/fixtures/games/_game.erb create mode 100644 actionview/test/fixtures/good_customers/_good_customer.html.erb create mode 100644 actionview/test/fixtures/happy_path/render_action/hello_world.erb create mode 100644 actionview/test/fixtures/hello.html create mode 100644 actionview/test/fixtures/helpers/abc_helper.rb create mode 100644 actionview/test/fixtures/helpers/fun/games_helper.rb create mode 100644 actionview/test/fixtures/helpers/fun/pdf_helper.rb create mode 100644 actionview/test/fixtures/helpers/helpery_test_helper.rb create mode 100644 actionview/test/fixtures/helpers/just_me_helper.rb create mode 100644 actionview/test/fixtures/helpers/me_too_helper.rb create mode 100644 actionview/test/fixtures/helpers1_pack/pack1_helper.rb create mode 100644 actionview/test/fixtures/helpers2_pack/pack2_helper.rb create mode 100644 actionview/test/fixtures/layout_tests/alt/hello.erb create mode 100644 actionview/test/fixtures/layout_tests/alt/layouts/alt.erb create mode 100644 actionview/test/fixtures/layout_tests/layouts/controller_name_space/nested.erb create mode 100644 actionview/test/fixtures/layout_tests/layouts/item.erb create mode 100644 actionview/test/fixtures/layout_tests/layouts/layout_test.erb create mode 100644 actionview/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb create mode 120000 actionview/test/fixtures/layout_tests/layouts/symlinked create mode 100644 actionview/test/fixtures/layout_tests/layouts/third_party_template_library.mab create mode 100644 actionview/test/fixtures/layout_tests/views/goodbye.erb create mode 100644 actionview/test/fixtures/layout_tests/views/hello.erb create mode 100644 actionview/test/fixtures/layouts/_column.html.erb create mode 100644 actionview/test/fixtures/layouts/_customers.erb create mode 100644 actionview/test/fixtures/layouts/_partial_and_yield.erb create mode 100644 actionview/test/fixtures/layouts/_yield_only.erb create mode 100644 actionview/test/fixtures/layouts/_yield_with_params.erb create mode 100644 actionview/test/fixtures/layouts/block_with_layout.erb create mode 100644 actionview/test/fixtures/layouts/builder.builder create mode 100644 actionview/test/fixtures/layouts/partial_with_layout.erb create mode 100644 actionview/test/fixtures/layouts/standard.html.erb create mode 100644 actionview/test/fixtures/layouts/streaming.erb create mode 100644 actionview/test/fixtures/layouts/talk_from_action.erb create mode 100644 actionview/test/fixtures/layouts/with_html_partial.html.erb create mode 100644 actionview/test/fixtures/layouts/xhr.html.erb create mode 100644 actionview/test/fixtures/layouts/yield.erb create mode 100644 actionview/test/fixtures/layouts/yield_with_render_inline_inside.erb create mode 100644 actionview/test/fixtures/layouts/yield_with_render_partial_inside.erb create mode 100644 actionview/test/fixtures/localized/hello_world.de.html create mode 100644 actionview/test/fixtures/localized/hello_world.en.html create mode 100644 actionview/test/fixtures/mascot.rb create mode 100644 actionview/test/fixtures/mascots.yml create mode 100644 actionview/test/fixtures/mascots/_mascot.html.erb create mode 100644 actionview/test/fixtures/multipart/binary_file create mode 100644 actionview/test/fixtures/multipart/boundary_problem_file create mode 100644 actionview/test/fixtures/multipart/bracketed_param create mode 100644 actionview/test/fixtures/multipart/bracketed_utf8_param create mode 100644 actionview/test/fixtures/multipart/empty create mode 100644 actionview/test/fixtures/multipart/hello.txt create mode 100644 actionview/test/fixtures/multipart/large_text_file create mode 100644 actionview/test/fixtures/multipart/mixed_files create mode 100644 actionview/test/fixtures/multipart/mona_lisa.jpg create mode 100644 actionview/test/fixtures/multipart/none create mode 100644 actionview/test/fixtures/multipart/single_parameter create mode 100644 actionview/test/fixtures/multipart/single_utf8_param create mode 100644 actionview/test/fixtures/multipart/text_file create mode 100644 actionview/test/fixtures/old_content_type/render_default_content_types_for_respond_to.xml.erb create mode 100644 actionview/test/fixtures/old_content_type/render_default_for_builder.builder create mode 100644 actionview/test/fixtures/old_content_type/render_default_for_erb.erb create mode 100644 actionview/test/fixtures/override/test/hello_world.erb create mode 100644 actionview/test/fixtures/override2/layouts/test/sub.erb create mode 100644 actionview/test/fixtures/plain_text.raw create mode 100644 actionview/test/fixtures/plain_text_with_characters.raw create mode 100644 actionview/test/fixtures/post_test/layouts/post.html.erb create mode 100644 actionview/test/fixtures/post_test/layouts/super_post.iphone.erb create mode 100644 actionview/test/fixtures/post_test/post/index.html.erb create mode 100644 actionview/test/fixtures/post_test/post/index.iphone.erb create mode 100644 actionview/test/fixtures/post_test/super_post/index.html.erb create mode 100644 actionview/test/fixtures/post_test/super_post/index.iphone.erb create mode 100644 actionview/test/fixtures/project.rb create mode 100644 actionview/test/fixtures/projects.yml create mode 100644 actionview/test/fixtures/projects/_project.erb create mode 100644 actionview/test/fixtures/public/.gitignore create mode 100644 actionview/test/fixtures/public/404.html create mode 100644 actionview/test/fixtures/public/500.da.html create mode 100644 actionview/test/fixtures/public/500.html create mode 100644 actionview/test/fixtures/public/elsewhere/cools.js create mode 100644 actionview/test/fixtures/public/elsewhere/file.css create mode 100644 actionview/test/fixtures/public/foo/bar.html create mode 100644 actionview/test/fixtures/public/foo/baz.css create mode 100644 actionview/test/fixtures/public/foo/index.html create mode 100644 "actionview/test/fixtures/public/foo/\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257.html" create mode 100644 actionview/test/fixtures/public/index.html create mode 100644 actionview/test/fixtures/public/javascripts/application.js create mode 100644 actionview/test/fixtures/public/javascripts/bank.js create mode 100644 actionview/test/fixtures/public/javascripts/common.javascript create mode 100644 actionview/test/fixtures/public/javascripts/controls.js create mode 100644 actionview/test/fixtures/public/javascripts/dragdrop.js create mode 100644 actionview/test/fixtures/public/javascripts/effects.js create mode 100644 actionview/test/fixtures/public/javascripts/prototype.js create mode 100644 actionview/test/fixtures/public/javascripts/robber.js create mode 100644 actionview/test/fixtures/public/javascripts/subdir/subdir.js create mode 100644 actionview/test/fixtures/public/javascripts/version.1.0.js create mode 100644 actionview/test/fixtures/public/stylesheets/bank.css create mode 100644 actionview/test/fixtures/public/stylesheets/random.styles create mode 100644 actionview/test/fixtures/public/stylesheets/robber.css create mode 100644 actionview/test/fixtures/public/stylesheets/subdir/subdir.css create mode 100644 actionview/test/fixtures/public/stylesheets/version.1.0.css create mode 100644 actionview/test/fixtures/quiz/questions/_question.html.erb create mode 100644 actionview/test/fixtures/replies.yml create mode 100644 actionview/test/fixtures/replies/_reply.erb create mode 100644 actionview/test/fixtures/reply.rb create mode 100644 actionview/test/fixtures/respond_to/all_types_with_layout.html.erb create mode 100644 actionview/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb create mode 100644 actionview/test/fixtures/respond_to/iphone_with_html_response_type.html.erb create mode 100644 actionview/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb create mode 100644 actionview/test/fixtures/respond_to/layouts/missing.html.erb create mode 100644 actionview/test/fixtures/respond_to/layouts/standard.html.erb create mode 100644 actionview/test/fixtures/respond_to/layouts/standard.iphone.erb create mode 100644 actionview/test/fixtures/respond_to/using_defaults.html.erb create mode 100644 actionview/test/fixtures/respond_to/using_defaults.xml.builder create mode 100644 actionview/test/fixtures/respond_to/using_defaults_with_all.html.erb create mode 100644 actionview/test/fixtures/respond_to/using_defaults_with_type_list.html.erb create mode 100644 actionview/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder create mode 100644 actionview/test/fixtures/respond_with/edit.html.erb create mode 100644 actionview/test/fixtures/respond_with/new.html.erb create mode 100644 actionview/test/fixtures/respond_with/using_invalid_resource_with_template.xml.erb create mode 100644 actionview/test/fixtures/respond_with/using_options_with_template.xml.erb create mode 100644 actionview/test/fixtures/respond_with/using_resource.js.erb create mode 100644 actionview/test/fixtures/respond_with/using_resource_with_block.html.erb create mode 100644 actionview/test/fixtures/ruby_template.ruby create mode 100644 actionview/test/fixtures/scope/test/modgreet.erb create mode 100644 actionview/test/fixtures/session_autoload_test/session_autoload_test/foo.rb create mode 100644 actionview/test/fixtures/shared.html.erb create mode 100644 actionview/test/fixtures/star_star_mime/index.js.erb create mode 100644 actionview/test/fixtures/symlink_parent/symlinked_layout.erb create mode 100644 actionview/test/fixtures/test/_200.html.erb create mode 100644 actionview/test/fixtures/test/_b_layout_for_partial.html.erb create mode 100644 actionview/test/fixtures/test/_b_layout_for_partial_with_object.html.erb create mode 100644 actionview/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb create mode 100644 actionview/test/fixtures/test/_changing_priority.html.erb create mode 100644 actionview/test/fixtures/test/_changing_priority.json.erb create mode 100644 actionview/test/fixtures/test/_content_tag_nested_in_content_tag.erb create mode 100644 actionview/test/fixtures/test/_counter.html.erb create mode 100644 actionview/test/fixtures/test/_customer.erb create mode 100644 actionview/test/fixtures/test/_customer_counter.erb create mode 100644 actionview/test/fixtures/test/_customer_counter_with_as.erb create mode 100644 actionview/test/fixtures/test/_customer_greeting.erb create mode 100644 actionview/test/fixtures/test/_customer_with_var.erb create mode 100644 actionview/test/fixtures/test/_directory/_partial_with_locales.html.erb create mode 100644 actionview/test/fixtures/test/_first_json_partial.json.erb create mode 100644 actionview/test/fixtures/test/_form.erb create mode 100644 actionview/test/fixtures/test/_from_helper.erb create mode 100644 actionview/test/fixtures/test/_hash_greeting.erb create mode 100644 actionview/test/fixtures/test/_hash_object.erb create mode 100644 actionview/test/fixtures/test/_hello.builder create mode 100644 actionview/test/fixtures/test/_json_change_priority.json.erb create mode 100644 actionview/test/fixtures/test/_label_with_block.erb create mode 100644 actionview/test/fixtures/test/_labelling_form.erb create mode 100644 actionview/test/fixtures/test/_layout_for_block_with_args.html.erb create mode 100644 actionview/test/fixtures/test/_layout_for_partial.html.erb create mode 100644 actionview/test/fixtures/test/_layout_with_partial_and_yield.html.erb create mode 100644 actionview/test/fixtures/test/_local_inspector.html.erb create mode 100644 actionview/test/fixtures/test/_object_inspector.erb create mode 100644 actionview/test/fixtures/test/_one.html.erb create mode 100644 actionview/test/fixtures/test/_partial.erb create mode 100644 actionview/test/fixtures/test/_partial.html.erb create mode 100644 actionview/test/fixtures/test/_partial.js.erb create mode 100644 actionview/test/fixtures/test/_partial_for_use_in_layout.html.erb create mode 100644 actionview/test/fixtures/test/_partial_html_erb.html.erb create mode 100644 actionview/test/fixtures/test/_partial_name_local_variable.erb create mode 100644 actionview/test/fixtures/test/_partial_only.erb create mode 100644 actionview/test/fixtures/test/_partial_only_html.html create mode 100644 actionview/test/fixtures/test/_partial_with_layout.erb create mode 100644 actionview/test/fixtures/test/_partial_with_layout_block_content.erb create mode 100644 actionview/test/fixtures/test/_partial_with_layout_block_partial.erb create mode 100644 actionview/test/fixtures/test/_partial_with_only_html_version.html.erb create mode 100644 actionview/test/fixtures/test/_partial_with_partial.erb create mode 100644 actionview/test/fixtures/test/_person.erb create mode 100644 actionview/test/fixtures/test/_raise.html.erb create mode 100644 actionview/test/fixtures/test/_raise_indentation.html.erb create mode 100644 actionview/test/fixtures/test/_second_json_partial.json.erb create mode 100644 actionview/test/fixtures/test/_two.html.erb create mode 100644 actionview/test/fixtures/test/_utf8_partial.html.erb create mode 100644 actionview/test/fixtures/test/_utf8_partial_magic.html.erb create mode 100644 actionview/test/fixtures/test/action_talk_to_layout.erb create mode 100644 actionview/test/fixtures/test/basic.html.erb create mode 100644 actionview/test/fixtures/test/calling_partial_with_layout.html.erb create mode 100644 actionview/test/fixtures/test/capturing.erb create mode 100644 actionview/test/fixtures/test/change_priority.html.erb create mode 100644 actionview/test/fixtures/test/content_for.erb create mode 100644 actionview/test/fixtures/test/content_for_concatenated.erb create mode 100644 actionview/test/fixtures/test/content_for_with_parameter.erb create mode 100644 actionview/test/fixtures/test/dont_pick_me create mode 100644 actionview/test/fixtures/test/dot.directory/render_file_with_ivar.erb create mode 100644 actionview/test/fixtures/test/formatted_html_erb.html.erb create mode 100644 actionview/test/fixtures/test/formatted_xml_erb.builder create mode 100644 actionview/test/fixtures/test/formatted_xml_erb.html.erb create mode 100644 actionview/test/fixtures/test/formatted_xml_erb.xml.erb create mode 100644 actionview/test/fixtures/test/greeting.html.erb create mode 100644 actionview/test/fixtures/test/greeting.xml.erb create mode 100644 actionview/test/fixtures/test/hello,world.erb create mode 100644 actionview/test/fixtures/test/hello.builder create mode 100644 actionview/test/fixtures/test/hello/hello.erb create mode 100644 actionview/test/fixtures/test/hello_world.da.html.erb create mode 100644 actionview/test/fixtures/test/hello_world.erb create mode 100644 actionview/test/fixtures/test/hello_world.pt-BR.html.erb create mode 100644 actionview/test/fixtures/test/hello_world_container.builder create mode 100644 actionview/test/fixtures/test/hello_world_from_rxml.builder create mode 100644 actionview/test/fixtures/test/hello_world_with_layout_false.erb create mode 100644 actionview/test/fixtures/test/hello_world_with_partial.html.erb create mode 100644 actionview/test/fixtures/test/hello_xml_world.builder create mode 100644 actionview/test/fixtures/test/html_template.html.erb create mode 100644 actionview/test/fixtures/test/hyphen-ated.erb create mode 100644 actionview/test/fixtures/test/implicit_content_type.atom.builder create mode 100644 actionview/test/fixtures/test/layout_render_file.erb create mode 100644 actionview/test/fixtures/test/layout_render_object.erb create mode 100644 actionview/test/fixtures/test/list.erb create mode 100644 actionview/test/fixtures/test/nested_layout.erb create mode 100644 actionview/test/fixtures/test/nested_streaming.erb create mode 100644 actionview/test/fixtures/test/non_erb_block_content_for.builder create mode 100644 actionview/test/fixtures/test/one.html.erb create mode 100644 actionview/test/fixtures/test/potential_conflicts.erb create mode 100644 actionview/test/fixtures/test/proper_block_detection.erb create mode 100644 actionview/test/fixtures/test/render_file_from_template.html.erb create mode 100644 actionview/test/fixtures/test/render_file_with_ivar.erb create mode 100644 actionview/test/fixtures/test/render_file_with_locals.erb create mode 100644 actionview/test/fixtures/test/render_file_with_locals_and_default.erb create mode 100644 actionview/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb create mode 100644 actionview/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb create mode 100644 actionview/test/fixtures/test/render_implicit_js_template_without_layout.js.erb create mode 100644 actionview/test/fixtures/test/render_partial_inside_directory.html.erb create mode 100644 actionview/test/fixtures/test/render_to_string_test.erb create mode 100644 actionview/test/fixtures/test/render_two_partials.html.erb create mode 100644 actionview/test/fixtures/test/streaming.erb create mode 100644 actionview/test/fixtures/test/streaming_buster.erb create mode 100644 actionview/test/fixtures/test/sub_template_raise.html.erb create mode 100644 actionview/test/fixtures/test/template.erb create mode 100644 actionview/test/fixtures/test/update_element_with_capture.erb create mode 100644 actionview/test/fixtures/test/using_layout_around_block.html.erb create mode 100644 actionview/test/fixtures/test/utf8.html.erb create mode 100644 actionview/test/fixtures/test/utf8_magic.html.erb create mode 100644 actionview/test/fixtures/test/utf8_magic_with_bare_partial.html.erb create mode 100644 actionview/test/fixtures/test/with_html_partial.html.erb create mode 100644 actionview/test/fixtures/test/with_partial.html.erb create mode 100644 actionview/test/fixtures/test/with_partial.text.erb create mode 100644 actionview/test/fixtures/test/with_xml_template.html.erb create mode 100644 actionview/test/fixtures/topic.rb create mode 100644 actionview/test/fixtures/topics.yml create mode 100644 actionview/test/fixtures/topics/_topic.html.erb create mode 100644 actionview/test/fixtures/translations/templates/array.erb create mode 100644 actionview/test/fixtures/translations/templates/default.erb create mode 100644 actionview/test/fixtures/translations/templates/found.erb create mode 100644 actionview/test/fixtures/translations/templates/missing.erb create mode 100644 actionview/test/fixtures/with_format.json.erb create mode 100644 actionview/test/lib/controller/fake_controllers.rb create mode 100644 actionview/test/lib/controller/fake_models.rb create mode 100644 actionview/test/template/active_model_helper_test.rb create mode 100644 actionview/test/template/asset_tag_helper_test.rb create mode 100644 actionview/test/template/atom_feed_helper_test.rb create mode 100644 actionview/test/template/capture_helper_test.rb create mode 100644 actionview/test/template/compiled_templates_test.rb create mode 100644 actionview/test/template/date_helper_i18n_test.rb create mode 100644 actionview/test/template/date_helper_test.rb create mode 100644 actionview/test/template/debug_helper_test.rb create mode 100644 actionview/test/template/dependency_tracker_test.rb create mode 100644 actionview/test/template/digestor_test.rb create mode 100644 actionview/test/template/erb/form_for_test.rb create mode 100644 actionview/test/template/erb/helper.rb create mode 100644 actionview/test/template/erb/tag_helper_test.rb create mode 100644 actionview/test/template/erb_util_test.rb create mode 100644 actionview/test/template/form_collections_helper_test.rb create mode 100644 actionview/test/template/form_helper_test.rb create mode 100644 actionview/test/template/form_options_helper_i18n_test.rb create mode 100644 actionview/test/template/form_options_helper_test.rb create mode 100644 actionview/test/template/form_tag_helper_test.rb create mode 100644 actionview/test/template/html-scanner/cdata_node_test.rb create mode 100644 actionview/test/template/html-scanner/document_test.rb create mode 100644 actionview/test/template/html-scanner/node_test.rb create mode 100644 actionview/test/template/html-scanner/sanitizer_test.rb create mode 100644 actionview/test/template/html-scanner/tag_node_test.rb create mode 100644 actionview/test/template/html-scanner/text_node_test.rb create mode 100644 actionview/test/template/html-scanner/tokenizer_test.rb create mode 100644 actionview/test/template/javascript_helper_test.rb create mode 100644 actionview/test/template/log_subscriber_test.rb create mode 100644 actionview/test/template/lookup_context_test.rb create mode 100644 actionview/test/template/number_helper_test.rb create mode 100644 actionview/test/template/output_buffer_test.rb create mode 100644 actionview/test/template/output_safety_helper_test.rb create mode 100644 actionview/test/template/record_identifier_test.rb create mode 100644 actionview/test/template/record_tag_helper_test.rb create mode 100644 actionview/test/template/render_test.rb create mode 100644 actionview/test/template/resolver_patterns_test.rb create mode 100644 actionview/test/template/sanitize_helper_test.rb create mode 100644 actionview/test/template/streaming_render_test.rb create mode 100644 actionview/test/template/tag_helper_test.rb create mode 100644 actionview/test/template/template_error_test.rb create mode 100644 actionview/test/template/template_test.rb create mode 100644 actionview/test/template/test_case_test.rb create mode 100644 actionview/test/template/test_test.rb create mode 100644 actionview/test/template/testing/fixture_resolver_test.rb create mode 100644 actionview/test/template/testing/null_resolver_test.rb create mode 100644 actionview/test/template/text_helper_test.rb create mode 100644 actionview/test/template/translation_helper_test.rb create mode 100644 actionview/test/template/url_helper_test.rb (limited to 'actionview/test') diff --git a/actionview/test/abstract_unit.rb b/actionview/test/abstract_unit.rb new file mode 100644 index 0000000000..8213997f4e --- /dev/null +++ b/actionview/test/abstract_unit.rb @@ -0,0 +1,382 @@ +require File.expand_path('../../../load_paths', __FILE__) + +$:.unshift(File.dirname(__FILE__) + '/lib') +$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers') +$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers') + +ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp') + +require 'active_support/core_ext/kernel/reporting' + +# These are the normal settings that will be set up by Railties +# TODO: Have these tests support other combinations of these values +silence_warnings do + Encoding.default_internal = "UTF-8" + Encoding.default_external = "UTF-8" +end + +require 'active_support/testing/autorun' +require 'abstract_controller' +require 'action_controller' +require 'action_view' +require 'action_view/testing/resolvers' +require 'action_dispatch' +require 'active_support/dependencies' +require 'active_model' +require 'active_record' +require 'action_controller/caching' + +require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late + +module Rails + class << self + def env + @_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "test") + end + end +end + +ActiveSupport::Dependencies.hook! + +Thread.abort_on_exception = true + +# Show backtraces for deprecated behavior for quicker cleanup. +ActiveSupport::Deprecation.debug = true + +# Register danish language for testing +I18n.backend.store_translations 'da', {} +I18n.backend.store_translations 'pt-BR', {} +ORIGINAL_LOCALES = I18n.available_locales.map {|locale| locale.to_s }.sort + +FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') +FIXTURES = Pathname.new(FIXTURE_LOAD_PATH) + +module RackTestUtils + def body_to_string(body) + if body.respond_to?(:each) + str = "" + body.each {|s| str << s } + str + else + body + end + end + extend self +end + +module RenderERBUtils + def view + @view ||= begin + path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH) + view_paths = ActionView::PathSet.new([path]) + ActionView::Base.new(view_paths) + end + end + + def render_erb(string) + @virtual_path = nil + + template = ActionView::Template.new( + string.strip, + "test template", + ActionView::Template::Handlers::ERB, + {}) + + template.render(self, {}).strip + end +end + +SharedTestRoutes = ActionDispatch::Routing::RouteSet.new + +module ActionDispatch + module SharedRoutes + def before_setup + @routes = SharedTestRoutes + super + end + end + + # Hold off drawing routes until all the possible controller classes + # have been loaded. + module DrawOnce + class << self + attr_accessor :drew + end + self.drew = false + + def before_setup + super + return if DrawOnce.drew + + SharedTestRoutes.draw do + get ':controller(/:action)' + end + + ActionDispatch::IntegrationTest.app.routes.draw do + get ':controller(/:action)' + end + + DrawOnce.drew = true + end + end +end + +module ActiveSupport + class TestCase + include ActionDispatch::DrawOnce + end +end + +class RoutedRackApp + attr_reader :routes + + def initialize(routes, &blk) + @routes = routes + @stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes) + end + + def call(env) + @stack.call(env) + end +end + +class BasicController + attr_accessor :request + + def config + @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config).tap do |config| + # VIEW TODO: View tests should not require a controller + public_dir = File.expand_path("../fixtures/public", __FILE__) + config.assets_dir = public_dir + config.javascripts_dir = "#{public_dir}/javascripts" + config.stylesheets_dir = "#{public_dir}/stylesheets" + config.assets = ActiveSupport::InheritableOptions.new({ :prefix => "assets" }) + config + end + end +end + +class ActionDispatch::IntegrationTest < ActiveSupport::TestCase + include ActionDispatch::SharedRoutes + + def self.build_app(routes = nil) + RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware| + middleware.use "ActionDispatch::ShowExceptions", ActionDispatch::PublicExceptions.new("#{FIXTURE_LOAD_PATH}/public") + middleware.use "ActionDispatch::DebugExceptions" + middleware.use "ActionDispatch::Callbacks" + middleware.use "ActionDispatch::ParamsParser" + middleware.use "ActionDispatch::Cookies" + middleware.use "ActionDispatch::Flash" + middleware.use "Rack::Head" + yield(middleware) if block_given? + end + end + + self.app = build_app + + # Stub Rails dispatcher so it does not get controller references and + # simply return the controller#action as Rack::Body. + class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher + protected + def controller_reference(controller_param) + controller_param + end + + def dispatch(controller, action, env) + [200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]] + end + end + + def self.stub_controllers + old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher + ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher } + ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher } + yield ActionDispatch::Routing::RouteSet.new + ensure + ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher } + ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher } + end + + def with_routing(&block) + temporary_routes = ActionDispatch::Routing::RouteSet.new + old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes) + old_routes = SharedTestRoutes + silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) } + + yield temporary_routes + ensure + self.class.app = old_app + silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) } + end + + def with_autoload_path(path) + path = File.join(File.dirname(__FILE__), "fixtures", path) + if ActiveSupport::Dependencies.autoload_paths.include?(path) + yield + else + begin + ActiveSupport::Dependencies.autoload_paths << path + yield + ensure + ActiveSupport::Dependencies.autoload_paths.reject! {|p| p == path} + ActiveSupport::Dependencies.clear + end + end + end +end + +# Temporary base class +class Rack::TestCase < ActionDispatch::IntegrationTest + def self.testing(klass = nil) + if klass + @testing = "/#{klass.name.underscore}".sub!(/_controller$/, '') + else + @testing + end + end + + def get(thing, *args) + if thing.is_a?(Symbol) + super("#{self.class.testing}/#{thing}", *args) + else + super + end + end + + def assert_body(body) + assert_equal body, Array(response.body).join + end + + def assert_status(code) + assert_equal code, response.status + end + + def assert_response(body, status = 200, headers = {}) + assert_body body + assert_status status + headers.each do |header, value| + assert_header header, value + end + end + + def assert_content_type(type) + assert_equal type, response.headers["Content-Type"] + end + + def assert_header(name, value) + assert_equal value, response.headers[name] + end +end + +module ActionController + class Base + include ActionController::Testing + # This stub emulates the Railtie including the URL helpers from a Rails application + include SharedTestRoutes.url_helpers + include SharedTestRoutes.mounted_helpers + + self.view_paths = FIXTURE_LOAD_PATH + + def self.test_routes(&block) + routes = ActionDispatch::Routing::RouteSet.new + routes.draw(&block) + include routes.url_helpers + end + end + + class TestCase + include ActionDispatch::TestProcess + include ActionDispatch::SharedRoutes + end +end + +class ::ApplicationController < ActionController::Base +end + +module ActionView + class TestCase + # Must repeat the setup because AV::TestCase is a duplication + # of AC::TestCase + include ActionDispatch::SharedRoutes + end +end + +class Workshop + extend ActiveModel::Naming + include ActiveModel::Conversion + attr_accessor :id + + def initialize(id) + @id = id + end + + def persisted? + id.present? + end + + def to_s + id.to_s + end +end + +module ActionDispatch + class DebugExceptions + private + remove_method :stderr_logger + # Silence logger + def stderr_logger + nil + end + end +end + +module ActionDispatch + module RoutingVerbs + def get(uri_or_host, path = nil) + host = uri_or_host.host unless path + path ||= uri_or_host.path + + params = {'PATH_INFO' => path, + 'REQUEST_METHOD' => 'GET', + 'HTTP_HOST' => host} + + routes.call(params)[2].join + end + end +end + +module RoutingTestHelpers + def url_for(set, options, recall = nil) + set.send(:url_for, options.merge(:only_path => true, :_recall => recall)) + end +end + +class ResourcesController < ActionController::Base + def index() render :nothing => true end + alias_method :show, :index +end + +class ThreadsController < ResourcesController; end +class MessagesController < ResourcesController; end +class CommentsController < ResourcesController; end +class ReviewsController < ResourcesController; end +class AuthorsController < ResourcesController; end +class LogosController < ResourcesController; end + +class AccountsController < ResourcesController; end +class AdminController < ResourcesController; end +class ProductsController < ResourcesController; end +class ImagesController < ResourcesController; end +class PreferencesController < ResourcesController; end + +module Backoffice + class ProductsController < ResourcesController; end + class TagsController < ResourcesController; end + class ManufacturersController < ResourcesController; end + class ImagesController < ResourcesController; end + + module Admin + class ProductsController < ResourcesController; end + class ImagesController < ResourcesController; end + end +end diff --git a/actionview/test/active_record_unit.rb b/actionview/test/active_record_unit.rb new file mode 100644 index 0000000000..95fbb112c0 --- /dev/null +++ b/actionview/test/active_record_unit.rb @@ -0,0 +1,91 @@ +require 'abstract_unit' + +# Define the essentials +class ActiveRecordTestConnector + cattr_accessor :able_to_connect + cattr_accessor :connected + + # Set our defaults + self.connected = false + self.able_to_connect = true +end + +# Try to grab AR +unless defined?(ActiveRecord) && defined?(FixtureSet) + begin + PATH_TO_AR = "#{File.dirname(__FILE__)}/../../activerecord/lib" + raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR) + $LOAD_PATH.unshift PATH_TO_AR + require 'active_record' + rescue LoadError => e + $stderr.print "Failed to load Active Record. Skipping Active Record assertion tests: #{e}" + ActiveRecordTestConnector.able_to_connect = false + end +end +$stderr.flush + + +# Define the rest of the connector +class ActiveRecordTestConnector + class << self + def setup + unless self.connected || !self.able_to_connect + setup_connection + load_schema + require_fixture_models + self.connected = true + end + rescue Exception => e # errors from ActiveRecord setup + $stderr.puts "\nSkipping ActiveRecord assertion tests: #{e}" + #$stderr.puts " #{e.backtrace.join("\n ")}\n" + self.able_to_connect = false + end + + private + def setup_connection + if Object.const_defined?(:ActiveRecord) + defaults = { :database => ':memory:' } + adapter = defined?(JRUBY_VERSION) ? 'jdbcsqlite3' : 'sqlite3' + options = defaults.merge :adapter => adapter, :timeout => 500 + ActiveRecord::Base.establish_connection(options) + ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options } + ActiveRecord::Base.connection + + Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE) + else + raise "Can't setup connection since ActiveRecord isn't loaded." + end + end + + # Load actionpack sqlite tables + def load_schema + File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql| + ActiveRecord::Base.connection.execute(sql) unless sql.blank? + end + end + + def require_fixture_models + Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f} + end + end +end + +class ActiveRecordTestCase < ActionController::TestCase + include ActiveRecord::TestFixtures + + # Set our fixture path + if ActiveRecordTestConnector.able_to_connect + self.fixture_path = [FIXTURE_LOAD_PATH] + self.use_transactional_fixtures = false + end + + def self.fixtures(*args) + super if ActiveRecordTestConnector.connected + end + + def run(*args) + super if ActiveRecordTestConnector.connected + end +end + +ActiveRecordTestConnector.setup diff --git a/actionview/test/activerecord/controller_runtime_test.rb b/actionview/test/activerecord/controller_runtime_test.rb new file mode 100644 index 0000000000..368bec1c70 --- /dev/null +++ b/actionview/test/activerecord/controller_runtime_test.rb @@ -0,0 +1,95 @@ +require 'active_record_unit' +require 'active_record/railties/controller_runtime' +require 'fixtures/project' +require 'active_support/log_subscriber/test_helper' +require 'action_controller/log_subscriber' + +ActionController::Base.send :include, ActiveRecord::Railties::ControllerRuntime + +class ControllerRuntimeLogSubscriberTest < ActionController::TestCase + class LogSubscriberController < ActionController::Base + respond_to :html + + def show + render :inline => "<%= Project.all %>" + end + + def zero + render :inline => "Zero DB runtime" + end + + def create + ActiveRecord::LogSubscriber.runtime += 100 + project = Project.last + respond_with(project, location: url_for(action: :show)) + end + + def redirect + Project.all + redirect_to :action => 'show' + end + + def db_after_render + render :inline => "Hello world" + Project.all + ActiveRecord::LogSubscriber.runtime += 100 + end + end + + include ActiveSupport::LogSubscriber::TestHelper + tests LogSubscriberController + + def setup + super + @old_logger = ActionController::Base.logger + ActionController::LogSubscriber.attach_to :action_controller + end + + def teardown + super + ActiveSupport::LogSubscriber.log_subscribers.clear + ActionController::Base.logger = @old_logger + end + + def set_logger(logger) + ActionController::Base.logger = logger + end + + def test_log_with_active_record + get :show + wait + + assert_equal 2, @logger.logged(:info).size + assert_match(/\(Views: [\d.]+ms \| ActiveRecord: [\d.]+ms\)/, @logger.logged(:info)[1]) + end + + def test_runtime_reset_before_requests + ActiveRecord::LogSubscriber.runtime += 12345 + get :zero + wait + + assert_equal 2, @logger.logged(:info).size + assert_match(/\(Views: [\d.]+ms \| ActiveRecord: 0.0ms\)/, @logger.logged(:info)[1]) + end + + def test_log_with_active_record_when_post + post :create + wait + assert_match(/ActiveRecord: ([1-9][\d.]+)ms\)/, @logger.logged(:info)[2]) + end + + def test_log_with_active_record_when_redirecting + get :redirect + wait + assert_equal 3, @logger.logged(:info).size + assert_match(/\(ActiveRecord: [\d.]+ms\)/, @logger.logged(:info)[2]) + end + + def test_include_time_query_time_after_rendering + get :db_after_render + wait + + assert_equal 2, @logger.logged(:info).size + assert_match(/\(Views: [\d.]+ms \| ActiveRecord: ([1-9][\d.]+)ms\)/, @logger.logged(:info)[1]) + end +end diff --git a/actionview/test/activerecord/form_helper_activerecord_test.rb b/actionview/test/activerecord/form_helper_activerecord_test.rb new file mode 100644 index 0000000000..2e302c65a7 --- /dev/null +++ b/actionview/test/activerecord/form_helper_activerecord_test.rb @@ -0,0 +1,91 @@ +require 'active_record_unit' +require 'fixtures/project' +require 'fixtures/developer' + +class FormHelperActiveRecordTest < ActionView::TestCase + tests ActionView::Helpers::FormHelper + + def form_for(*) + @output_buffer = super + end + + def setup + @developer = Developer.new + @developer.id = 123 + @developer.name = "developer #123" + + @project = Project.new + @project.id = 321 + @project.name = "project #321" + @project.save + + @developer.projects << @project + @developer.save + end + + def teardown + Project.delete(321) + Developer.delete(123) + end + + Routes = ActionDispatch::Routing::RouteSet.new + Routes.draw do + resources :developers do + resources :projects + end + end + + def _routes + Routes + end + + include Routes.url_helpers + + def test_nested_fields_for_with_child_index_option_override_on_a_nested_attributes_collection_association + form_for(@developer) do |f| + concat f.fields_for(:projects, @developer.projects.first, :child_index => 'abc') { |cf| + concat cf.text_field(:name) + } + end + + expected = whole_form('/developers/123', 'edit_developer_123', 'edit_developer', :method => 'patch') do + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + protected + + def hidden_fields(method = nil) + txt = %{
} + txt << %{} + if method && !%w(get post).include?(method.to_s) + txt << %{} + end + txt << %{
} + end + + def form_text(action = "/", id = nil, html_class = nil, remote = nil, multipart = nil, method = nil) + txt = %{
} + end + + def whole_form(action = "/", id = nil, html_class = nil, options = nil) + contents = block_given? ? yield : "" + + if options.is_a?(Hash) + method, remote, multipart = options.values_at(:method, :remote, :multipart) + else + method = options + end + + form_text(action, id, html_class, remote, multipart, method) + hidden_fields(method) + contents + "
" + end +end \ No newline at end of file diff --git a/actionview/test/activerecord/polymorphic_routes_test.rb b/actionview/test/activerecord/polymorphic_routes_test.rb new file mode 100644 index 0000000000..afb714484b --- /dev/null +++ b/actionview/test/activerecord/polymorphic_routes_test.rb @@ -0,0 +1,546 @@ +require 'active_record_unit' +require 'fixtures/project' + +class Task < ActiveRecord::Base + self.table_name = 'projects' +end + +class Step < ActiveRecord::Base + self.table_name = 'projects' +end + +class Bid < ActiveRecord::Base + self.table_name = 'projects' +end + +class Tax < ActiveRecord::Base + self.table_name = 'projects' +end + +class Fax < ActiveRecord::Base + self.table_name = 'projects' +end + +class Series < ActiveRecord::Base + self.table_name = 'projects' +end + +class ModelDelegator < ActiveRecord::Base + self.table_name = 'projects' + + def to_model + ModelDelegate.new + end +end + +class ModelDelegate + def self.model_name + ActiveModel::Name.new(self) + end + + def to_param + 'overridden' + end +end + +module Blog + class Post < ActiveRecord::Base + self.table_name = 'projects' + end + + class Blog < ActiveRecord::Base + self.table_name = 'projects' + end + + def self.use_relative_model_naming? + true + end +end + +class PolymorphicRoutesTest < ActionController::TestCase + include SharedTestRoutes.url_helpers + self.default_url_options[:host] = 'example.com' + + def setup + @project = Project.new + @task = Task.new + @step = Step.new + @bid = Bid.new + @tax = Tax.new + @fax = Fax.new + @delegator = ModelDelegator.new + @series = Series.new + @blog_post = Blog::Post.new + @blog_blog = Blog::Blog.new + end + + def test_passing_routes_proxy + with_namespaced_routes(:blog) do + proxy = ActionDispatch::Routing::RoutesProxy.new(_routes, self) + @blog_post.save + assert_equal "http://example.com/posts/#{@blog_post.id}", polymorphic_url([proxy, @blog_post]) + end + end + + def test_namespaced_model + with_namespaced_routes(:blog) do + @blog_post.save + assert_equal "http://example.com/posts/#{@blog_post.id}", polymorphic_url(@blog_post) + end + end + + def test_namespaced_model_with_name_the_same_as_namespace + with_namespaced_routes(:blog) do + @blog_blog.save + assert_equal "http://example.com/blogs/#{@blog_blog.id}", polymorphic_url(@blog_blog) + end + end + + def test_namespaced_model_with_nested_resources + with_namespaced_routes(:blog) do + @blog_post.save + @blog_blog.save + assert_equal "http://example.com/blogs/#{@blog_blog.id}/posts/#{@blog_post.id}", polymorphic_url([@blog_blog, @blog_post]) + end + end + + def test_with_nil + with_test_routes do + assert_raise ArgumentError, "Nil location provided. Can't build URI." do + polymorphic_url(nil) + end + end + end + + def test_with_record + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}", polymorphic_url(@project) + end + end + + def test_with_class + with_test_routes do + assert_equal "http://example.com/projects", polymorphic_url(@project.class) + end + end + + def test_with_new_record + with_test_routes do + assert_equal "http://example.com/projects", polymorphic_url(@project) + end + end + + def test_with_destroyed_record + with_test_routes do + @project.destroy + assert_equal "http://example.com/projects", polymorphic_url(@project) + end + end + + def test_with_record_and_action + with_test_routes do + assert_equal "http://example.com/projects/new", polymorphic_url(@project, :action => 'new') + end + end + + def test_url_helper_prefixed_with_new + with_test_routes do + assert_equal "http://example.com/projects/new", new_polymorphic_url(@project) + end + end + + def test_url_helper_prefixed_with_edit + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}/edit", edit_polymorphic_url(@project) + end + end + + def test_url_helper_prefixed_with_edit_with_url_options + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}/edit?param1=10", edit_polymorphic_url(@project, :param1 => '10') + end + end + + def test_url_helper_with_url_options + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}?param1=10", polymorphic_url(@project, :param1 => '10') + end + end + + def test_format_option + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}.pdf", polymorphic_url(@project, :format => :pdf) + end + end + + def test_format_option_with_url_options + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}.pdf?param1=10", polymorphic_url(@project, :format => :pdf, :param1 => '10') + end + end + + def test_id_and_format_option + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}.pdf", polymorphic_url(:id => @project, :format => :pdf) + end + end + + def test_with_nested + with_test_routes do + @project.save + @task.save + assert_equal "http://example.com/projects/#{@project.id}/tasks/#{@task.id}", polymorphic_url([@project, @task]) + end + end + + def test_with_nested_unsaved + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}/tasks", polymorphic_url([@project, @task]) + end + end + + def test_with_nested_destroyed + with_test_routes do + @project.save + @task.destroy + assert_equal "http://example.com/projects/#{@project.id}/tasks", polymorphic_url([@project, @task]) + end + end + + def test_with_nested_class + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}/tasks", polymorphic_url([@project, @task.class]) + end + end + + def test_class_with_array_and_namespace + with_admin_test_routes do + assert_equal "http://example.com/admin/projects", polymorphic_url([:admin, @project.class]) + end + end + + def test_new_with_array_and_namespace + with_admin_test_routes do + assert_equal "http://example.com/admin/projects/new", polymorphic_url([:admin, @project], :action => 'new') + end + end + + def test_unsaved_with_array_and_namespace + with_admin_test_routes do + assert_equal "http://example.com/admin/projects", polymorphic_url([:admin, @project]) + end + end + + def test_nested_unsaved_with_array_and_namespace + with_admin_test_routes do + @project.save + assert_equal "http://example.com/admin/projects/#{@project.id}/tasks", polymorphic_url([:admin, @project, @task]) + end + end + + def test_nested_with_array_and_namespace + with_admin_test_routes do + @project.save + @task.save + assert_equal "http://example.com/admin/projects/#{@project.id}/tasks/#{@task.id}", polymorphic_url([:admin, @project, @task]) + end + end + + def test_ordering_of_nesting_and_namespace + with_admin_and_site_test_routes do + @project.save + @task.save + @step.save + assert_equal "http://example.com/admin/projects/#{@project.id}/site/tasks/#{@task.id}/steps/#{@step.id}", polymorphic_url([:admin, @project, :site, @task, @step]) + end + end + + def test_nesting_with_array_ending_in_singleton_resource + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}/bid", polymorphic_url([@project, :bid]) + end + end + + def test_nesting_with_array_containing_singleton_resource + with_test_routes do + @project.save + @task.save + assert_equal "http://example.com/projects/#{@project.id}/bid/tasks/#{@task.id}", polymorphic_url([@project, :bid, @task]) + end + end + + def test_nesting_with_array_containing_singleton_resource_and_format + with_test_routes do + @project.save + @task.save + assert_equal "http://example.com/projects/#{@project.id}/bid/tasks/#{@task.id}.pdf", polymorphic_url([@project, :bid, @task], :format => :pdf) + end + end + + def test_nesting_with_array_containing_namespace_and_singleton_resource + with_admin_test_routes do + @project.save + @task.save + assert_equal "http://example.com/admin/projects/#{@project.id}/bid/tasks/#{@task.id}", polymorphic_url([:admin, @project, :bid, @task]) + end + end + + def test_nesting_with_array_containing_nil + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}/bid", polymorphic_url([@project, nil, :bid]) + end + end + + def test_with_array_containing_single_object + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}", polymorphic_url([nil, @project]) + end + end + + def test_with_array_containing_single_name + with_test_routes do + @project.save + assert_equal "http://example.com/projects", polymorphic_url([:projects]) + end + end + + def test_with_array_containing_symbols + with_test_routes do + assert_equal "http://example.com/series/new", polymorphic_url([:new, :series]) + end + end + + def test_with_hash + with_test_routes do + @project.save + assert_equal "http://example.com/projects/#{@project.id}", polymorphic_url(:id => @project) + end + end + + def test_polymorphic_path_accepts_options + with_test_routes do + assert_equal "/projects/new", polymorphic_path(@project, :action => 'new') + end + end + + def test_polymorphic_path_does_not_modify_arguments + with_admin_test_routes do + @project.save + @task.save + + options = {} + object_array = [:admin, @project, @task] + original_args = [object_array.dup, options.dup] + + assert_no_difference('object_array.size') { polymorphic_path(object_array, options) } + assert_equal original_args, [object_array, options] + end + end + + # Tests for names where .plural.singular doesn't round-trip + def test_with_irregular_plural_record + with_test_routes do + @tax.save + assert_equal "http://example.com/taxes/#{@tax.id}", polymorphic_url(@tax) + end + end + + def test_with_irregular_plural_class + with_test_routes do + assert_equal "http://example.com/taxes", polymorphic_url(@tax.class) + end + end + + def test_with_irregular_plural_new_record + with_test_routes do + assert_equal "http://example.com/taxes", polymorphic_url(@tax) + end + end + + def test_with_irregular_plural_destroyed_record + with_test_routes do + @tax.destroy + assert_equal "http://example.com/taxes", polymorphic_url(@tax) + end + end + + def test_with_irregular_plural_record_and_action + with_test_routes do + assert_equal "http://example.com/taxes/new", polymorphic_url(@tax, :action => 'new') + end + end + + def test_irregular_plural_url_helper_prefixed_with_new + with_test_routes do + assert_equal "http://example.com/taxes/new", new_polymorphic_url(@tax) + end + end + + def test_irregular_plural_url_helper_prefixed_with_edit + with_test_routes do + @tax.save + assert_equal "http://example.com/taxes/#{@tax.id}/edit", edit_polymorphic_url(@tax) + end + end + + def test_with_nested_irregular_plurals + with_test_routes do + @tax.save + @fax.save + assert_equal "http://example.com/taxes/#{@tax.id}/faxes/#{@fax.id}", polymorphic_url([@tax, @fax]) + end + end + + def test_with_nested_unsaved_irregular_plurals + with_test_routes do + @tax.save + assert_equal "http://example.com/taxes/#{@tax.id}/faxes", polymorphic_url([@tax, @fax]) + end + end + + def test_new_with_irregular_plural_array_and_namespace + with_admin_test_routes do + assert_equal "http://example.com/admin/taxes/new", polymorphic_url([:admin, @tax], :action => 'new') + end + end + + def test_class_with_irregular_plural_array_and_namespace + with_admin_test_routes do + assert_equal "http://example.com/admin/taxes", polymorphic_url([:admin, @tax.class]) + end + end + + def test_unsaved_with_irregular_plural_array_and_namespace + with_admin_test_routes do + assert_equal "http://example.com/admin/taxes", polymorphic_url([:admin, @tax]) + end + end + + def test_nesting_with_irregular_plurals_and_array_ending_in_singleton_resource + with_test_routes do + @tax.save + assert_equal "http://example.com/taxes/#{@tax.id}/bid", polymorphic_url([@tax, :bid]) + end + end + + def test_with_array_containing_single_irregular_plural_object + with_test_routes do + @tax.save + assert_equal "http://example.com/taxes/#{@tax.id}", polymorphic_url([nil, @tax]) + end + end + + def test_with_array_containing_single_name_irregular_plural + with_test_routes do + @tax.save + assert_equal "http://example.com/taxes", polymorphic_url([:taxes]) + end + end + + # Tests for uncountable names + def test_uncountable_resource + with_test_routes do + @series.save + assert_equal "http://example.com/series/#{@series.id}", polymorphic_url(@series) + assert_equal "http://example.com/series", polymorphic_url(Series.new) + end + end + + def test_routing_a_to_model_delegate + with_test_routes do + @delegator.save + assert_equal "http://example.com/model_delegates/overridden", polymorphic_url(@delegator) + end + end + + def with_namespaced_routes(name) + with_routing do |set| + set.draw do + scope(:module => name) do + resources :blogs do + resources :posts + end + resources :posts + end + end + + self.class.send(:include, @routes.url_helpers) + yield + end + end + + def with_test_routes(options = {}) + with_routing do |set| + set.draw do + resources :projects do + resources :tasks + resource :bid do + resources :tasks + end + end + resources :taxes do + resources :faxes + resource :bid + end + resources :series + resources :model_delegates + end + + self.class.send(:include, @routes.url_helpers) + yield + end + end + + def with_admin_test_routes(options = {}) + with_routing do |set| + set.draw do + namespace :admin do + resources :projects do + resources :tasks + resource :bid do + resources :tasks + end + end + resources :taxes do + resources :faxes + end + resources :series + end + end + + self.class.send(:include, @routes.url_helpers) + yield + end + end + + def with_admin_and_site_test_routes(options = {}) + with_routing do |set| + set.draw do + namespace :admin do + resources :projects do + namespace :site do + resources :tasks do + resources :steps + end + end + end + end + end + + self.class.send(:include, @routes.url_helpers) + yield + end + end +end diff --git a/actionview/test/activerecord/render_partial_with_record_identification_test.rb b/actionview/test/activerecord/render_partial_with_record_identification_test.rb new file mode 100644 index 0000000000..409370104d --- /dev/null +++ b/actionview/test/activerecord/render_partial_with_record_identification_test.rb @@ -0,0 +1,210 @@ +require 'active_record_unit' + +class RenderPartialWithRecordIdentificationController < ActionController::Base + def render_with_has_many_and_belongs_to_association + @developer = Developer.find(1) + render :partial => @developer.projects + end + + def render_with_has_many_association + @topic = Topic.find(1) + render :partial => @topic.replies + end + + def render_with_scope + render :partial => Reply.base + end + + def render_with_has_many_through_association + @developer = Developer.first + render :partial => @developer.topics + end + + def render_with_has_one_association + @company = Company.find(1) + render :partial => @company.mascot + end + + def render_with_belongs_to_association + @reply = Reply.find(1) + render :partial => @reply.topic + end + + def render_with_record + @developer = Developer.first + render :partial => @developer + end + + def render_with_record_collection + @developers = Developer.all + render :partial => @developers + end + + def render_with_record_collection_and_spacer_template + @developer = Developer.find(1) + render :partial => @developer.projects, :spacer_template => 'test/partial_only' + end +end + +class RenderPartialWithRecordIdentificationTest < ActiveRecordTestCase + tests RenderPartialWithRecordIdentificationController + fixtures :developers, :projects, :developers_projects, :topics, :replies, :companies, :mascots + + def test_rendering_partial_with_has_many_and_belongs_to_association + get :render_with_has_many_and_belongs_to_association + assert_template 'projects/_project' + assert_equal assigns(:developer).projects.map(&:name).join, @response.body + end + + def test_rendering_partial_with_has_many_association + get :render_with_has_many_association + assert_template 'replies/_reply' + assert_equal 'Birdman is better!', @response.body + end + + def test_rendering_partial_with_scope + get :render_with_scope + assert_template 'replies/_reply' + assert_equal 'Birdman is better!Nuh uh!', @response.body + end + + def test_render_with_record + get :render_with_record + assert_template 'developers/_developer' + assert_equal 'David', @response.body + end + + def test_render_with_record_collection + get :render_with_record_collection + assert_template 'developers/_developer' + assert_equal 'DavidJamisfixture_3fixture_4fixture_5fixture_6fixture_7fixture_8fixture_9fixture_10Jamis', @response.body + end + + def test_render_with_record_collection_and_spacer_template + get :render_with_record_collection_and_spacer_template + assert_equal assigns(:developer).projects.map(&:name).join('only partial'), @response.body + end + + def test_rendering_partial_with_has_one_association + mascot = Company.find(1).mascot + get :render_with_has_one_association + assert_template 'mascots/_mascot' + assert_equal mascot.name, @response.body + end +end + +class Game < Struct.new(:name, :id) + extend ActiveModel::Naming + include ActiveModel::Conversion + def to_param + id.to_s + end +end + +module Fun + class NestedController < ActionController::Base + def render_with_record_in_nested_controller + render :partial => Game.new("Pong") + end + + def render_with_record_collection_in_nested_controller + render :partial => [ Game.new("Pong"), Game.new("Tank") ] + end + end + + module Serious + class NestedDeeperController < ActionController::Base + def render_with_record_in_deeper_nested_controller + render :partial => Game.new("Chess") + end + + def render_with_record_collection_in_deeper_nested_controller + render :partial => [ Game.new("Chess"), Game.new("Sudoku"), Game.new("Solitaire") ] + end + end + end +end + +class RenderPartialWithRecordIdentificationAndNestedControllersTest < ActiveRecordTestCase + tests Fun::NestedController + + def test_render_with_record_in_nested_controller + get :render_with_record_in_nested_controller + assert_template %r{\Afun/games/_game\Z} + assert_equal "Fun Pong\n", @response.body + end + + def test_render_with_record_collection_in_nested_controller + get :render_with_record_collection_in_nested_controller + assert_template %r{\Afun/games/_game\Z} + assert_equal "Fun Pong\nFun Tank\n", @response.body + end +end + +class RenderPartialWithRecordIdentificationAndNestedControllersWithoutPrefixTest < ActiveRecordTestCase + tests Fun::NestedController + + def test_render_with_record_in_nested_controller + old_config = ActionView::Base.prefix_partial_path_with_controller_namespace + ActionView::Base.prefix_partial_path_with_controller_namespace = false + + get :render_with_record_in_nested_controller + assert_template %r{\Agames/_game\Z} + assert_equal "Just Pong\n", @response.body + ensure + ActionView::Base.prefix_partial_path_with_controller_namespace = old_config + end + + def test_render_with_record_collection_in_nested_controller + old_config = ActionView::Base.prefix_partial_path_with_controller_namespace + ActionView::Base.prefix_partial_path_with_controller_namespace = false + + get :render_with_record_collection_in_nested_controller + assert_template %r{\Agames/_game\Z} + assert_equal "Just Pong\nJust Tank\n", @response.body + ensure + ActionView::Base.prefix_partial_path_with_controller_namespace = old_config + end +end + +class RenderPartialWithRecordIdentificationAndNestedDeeperControllersTest < ActiveRecordTestCase + tests Fun::Serious::NestedDeeperController + + def test_render_with_record_in_deeper_nested_controller + get :render_with_record_in_deeper_nested_controller + assert_template %r{\Afun/serious/games/_game\Z} + assert_equal "Serious Chess\n", @response.body + end + + def test_render_with_record_collection_in_deeper_nested_controller + get :render_with_record_collection_in_deeper_nested_controller + assert_template %r{\Afun/serious/games/_game\Z} + assert_equal "Serious Chess\nSerious Sudoku\nSerious Solitaire\n", @response.body + end +end + +class RenderPartialWithRecordIdentificationAndNestedDeeperControllersWithoutPrefixTest < ActiveRecordTestCase + tests Fun::Serious::NestedDeeperController + + def test_render_with_record_in_deeper_nested_controller + old_config = ActionView::Base.prefix_partial_path_with_controller_namespace + ActionView::Base.prefix_partial_path_with_controller_namespace = false + + get :render_with_record_in_deeper_nested_controller + assert_template %r{\Agames/_game\Z} + assert_equal "Just Chess\n", @response.body + ensure + ActionView::Base.prefix_partial_path_with_controller_namespace = old_config + end + + def test_render_with_record_collection_in_deeper_nested_controller + old_config = ActionView::Base.prefix_partial_path_with_controller_namespace + ActionView::Base.prefix_partial_path_with_controller_namespace = false + + get :render_with_record_collection_in_deeper_nested_controller + assert_template %r{\Agames/_game\Z} + assert_equal "Just Chess\nJust Sudoku\nJust Solitaire\n", @response.body + ensure + ActionView::Base.prefix_partial_path_with_controller_namespace = old_config + end +end diff --git a/actionview/test/fixtures/_top_level_partial.html.erb b/actionview/test/fixtures/_top_level_partial.html.erb new file mode 100644 index 0000000000..0b1c2e46e0 --- /dev/null +++ b/actionview/test/fixtures/_top_level_partial.html.erb @@ -0,0 +1 @@ +top level partial html \ No newline at end of file diff --git a/actionview/test/fixtures/_top_level_partial_only.erb b/actionview/test/fixtures/_top_level_partial_only.erb new file mode 100644 index 0000000000..44f25b61d0 --- /dev/null +++ b/actionview/test/fixtures/_top_level_partial_only.erb @@ -0,0 +1 @@ +top level partial \ No newline at end of file diff --git a/actionview/test/fixtures/alternate_helpers/foo_helper.rb b/actionview/test/fixtures/alternate_helpers/foo_helper.rb new file mode 100644 index 0000000000..2528584473 --- /dev/null +++ b/actionview/test/fixtures/alternate_helpers/foo_helper.rb @@ -0,0 +1,3 @@ +module FooHelper + redefine_method(:baz) {} +end diff --git a/actionview/test/fixtures/bad_customers/_bad_customer.html.erb b/actionview/test/fixtures/bad_customers/_bad_customer.html.erb new file mode 100644 index 0000000000..d22af431ec --- /dev/null +++ b/actionview/test/fixtures/bad_customers/_bad_customer.html.erb @@ -0,0 +1 @@ +<%= greeting %> bad customer: <%= bad_customer.name %><%= bad_customer_counter %> \ No newline at end of file diff --git a/actionview/test/fixtures/blog_public/.gitignore b/actionview/test/fixtures/blog_public/.gitignore new file mode 100644 index 0000000000..312e635ee6 --- /dev/null +++ b/actionview/test/fixtures/blog_public/.gitignore @@ -0,0 +1 @@ +absolute/* diff --git a/actionview/test/fixtures/blog_public/blog.html b/actionview/test/fixtures/blog_public/blog.html new file mode 100644 index 0000000000..79ad44c010 --- /dev/null +++ b/actionview/test/fixtures/blog_public/blog.html @@ -0,0 +1 @@ +/blog/blog.html \ No newline at end of file diff --git a/actionview/test/fixtures/blog_public/index.html b/actionview/test/fixtures/blog_public/index.html new file mode 100644 index 0000000000..2de3825481 --- /dev/null +++ b/actionview/test/fixtures/blog_public/index.html @@ -0,0 +1 @@ +/blog/index.html \ No newline at end of file diff --git a/actionview/test/fixtures/blog_public/subdir/index.html b/actionview/test/fixtures/blog_public/subdir/index.html new file mode 100644 index 0000000000..517bded335 --- /dev/null +++ b/actionview/test/fixtures/blog_public/subdir/index.html @@ -0,0 +1 @@ +/blog/subdir/index.html \ No newline at end of file diff --git a/actionview/test/fixtures/comments/empty.de.html.erb b/actionview/test/fixtures/comments/empty.de.html.erb new file mode 100644 index 0000000000..cffd90dd26 --- /dev/null +++ b/actionview/test/fixtures/comments/empty.de.html.erb @@ -0,0 +1 @@ +

Kein Kommentar

\ No newline at end of file diff --git a/actionview/test/fixtures/comments/empty.html.builder b/actionview/test/fixtures/comments/empty.html.builder new file mode 100644 index 0000000000..2b0c7207a3 --- /dev/null +++ b/actionview/test/fixtures/comments/empty.html.builder @@ -0,0 +1 @@ +xml.h1 'No Comment' \ No newline at end of file diff --git a/actionview/test/fixtures/comments/empty.html.erb b/actionview/test/fixtures/comments/empty.html.erb new file mode 100644 index 0000000000..827f3861de --- /dev/null +++ b/actionview/test/fixtures/comments/empty.html.erb @@ -0,0 +1 @@ +

No Comment

\ No newline at end of file diff --git a/actionview/test/fixtures/comments/empty.xml.erb b/actionview/test/fixtures/comments/empty.xml.erb new file mode 100644 index 0000000000..db1027cd7d --- /dev/null +++ b/actionview/test/fixtures/comments/empty.xml.erb @@ -0,0 +1 @@ +No Comment \ No newline at end of file diff --git a/actionview/test/fixtures/companies.yml b/actionview/test/fixtures/companies.yml new file mode 100644 index 0000000000..ed2992e0b1 --- /dev/null +++ b/actionview/test/fixtures/companies.yml @@ -0,0 +1,24 @@ +thirty_seven_signals: + id: 1 + name: 37Signals + rating: 4 + +TextDrive: + id: 2 + name: TextDrive + rating: 4 + +PlanetArgon: + id: 3 + name: Planet Argon + rating: 4 + +Google: + id: 4 + name: Google + rating: 4 + +Ionist: + id: 5 + name: Ioni.st + rating: 4 \ No newline at end of file diff --git a/actionview/test/fixtures/company.rb b/actionview/test/fixtures/company.rb new file mode 100644 index 0000000000..f3ac3642fa --- /dev/null +++ b/actionview/test/fixtures/company.rb @@ -0,0 +1,9 @@ +class Company < ActiveRecord::Base + has_one :mascot + self.sequence_name = :companies_nonstd_seq + + validates_presence_of :name + def validate + errors.add('rating', 'rating should not be 2') if rating == 2 + end +end diff --git a/actionview/test/fixtures/custom_pattern/another.html.erb b/actionview/test/fixtures/custom_pattern/another.html.erb new file mode 100644 index 0000000000..6d7f3bafbb --- /dev/null +++ b/actionview/test/fixtures/custom_pattern/another.html.erb @@ -0,0 +1 @@ +Hello custom patterns! \ No newline at end of file diff --git a/actionview/test/fixtures/custom_pattern/html/another.erb b/actionview/test/fixtures/custom_pattern/html/another.erb new file mode 100644 index 0000000000..dbd7e96ab6 --- /dev/null +++ b/actionview/test/fixtures/custom_pattern/html/another.erb @@ -0,0 +1 @@ +Another template! \ No newline at end of file diff --git a/actionview/test/fixtures/custom_pattern/html/path.erb b/actionview/test/fixtures/custom_pattern/html/path.erb new file mode 100644 index 0000000000..6d7f3bafbb --- /dev/null +++ b/actionview/test/fixtures/custom_pattern/html/path.erb @@ -0,0 +1 @@ +Hello custom patterns! \ No newline at end of file diff --git a/actionview/test/fixtures/customers/_customer.html.erb b/actionview/test/fixtures/customers/_customer.html.erb new file mode 100644 index 0000000000..483571e22a --- /dev/null +++ b/actionview/test/fixtures/customers/_customer.html.erb @@ -0,0 +1 @@ +<%= greeting %>: <%= customer.name %> \ No newline at end of file diff --git a/actionview/test/fixtures/db_definitions/sqlite.sql b/actionview/test/fixtures/db_definitions/sqlite.sql new file mode 100644 index 0000000000..99df4b3e61 --- /dev/null +++ b/actionview/test/fixtures/db_definitions/sqlite.sql @@ -0,0 +1,49 @@ +CREATE TABLE 'companies' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT DEFAULT NULL, + 'rating' INTEGER DEFAULT 1 +); + +CREATE TABLE 'replies' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'content' text, + 'created_at' datetime, + 'updated_at' datetime, + 'topic_id' integer, + 'developer_id' integer +); + +CREATE TABLE 'topics' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'title' varchar(255), + 'subtitle' varchar(255), + 'content' text, + 'created_at' datetime, + 'updated_at' datetime +); + +CREATE TABLE 'developers' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT DEFAULT NULL, + 'salary' INTEGER DEFAULT 70000, + 'created_at' DATETIME DEFAULT NULL, + 'updated_at' DATETIME DEFAULT NULL +); + +CREATE TABLE 'projects' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'name' TEXT DEFAULT NULL +); + +CREATE TABLE 'developers_projects' ( + 'developer_id' INTEGER NOT NULL, + 'project_id' INTEGER NOT NULL, + 'joined_on' DATE DEFAULT NULL, + 'access_level' INTEGER DEFAULT 1 +); + +CREATE TABLE 'mascots' ( + 'id' INTEGER PRIMARY KEY NOT NULL, + 'company_id' INTEGER NOT NULL, + 'name' TEXT DEFAULT NULL +); \ No newline at end of file diff --git a/actionview/test/fixtures/developer.rb b/actionview/test/fixtures/developer.rb new file mode 100644 index 0000000000..4941463015 --- /dev/null +++ b/actionview/test/fixtures/developer.rb @@ -0,0 +1,10 @@ +class Developer < ActiveRecord::Base + has_and_belongs_to_many :projects + has_many :replies + has_many :topics, :through => :replies + accepts_nested_attributes_for :projects +end + +class DeVeLoPeR < ActiveRecord::Base + self.table_name = "developers" +end diff --git a/actionview/test/fixtures/developers.yml b/actionview/test/fixtures/developers.yml new file mode 100644 index 0000000000..3656564f63 --- /dev/null +++ b/actionview/test/fixtures/developers.yml @@ -0,0 +1,21 @@ +david: + id: 1 + name: David + salary: 80000 + +jamis: + id: 2 + name: Jamis + salary: 150000 + +<% (3..10).each do |digit| %> +dev_<%= digit %>: + id: <%= digit %> + name: fixture_<%= digit %> + salary: 100000 +<% end %> + +poor_jamis: + id: 11 + name: Jamis + salary: 9000 \ No newline at end of file diff --git a/actionview/test/fixtures/developers/_developer.erb b/actionview/test/fixtures/developers/_developer.erb new file mode 100644 index 0000000000..904a3137e7 --- /dev/null +++ b/actionview/test/fixtures/developers/_developer.erb @@ -0,0 +1 @@ +<%= developer.name %> \ No newline at end of file diff --git a/actionview/test/fixtures/developers_projects.yml b/actionview/test/fixtures/developers_projects.yml new file mode 100644 index 0000000000..cee359c7cf --- /dev/null +++ b/actionview/test/fixtures/developers_projects.yml @@ -0,0 +1,13 @@ +david_action_controller: + developer_id: 1 + project_id: 2 + joined_on: 2004-10-10 + +david_active_record: + developer_id: 1 + project_id: 1 + joined_on: 2004-10-10 + +jamis_active_record: + developer_id: 2 + project_id: 1 \ No newline at end of file diff --git a/actionview/test/fixtures/digestor/comments/_comment.html.erb b/actionview/test/fixtures/digestor/comments/_comment.html.erb new file mode 100644 index 0000000000..f172e749da --- /dev/null +++ b/actionview/test/fixtures/digestor/comments/_comment.html.erb @@ -0,0 +1 @@ +Great story, bro! diff --git a/actionview/test/fixtures/digestor/comments/_comments.html.erb b/actionview/test/fixtures/digestor/comments/_comments.html.erb new file mode 100644 index 0000000000..c28646a283 --- /dev/null +++ b/actionview/test/fixtures/digestor/comments/_comments.html.erb @@ -0,0 +1 @@ +<%= render partial: "comments/comment", collection: commentable.comments %> diff --git a/actionview/test/fixtures/digestor/events/_event.html.erb b/actionview/test/fixtures/digestor/events/_event.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actionview/test/fixtures/digestor/level/below/_header.html.erb b/actionview/test/fixtures/digestor/level/below/_header.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actionview/test/fixtures/digestor/level/below/index.html.erb b/actionview/test/fixtures/digestor/level/below/index.html.erb new file mode 100644 index 0000000000..b92f49a8f8 --- /dev/null +++ b/actionview/test/fixtures/digestor/level/below/index.html.erb @@ -0,0 +1 @@ +<%= render partial: "header" %> diff --git a/actionview/test/fixtures/digestor/messages/_form.html.erb b/actionview/test/fixtures/digestor/messages/_form.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actionview/test/fixtures/digestor/messages/_header.html.erb b/actionview/test/fixtures/digestor/messages/_header.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actionview/test/fixtures/digestor/messages/_message.html.erb b/actionview/test/fixtures/digestor/messages/_message.html.erb new file mode 100644 index 0000000000..406a0fb848 --- /dev/null +++ b/actionview/test/fixtures/digestor/messages/_message.html.erb @@ -0,0 +1 @@ +THIS BE WHERE THEM MESSAGE GO, YO! \ No newline at end of file diff --git a/actionview/test/fixtures/digestor/messages/actions/_move.html.erb b/actionview/test/fixtures/digestor/messages/actions/_move.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actionview/test/fixtures/digestor/messages/edit.html.erb b/actionview/test/fixtures/digestor/messages/edit.html.erb new file mode 100644 index 0000000000..a9e0a88e32 --- /dev/null +++ b/actionview/test/fixtures/digestor/messages/edit.html.erb @@ -0,0 +1,5 @@ +<%= render "header" %> +<%= render partial: "form" %> +<%= render @message %> +<%= render ( @message.events ) %> +<%= render :partial => "comments/comment", :collection => @message.comments %> diff --git a/actionview/test/fixtures/digestor/messages/index.html.erb b/actionview/test/fixtures/digestor/messages/index.html.erb new file mode 100644 index 0000000000..1937b652e4 --- /dev/null +++ b/actionview/test/fixtures/digestor/messages/index.html.erb @@ -0,0 +1,2 @@ +<%= render @messages %> +<%= render @events %> diff --git a/actionview/test/fixtures/digestor/messages/show.html.erb b/actionview/test/fixtures/digestor/messages/show.html.erb new file mode 100644 index 0000000000..51b3b61e8e --- /dev/null +++ b/actionview/test/fixtures/digestor/messages/show.html.erb @@ -0,0 +1,13 @@ +<%# Template Dependency: messages/message %> +<%= render "header" %> +<%= render "comments/comments" %> + +<%= render "messages/actions/move" %> + +<%= render @message.history.events %> + +<%# render "something_missing" %> + +<% + # Template Dependency: messages/form +%> \ No newline at end of file diff --git a/actionview/test/fixtures/filter_test/implicit_actions/edit.html.erb b/actionview/test/fixtures/filter_test/implicit_actions/edit.html.erb new file mode 100644 index 0000000000..8491ab9f80 --- /dev/null +++ b/actionview/test/fixtures/filter_test/implicit_actions/edit.html.erb @@ -0,0 +1 @@ +edit \ No newline at end of file diff --git a/actionview/test/fixtures/filter_test/implicit_actions/show.html.erb b/actionview/test/fixtures/filter_test/implicit_actions/show.html.erb new file mode 100644 index 0000000000..0a89cecf05 --- /dev/null +++ b/actionview/test/fixtures/filter_test/implicit_actions/show.html.erb @@ -0,0 +1 @@ +show \ No newline at end of file diff --git a/actionview/test/fixtures/fun/games/_form.erb b/actionview/test/fixtures/fun/games/_form.erb new file mode 100644 index 0000000000..01107f1cb2 --- /dev/null +++ b/actionview/test/fixtures/fun/games/_form.erb @@ -0,0 +1 @@ +<%= form.label :title %> diff --git a/actionview/test/fixtures/fun/games/_game.erb b/actionview/test/fixtures/fun/games/_game.erb new file mode 100644 index 0000000000..f0f542ff92 --- /dev/null +++ b/actionview/test/fixtures/fun/games/_game.erb @@ -0,0 +1 @@ +Fun <%= game.name %> diff --git a/actionview/test/fixtures/fun/games/hello_world.erb b/actionview/test/fixtures/fun/games/hello_world.erb new file mode 100644 index 0000000000..1ebfbe2539 --- /dev/null +++ b/actionview/test/fixtures/fun/games/hello_world.erb @@ -0,0 +1 @@ +Living in a nested world \ No newline at end of file diff --git a/actionview/test/fixtures/fun/serious/games/_game.erb b/actionview/test/fixtures/fun/serious/games/_game.erb new file mode 100644 index 0000000000..523bc55bd7 --- /dev/null +++ b/actionview/test/fixtures/fun/serious/games/_game.erb @@ -0,0 +1 @@ +Serious <%= game.name %> diff --git a/actionview/test/fixtures/functional_caching/_partial.erb b/actionview/test/fixtures/functional_caching/_partial.erb new file mode 100644 index 0000000000..ec0da7cf50 --- /dev/null +++ b/actionview/test/fixtures/functional_caching/_partial.erb @@ -0,0 +1,3 @@ +<% cache do %> +Old fragment caching in a partial +<% end %> diff --git a/actionview/test/fixtures/functional_caching/formatted_fragment_cached.html.erb b/actionview/test/fixtures/functional_caching/formatted_fragment_cached.html.erb new file mode 100644 index 0000000000..9b88fa1f5a --- /dev/null +++ b/actionview/test/fixtures/functional_caching/formatted_fragment_cached.html.erb @@ -0,0 +1,3 @@ + +<%= cache do %>

ERB

<% end %> + diff --git a/actionview/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder b/actionview/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder new file mode 100644 index 0000000000..efdcc28e0f --- /dev/null +++ b/actionview/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder @@ -0,0 +1,5 @@ +xml.body do + cache do + xml.p "Builder" + end +end diff --git a/actionview/test/fixtures/functional_caching/fragment_cached.html.erb b/actionview/test/fixtures/functional_caching/fragment_cached.html.erb new file mode 100644 index 0000000000..fa5e6bd318 --- /dev/null +++ b/actionview/test/fixtures/functional_caching/fragment_cached.html.erb @@ -0,0 +1,3 @@ +Hello +<%= cache do %>This bit's fragment cached<% end %> +<%= 'Ciao' %> diff --git a/actionview/test/fixtures/functional_caching/fragment_cached_without_digest.html.erb b/actionview/test/fixtures/functional_caching/fragment_cached_without_digest.html.erb new file mode 100644 index 0000000000..3125583a28 --- /dev/null +++ b/actionview/test/fixtures/functional_caching/fragment_cached_without_digest.html.erb @@ -0,0 +1,3 @@ + +<%= cache 'nodigest', skip_digest: true do %>

ERB

<% end %> + diff --git a/actionview/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb b/actionview/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb new file mode 100644 index 0000000000..a9462d3499 --- /dev/null +++ b/actionview/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb @@ -0,0 +1 @@ +<%= render :partial => 'partial' %> \ No newline at end of file diff --git a/actionview/test/fixtures/functional_caching/inline_fragment_cached.html.erb b/actionview/test/fixtures/functional_caching/inline_fragment_cached.html.erb new file mode 100644 index 0000000000..41647f1404 --- /dev/null +++ b/actionview/test/fixtures/functional_caching/inline_fragment_cached.html.erb @@ -0,0 +1,2 @@ +<%= render :inline => 'Some inline content' %> +<%= cache do %>Some cached content<% end %> diff --git a/actionview/test/fixtures/games/_game.erb b/actionview/test/fixtures/games/_game.erb new file mode 100644 index 0000000000..1aeb81fcba --- /dev/null +++ b/actionview/test/fixtures/games/_game.erb @@ -0,0 +1 @@ +Just <%= game.name %> diff --git a/actionview/test/fixtures/good_customers/_good_customer.html.erb b/actionview/test/fixtures/good_customers/_good_customer.html.erb new file mode 100644 index 0000000000..a2d97ebc6d --- /dev/null +++ b/actionview/test/fixtures/good_customers/_good_customer.html.erb @@ -0,0 +1 @@ +<%= greeting %> good customer: <%= good_customer.name %><%= good_customer_counter %> \ No newline at end of file diff --git a/actionview/test/fixtures/happy_path/render_action/hello_world.erb b/actionview/test/fixtures/happy_path/render_action/hello_world.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/happy_path/render_action/hello_world.erb @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/actionview/test/fixtures/hello.html b/actionview/test/fixtures/hello.html new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/hello.html @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/actionview/test/fixtures/helpers/abc_helper.rb b/actionview/test/fixtures/helpers/abc_helper.rb new file mode 100644 index 0000000000..7104ff3730 --- /dev/null +++ b/actionview/test/fixtures/helpers/abc_helper.rb @@ -0,0 +1,5 @@ +module AbcHelper + def bare_a() end + def bare_b() end + def bare_c() end +end diff --git a/actionview/test/fixtures/helpers/fun/games_helper.rb b/actionview/test/fixtures/helpers/fun/games_helper.rb new file mode 100644 index 0000000000..3b7adce086 --- /dev/null +++ b/actionview/test/fixtures/helpers/fun/games_helper.rb @@ -0,0 +1,5 @@ +module Fun + module GamesHelper + def stratego() "Iz guuut!" end + end +end \ No newline at end of file diff --git a/actionview/test/fixtures/helpers/fun/pdf_helper.rb b/actionview/test/fixtures/helpers/fun/pdf_helper.rb new file mode 100644 index 0000000000..0171be8500 --- /dev/null +++ b/actionview/test/fixtures/helpers/fun/pdf_helper.rb @@ -0,0 +1,5 @@ +module Fun + module PdfHelper + def foobar() 'baz' end + end +end diff --git a/actionview/test/fixtures/helpers/helpery_test_helper.rb b/actionview/test/fixtures/helpers/helpery_test_helper.rb new file mode 100644 index 0000000000..a4f2951efa --- /dev/null +++ b/actionview/test/fixtures/helpers/helpery_test_helper.rb @@ -0,0 +1,5 @@ +module HelperyTestHelper + def helpery_test + "Default" + end +end diff --git a/actionview/test/fixtures/helpers/just_me_helper.rb b/actionview/test/fixtures/helpers/just_me_helper.rb new file mode 100644 index 0000000000..b140a7b9b4 --- /dev/null +++ b/actionview/test/fixtures/helpers/just_me_helper.rb @@ -0,0 +1,3 @@ +module JustMeHelper + def me() "mine!" end +end \ No newline at end of file diff --git a/actionview/test/fixtures/helpers/me_too_helper.rb b/actionview/test/fixtures/helpers/me_too_helper.rb new file mode 100644 index 0000000000..ce56042143 --- /dev/null +++ b/actionview/test/fixtures/helpers/me_too_helper.rb @@ -0,0 +1,3 @@ +module MeTooHelper + def me() "me too!" end +end \ No newline at end of file diff --git a/actionview/test/fixtures/helpers1_pack/pack1_helper.rb b/actionview/test/fixtures/helpers1_pack/pack1_helper.rb new file mode 100644 index 0000000000..9faa427736 --- /dev/null +++ b/actionview/test/fixtures/helpers1_pack/pack1_helper.rb @@ -0,0 +1,5 @@ +module Pack1Helper + def conflicting_helper + "pack1" + end +end diff --git a/actionview/test/fixtures/helpers2_pack/pack2_helper.rb b/actionview/test/fixtures/helpers2_pack/pack2_helper.rb new file mode 100644 index 0000000000..cf56697dfb --- /dev/null +++ b/actionview/test/fixtures/helpers2_pack/pack2_helper.rb @@ -0,0 +1,5 @@ +module Pack2Helper + def conflicting_helper + "pack2" + end +end diff --git a/actionview/test/fixtures/layout_tests/alt/hello.erb b/actionview/test/fixtures/layout_tests/alt/hello.erb new file mode 100644 index 0000000000..1055c36659 --- /dev/null +++ b/actionview/test/fixtures/layout_tests/alt/hello.erb @@ -0,0 +1 @@ +alt/hello.erb diff --git a/actionview/test/fixtures/layout_tests/alt/layouts/alt.erb b/actionview/test/fixtures/layout_tests/alt/layouts/alt.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actionview/test/fixtures/layout_tests/layouts/controller_name_space/nested.erb b/actionview/test/fixtures/layout_tests/layouts/controller_name_space/nested.erb new file mode 100644 index 0000000000..121bc079a1 --- /dev/null +++ b/actionview/test/fixtures/layout_tests/layouts/controller_name_space/nested.erb @@ -0,0 +1 @@ +controller_name_space/nested.erb <%= yield %> \ No newline at end of file diff --git a/actionview/test/fixtures/layout_tests/layouts/item.erb b/actionview/test/fixtures/layout_tests/layouts/item.erb new file mode 100644 index 0000000000..60f04d77d5 --- /dev/null +++ b/actionview/test/fixtures/layout_tests/layouts/item.erb @@ -0,0 +1 @@ +item.erb <%= yield %> \ No newline at end of file diff --git a/actionview/test/fixtures/layout_tests/layouts/layout_test.erb b/actionview/test/fixtures/layout_tests/layouts/layout_test.erb new file mode 100644 index 0000000000..b74ac0840d --- /dev/null +++ b/actionview/test/fixtures/layout_tests/layouts/layout_test.erb @@ -0,0 +1 @@ +layout_test.erb <%= yield %> \ No newline at end of file diff --git a/actionview/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb b/actionview/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb new file mode 100644 index 0000000000..3b65e54f9c --- /dev/null +++ b/actionview/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb @@ -0,0 +1 @@ +multiple_extensions.html.erb <%= yield %> diff --git a/actionview/test/fixtures/layout_tests/layouts/symlinked b/actionview/test/fixtures/layout_tests/layouts/symlinked new file mode 120000 index 0000000000..0ddc1154ab --- /dev/null +++ b/actionview/test/fixtures/layout_tests/layouts/symlinked @@ -0,0 +1 @@ +../../symlink_parent \ No newline at end of file diff --git a/actionview/test/fixtures/layout_tests/layouts/third_party_template_library.mab b/actionview/test/fixtures/layout_tests/layouts/third_party_template_library.mab new file mode 100644 index 0000000000..fcee620d82 --- /dev/null +++ b/actionview/test/fixtures/layout_tests/layouts/third_party_template_library.mab @@ -0,0 +1 @@ +layouts/third_party_template_library.mab \ No newline at end of file diff --git a/actionview/test/fixtures/layout_tests/views/goodbye.erb b/actionview/test/fixtures/layout_tests/views/goodbye.erb new file mode 100644 index 0000000000..4ee911188e --- /dev/null +++ b/actionview/test/fixtures/layout_tests/views/goodbye.erb @@ -0,0 +1 @@ +hello.erb \ No newline at end of file diff --git a/actionview/test/fixtures/layout_tests/views/hello.erb b/actionview/test/fixtures/layout_tests/views/hello.erb new file mode 100644 index 0000000000..4ee911188e --- /dev/null +++ b/actionview/test/fixtures/layout_tests/views/hello.erb @@ -0,0 +1 @@ +hello.erb \ No newline at end of file diff --git a/actionview/test/fixtures/layouts/_column.html.erb b/actionview/test/fixtures/layouts/_column.html.erb new file mode 100644 index 0000000000..96db002b8a --- /dev/null +++ b/actionview/test/fixtures/layouts/_column.html.erb @@ -0,0 +1,2 @@ +
<%= yield :column %>
+
<%= yield %>
\ No newline at end of file diff --git a/actionview/test/fixtures/layouts/_customers.erb b/actionview/test/fixtures/layouts/_customers.erb new file mode 100644 index 0000000000..ae63f13cd3 --- /dev/null +++ b/actionview/test/fixtures/layouts/_customers.erb @@ -0,0 +1 @@ +<%= yield Struct.new(:name).new("David") %> \ No newline at end of file diff --git a/actionview/test/fixtures/layouts/_partial_and_yield.erb b/actionview/test/fixtures/layouts/_partial_and_yield.erb new file mode 100644 index 0000000000..74cc428ffa --- /dev/null +++ b/actionview/test/fixtures/layouts/_partial_and_yield.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'test/partial' %> +<%= yield %> diff --git a/actionview/test/fixtures/layouts/_yield_only.erb b/actionview/test/fixtures/layouts/_yield_only.erb new file mode 100644 index 0000000000..37f0bddbd7 --- /dev/null +++ b/actionview/test/fixtures/layouts/_yield_only.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/actionview/test/fixtures/layouts/_yield_with_params.erb b/actionview/test/fixtures/layouts/_yield_with_params.erb new file mode 100644 index 0000000000..68e6557fb8 --- /dev/null +++ b/actionview/test/fixtures/layouts/_yield_with_params.erb @@ -0,0 +1 @@ +<%= yield 'Yield!' %> diff --git a/actionview/test/fixtures/layouts/block_with_layout.erb b/actionview/test/fixtures/layouts/block_with_layout.erb new file mode 100644 index 0000000000..73ac833e52 --- /dev/null +++ b/actionview/test/fixtures/layouts/block_with_layout.erb @@ -0,0 +1,3 @@ +<%= render(:layout => "layout_for_partial", :locals => { :name => "Anthony" }) do %>Inside from first block in layout<% "Return value should be discarded" %><% end %> +<%= yield %> +<%= render(:layout => "layout_for_partial", :locals => { :name => "Ramm" }) do %>Inside from second block in layout<% end %> diff --git a/actionview/test/fixtures/layouts/builder.builder b/actionview/test/fixtures/layouts/builder.builder new file mode 100644 index 0000000000..7c7d4b2dd1 --- /dev/null +++ b/actionview/test/fixtures/layouts/builder.builder @@ -0,0 +1,3 @@ +xml.wrapper do + xml << yield +end \ No newline at end of file diff --git a/actionview/test/fixtures/layouts/partial_with_layout.erb b/actionview/test/fixtures/layouts/partial_with_layout.erb new file mode 100644 index 0000000000..a0349d731e --- /dev/null +++ b/actionview/test/fixtures/layouts/partial_with_layout.erb @@ -0,0 +1,3 @@ +<%= render( :layout => "layout_for_partial", :partial => "partial_for_use_in_layout", :locals => {:name => 'Anthony' } ) %> +<%= yield %> +<%= render( :layout => "layout_for_partial", :partial => "partial_for_use_in_layout", :locals => {:name => 'Ramm' } ) %> \ No newline at end of file diff --git a/actionview/test/fixtures/layouts/standard.html.erb b/actionview/test/fixtures/layouts/standard.html.erb new file mode 100644 index 0000000000..5e6c24fe39 --- /dev/null +++ b/actionview/test/fixtures/layouts/standard.html.erb @@ -0,0 +1 @@ +<%= yield %><%= @variable_for_layout %> \ No newline at end of file diff --git a/actionview/test/fixtures/layouts/streaming.erb b/actionview/test/fixtures/layouts/streaming.erb new file mode 100644 index 0000000000..d3f896a6ca --- /dev/null +++ b/actionview/test/fixtures/layouts/streaming.erb @@ -0,0 +1,4 @@ +<%= yield :header -%> +<%= yield -%> +<%= yield :footer -%> +<%= yield(:unknown).presence || "." -%> \ No newline at end of file diff --git a/actionview/test/fixtures/layouts/talk_from_action.erb b/actionview/test/fixtures/layouts/talk_from_action.erb new file mode 100644 index 0000000000..bf53fdb785 --- /dev/null +++ b/actionview/test/fixtures/layouts/talk_from_action.erb @@ -0,0 +1,2 @@ +<%= @title || yield(:title) %> +<%= yield -%> \ No newline at end of file diff --git a/actionview/test/fixtures/layouts/with_html_partial.html.erb b/actionview/test/fixtures/layouts/with_html_partial.html.erb new file mode 100644 index 0000000000..fd2896aeaa --- /dev/null +++ b/actionview/test/fixtures/layouts/with_html_partial.html.erb @@ -0,0 +1 @@ +<%= render :partial => "partial_only_html" %><%= yield %> diff --git a/actionview/test/fixtures/layouts/xhr.html.erb b/actionview/test/fixtures/layouts/xhr.html.erb new file mode 100644 index 0000000000..85285324ec --- /dev/null +++ b/actionview/test/fixtures/layouts/xhr.html.erb @@ -0,0 +1,2 @@ +XHR! +<%= yield %> \ No newline at end of file diff --git a/actionview/test/fixtures/layouts/yield.erb b/actionview/test/fixtures/layouts/yield.erb new file mode 100644 index 0000000000..482dc9022e --- /dev/null +++ b/actionview/test/fixtures/layouts/yield.erb @@ -0,0 +1,2 @@ +<%= yield :title %> +<%= yield %> diff --git a/actionview/test/fixtures/layouts/yield_with_render_inline_inside.erb b/actionview/test/fixtures/layouts/yield_with_render_inline_inside.erb new file mode 100644 index 0000000000..7298d79690 --- /dev/null +++ b/actionview/test/fixtures/layouts/yield_with_render_inline_inside.erb @@ -0,0 +1,2 @@ +<%= render :inline => 'welcome' %> +<%= yield %> diff --git a/actionview/test/fixtures/layouts/yield_with_render_partial_inside.erb b/actionview/test/fixtures/layouts/yield_with_render_partial_inside.erb new file mode 100644 index 0000000000..74cc428ffa --- /dev/null +++ b/actionview/test/fixtures/layouts/yield_with_render_partial_inside.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'test/partial' %> +<%= yield %> diff --git a/actionview/test/fixtures/localized/hello_world.de.html b/actionview/test/fixtures/localized/hello_world.de.html new file mode 100644 index 0000000000..4727d7a7e0 --- /dev/null +++ b/actionview/test/fixtures/localized/hello_world.de.html @@ -0,0 +1 @@ +Gutten Tag \ No newline at end of file diff --git a/actionview/test/fixtures/localized/hello_world.en.html b/actionview/test/fixtures/localized/hello_world.en.html new file mode 100644 index 0000000000..5e1c309dae --- /dev/null +++ b/actionview/test/fixtures/localized/hello_world.en.html @@ -0,0 +1 @@ +Hello World \ No newline at end of file diff --git a/actionview/test/fixtures/mascot.rb b/actionview/test/fixtures/mascot.rb new file mode 100644 index 0000000000..f9f1448b8f --- /dev/null +++ b/actionview/test/fixtures/mascot.rb @@ -0,0 +1,3 @@ +class Mascot < ActiveRecord::Base + belongs_to :company +end \ No newline at end of file diff --git a/actionview/test/fixtures/mascots.yml b/actionview/test/fixtures/mascots.yml new file mode 100644 index 0000000000..17b7dff454 --- /dev/null +++ b/actionview/test/fixtures/mascots.yml @@ -0,0 +1,4 @@ +upload_bird: + id: 1 + company_id: 1 + name: The Upload Bird \ No newline at end of file diff --git a/actionview/test/fixtures/mascots/_mascot.html.erb b/actionview/test/fixtures/mascots/_mascot.html.erb new file mode 100644 index 0000000000..432773a1da --- /dev/null +++ b/actionview/test/fixtures/mascots/_mascot.html.erb @@ -0,0 +1 @@ +<%= mascot.name %> \ No newline at end of file diff --git a/actionview/test/fixtures/multipart/binary_file b/actionview/test/fixtures/multipart/binary_file new file mode 100644 index 0000000000..556187ac1f Binary files /dev/null and b/actionview/test/fixtures/multipart/binary_file differ diff --git a/actionview/test/fixtures/multipart/boundary_problem_file b/actionview/test/fixtures/multipart/boundary_problem_file new file mode 100644 index 0000000000..e81c4d8f1b --- /dev/null +++ b/actionview/test/fixtures/multipart/boundary_problem_file @@ -0,0 +1,10 @@ +--AaB03x +Content-Disposition: form-data; name="file"; filename="file.txt" +Content-Type: text/plain + +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +--AaB03x +Content-Disposition: form-data; name="foo" + +bar +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/bracketed_param b/actionview/test/fixtures/multipart/bracketed_param new file mode 100644 index 0000000000..8bb66c9c84 --- /dev/null +++ b/actionview/test/fixtures/multipart/bracketed_param @@ -0,0 +1,5 @@ +--AaB03x +Content-Disposition: form-data; name="foo[baz]" + +bar +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/bracketed_utf8_param b/actionview/test/fixtures/multipart/bracketed_utf8_param new file mode 100644 index 0000000000..df9cecea08 --- /dev/null +++ b/actionview/test/fixtures/multipart/bracketed_utf8_param @@ -0,0 +1,5 @@ +--AaB03x +Content-Disposition: form-data; name="Iñtërnâtiônàlizætiøn_name[Iñtërnâtiônàlizætiøn_nested_name]" + +Iñtërnâtiônàlizætiøn_value +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/empty b/actionview/test/fixtures/multipart/empty new file mode 100644 index 0000000000..7ba009902e --- /dev/null +++ b/actionview/test/fixtures/multipart/empty @@ -0,0 +1,10 @@ +--AaB03x +Content-Disposition: form-data; name="submit-name" + +Larry +--AaB03x +Content-Disposition: form-data; name="files"; filename="file1.txt" +Content-Type: text/plain + + +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/hello.txt b/actionview/test/fixtures/multipart/hello.txt new file mode 100644 index 0000000000..5ab2f8a432 --- /dev/null +++ b/actionview/test/fixtures/multipart/hello.txt @@ -0,0 +1 @@ +Hello \ No newline at end of file diff --git a/actionview/test/fixtures/multipart/large_text_file b/actionview/test/fixtures/multipart/large_text_file new file mode 100644 index 0000000000..dab4225860 --- /dev/null +++ b/actionview/test/fixtures/multipart/large_text_file @@ -0,0 +1,10 @@ +--AaB03x +Content-Disposition: form-data; name="foo" + +bar +--AaB03x +Content-Disposition: form-data; name="file"; filename="file.txt" +Content-Type: text/plain + +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/mixed_files b/actionview/test/fixtures/multipart/mixed_files new file mode 100644 index 0000000000..5eba7a6b48 Binary files /dev/null and b/actionview/test/fixtures/multipart/mixed_files differ diff --git a/actionview/test/fixtures/multipart/mona_lisa.jpg b/actionview/test/fixtures/multipart/mona_lisa.jpg new file mode 100644 index 0000000000..5cf3bef3d0 Binary files /dev/null and b/actionview/test/fixtures/multipart/mona_lisa.jpg differ diff --git a/actionview/test/fixtures/multipart/none b/actionview/test/fixtures/multipart/none new file mode 100644 index 0000000000..47138799ba --- /dev/null +++ b/actionview/test/fixtures/multipart/none @@ -0,0 +1,9 @@ +--AaB03x +Content-Disposition: form-data; name="submit-name" + +Larry +--AaB03x +Content-Disposition: form-data; name="files"; filename="" + + +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/single_parameter b/actionview/test/fixtures/multipart/single_parameter new file mode 100644 index 0000000000..75f0b3bba9 --- /dev/null +++ b/actionview/test/fixtures/multipart/single_parameter @@ -0,0 +1,5 @@ +--AaB03x +Content-Disposition: form-data; name="foo" + +bar +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/single_utf8_param b/actionview/test/fixtures/multipart/single_utf8_param new file mode 100644 index 0000000000..1d9fae7b17 --- /dev/null +++ b/actionview/test/fixtures/multipart/single_utf8_param @@ -0,0 +1,5 @@ +--AaB03x +Content-Disposition: form-data; name="Iñtërnâtiônàlizætiøn_name" + +Iñtërnâtiônàlizætiøn_value +--AaB03x-- diff --git a/actionview/test/fixtures/multipart/text_file b/actionview/test/fixtures/multipart/text_file new file mode 100644 index 0000000000..133d4be43b --- /dev/null +++ b/actionview/test/fixtures/multipart/text_file @@ -0,0 +1,10 @@ +--AaB03x +Content-Disposition: form-data; name="foo" + +bar +--AaB03x +Content-Disposition: form-data; name="file"; filename="file.txt" +Content-Type: text/plain + +contents +--AaB03x-- diff --git a/actionview/test/fixtures/old_content_type/render_default_content_types_for_respond_to.xml.erb b/actionview/test/fixtures/old_content_type/render_default_content_types_for_respond_to.xml.erb new file mode 100644 index 0000000000..25dc746886 --- /dev/null +++ b/actionview/test/fixtures/old_content_type/render_default_content_types_for_respond_to.xml.erb @@ -0,0 +1 @@ +world \ No newline at end of file diff --git a/actionview/test/fixtures/old_content_type/render_default_for_builder.builder b/actionview/test/fixtures/old_content_type/render_default_for_builder.builder new file mode 100644 index 0000000000..598d62e2fc --- /dev/null +++ b/actionview/test/fixtures/old_content_type/render_default_for_builder.builder @@ -0,0 +1 @@ +xml.p "Hello world!" \ No newline at end of file diff --git a/actionview/test/fixtures/old_content_type/render_default_for_erb.erb b/actionview/test/fixtures/old_content_type/render_default_for_erb.erb new file mode 100644 index 0000000000..c7926d48bb --- /dev/null +++ b/actionview/test/fixtures/old_content_type/render_default_for_erb.erb @@ -0,0 +1 @@ +<%= 'hello world!' %> \ No newline at end of file diff --git a/actionview/test/fixtures/override/test/hello_world.erb b/actionview/test/fixtures/override/test/hello_world.erb new file mode 100644 index 0000000000..3e308d3d86 --- /dev/null +++ b/actionview/test/fixtures/override/test/hello_world.erb @@ -0,0 +1 @@ +Hello overridden world! \ No newline at end of file diff --git a/actionview/test/fixtures/override2/layouts/test/sub.erb b/actionview/test/fixtures/override2/layouts/test/sub.erb new file mode 100644 index 0000000000..3863d5a8ef --- /dev/null +++ b/actionview/test/fixtures/override2/layouts/test/sub.erb @@ -0,0 +1 @@ +layout: <%= yield %> \ No newline at end of file diff --git a/actionview/test/fixtures/plain_text.raw b/actionview/test/fixtures/plain_text.raw new file mode 100644 index 0000000000..b13985337f --- /dev/null +++ b/actionview/test/fixtures/plain_text.raw @@ -0,0 +1 @@ +<%= hello_world %> diff --git a/actionview/test/fixtures/plain_text_with_characters.raw b/actionview/test/fixtures/plain_text_with_characters.raw new file mode 100644 index 0000000000..1e86e44fb4 --- /dev/null +++ b/actionview/test/fixtures/plain_text_with_characters.raw @@ -0,0 +1 @@ +Here are some characters: !@#$%^&*()-="'}{` diff --git a/actionview/test/fixtures/post_test/layouts/post.html.erb b/actionview/test/fixtures/post_test/layouts/post.html.erb new file mode 100644 index 0000000000..c6c1a586dd --- /dev/null +++ b/actionview/test/fixtures/post_test/layouts/post.html.erb @@ -0,0 +1 @@ +
<%= yield %>
\ No newline at end of file diff --git a/actionview/test/fixtures/post_test/layouts/super_post.iphone.erb b/actionview/test/fixtures/post_test/layouts/super_post.iphone.erb new file mode 100644 index 0000000000..db0e43694d --- /dev/null +++ b/actionview/test/fixtures/post_test/layouts/super_post.iphone.erb @@ -0,0 +1 @@ +
<%= yield %>
\ No newline at end of file diff --git a/actionview/test/fixtures/post_test/post/index.html.erb b/actionview/test/fixtures/post_test/post/index.html.erb new file mode 100644 index 0000000000..b349b25618 --- /dev/null +++ b/actionview/test/fixtures/post_test/post/index.html.erb @@ -0,0 +1 @@ +Hello Firefox \ No newline at end of file diff --git a/actionview/test/fixtures/post_test/post/index.iphone.erb b/actionview/test/fixtures/post_test/post/index.iphone.erb new file mode 100644 index 0000000000..d741e44351 --- /dev/null +++ b/actionview/test/fixtures/post_test/post/index.iphone.erb @@ -0,0 +1 @@ +Hello iPhone \ No newline at end of file diff --git a/actionview/test/fixtures/post_test/super_post/index.html.erb b/actionview/test/fixtures/post_test/super_post/index.html.erb new file mode 100644 index 0000000000..7fc2eb190a --- /dev/null +++ b/actionview/test/fixtures/post_test/super_post/index.html.erb @@ -0,0 +1 @@ +Super Firefox \ No newline at end of file diff --git a/actionview/test/fixtures/post_test/super_post/index.iphone.erb b/actionview/test/fixtures/post_test/super_post/index.iphone.erb new file mode 100644 index 0000000000..99063a8d8c --- /dev/null +++ b/actionview/test/fixtures/post_test/super_post/index.iphone.erb @@ -0,0 +1 @@ +Super iPhone \ No newline at end of file diff --git a/actionview/test/fixtures/project.rb b/actionview/test/fixtures/project.rb new file mode 100644 index 0000000000..c124a9e605 --- /dev/null +++ b/actionview/test/fixtures/project.rb @@ -0,0 +1,3 @@ +class Project < ActiveRecord::Base + has_and_belongs_to_many :developers, -> { uniq } +end diff --git a/actionview/test/fixtures/projects.yml b/actionview/test/fixtures/projects.yml new file mode 100644 index 0000000000..02800c7824 --- /dev/null +++ b/actionview/test/fixtures/projects.yml @@ -0,0 +1,7 @@ +action_controller: + id: 2 + name: Active Controller + +active_record: + id: 1 + name: Active Record diff --git a/actionview/test/fixtures/projects/_project.erb b/actionview/test/fixtures/projects/_project.erb new file mode 100644 index 0000000000..480c4c2af3 --- /dev/null +++ b/actionview/test/fixtures/projects/_project.erb @@ -0,0 +1 @@ +<%= project.name %> \ No newline at end of file diff --git a/actionview/test/fixtures/public/.gitignore b/actionview/test/fixtures/public/.gitignore new file mode 100644 index 0000000000..312e635ee6 --- /dev/null +++ b/actionview/test/fixtures/public/.gitignore @@ -0,0 +1 @@ +absolute/* diff --git a/actionview/test/fixtures/public/404.html b/actionview/test/fixtures/public/404.html new file mode 100644 index 0000000000..497397ccea --- /dev/null +++ b/actionview/test/fixtures/public/404.html @@ -0,0 +1 @@ +404 error fixture diff --git a/actionview/test/fixtures/public/500.da.html b/actionview/test/fixtures/public/500.da.html new file mode 100644 index 0000000000..a497c13656 --- /dev/null +++ b/actionview/test/fixtures/public/500.da.html @@ -0,0 +1 @@ +500 localized error fixture diff --git a/actionview/test/fixtures/public/500.html b/actionview/test/fixtures/public/500.html new file mode 100644 index 0000000000..7c66c7a943 --- /dev/null +++ b/actionview/test/fixtures/public/500.html @@ -0,0 +1 @@ +500 error fixture diff --git a/actionview/test/fixtures/public/elsewhere/cools.js b/actionview/test/fixtures/public/elsewhere/cools.js new file mode 100644 index 0000000000..6e12fe29c4 --- /dev/null +++ b/actionview/test/fixtures/public/elsewhere/cools.js @@ -0,0 +1 @@ +// cools.js \ No newline at end of file diff --git a/actionview/test/fixtures/public/elsewhere/file.css b/actionview/test/fixtures/public/elsewhere/file.css new file mode 100644 index 0000000000..6aea0733b1 --- /dev/null +++ b/actionview/test/fixtures/public/elsewhere/file.css @@ -0,0 +1 @@ +/*file.css*/ \ No newline at end of file diff --git a/actionview/test/fixtures/public/foo/bar.html b/actionview/test/fixtures/public/foo/bar.html new file mode 100644 index 0000000000..9a35646205 --- /dev/null +++ b/actionview/test/fixtures/public/foo/bar.html @@ -0,0 +1 @@ +/foo/bar.html \ No newline at end of file diff --git a/actionview/test/fixtures/public/foo/baz.css b/actionview/test/fixtures/public/foo/baz.css new file mode 100644 index 0000000000..b5173fbef2 --- /dev/null +++ b/actionview/test/fixtures/public/foo/baz.css @@ -0,0 +1,3 @@ +body { +background: #000; +} diff --git a/actionview/test/fixtures/public/foo/index.html b/actionview/test/fixtures/public/foo/index.html new file mode 100644 index 0000000000..497a2e898f --- /dev/null +++ b/actionview/test/fixtures/public/foo/index.html @@ -0,0 +1 @@ +/foo/index.html \ No newline at end of file diff --git "a/actionview/test/fixtures/public/foo/\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257.html" "b/actionview/test/fixtures/public/foo/\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257.html" new file mode 100644 index 0000000000..1df9166522 --- /dev/null +++ "b/actionview/test/fixtures/public/foo/\343\201\223\343\202\223\343\201\253\343\201\241\343\201\257.html" @@ -0,0 +1 @@ +means hello in Japanese diff --git a/actionview/test/fixtures/public/index.html b/actionview/test/fixtures/public/index.html new file mode 100644 index 0000000000..525950ba6b --- /dev/null +++ b/actionview/test/fixtures/public/index.html @@ -0,0 +1 @@ +/index.html \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/application.js b/actionview/test/fixtures/public/javascripts/application.js new file mode 100644 index 0000000000..9702692980 --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/application.js @@ -0,0 +1 @@ +// application js \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/bank.js b/actionview/test/fixtures/public/javascripts/bank.js new file mode 100644 index 0000000000..4a1bee7182 --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/bank.js @@ -0,0 +1 @@ +// bank js \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/common.javascript b/actionview/test/fixtures/public/javascripts/common.javascript new file mode 100644 index 0000000000..2ae1929056 --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/common.javascript @@ -0,0 +1 @@ +// common.javascript \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/controls.js b/actionview/test/fixtures/public/javascripts/controls.js new file mode 100644 index 0000000000..88168d9f13 --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/controls.js @@ -0,0 +1 @@ +// controls js \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/dragdrop.js b/actionview/test/fixtures/public/javascripts/dragdrop.js new file mode 100644 index 0000000000..c07061ac0c --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/dragdrop.js @@ -0,0 +1 @@ +// dragdrop js \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/effects.js b/actionview/test/fixtures/public/javascripts/effects.js new file mode 100644 index 0000000000..b555d63034 --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/effects.js @@ -0,0 +1 @@ +// effects js \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/prototype.js b/actionview/test/fixtures/public/javascripts/prototype.js new file mode 100644 index 0000000000..9780064a0e --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/prototype.js @@ -0,0 +1 @@ +// prototype js \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/robber.js b/actionview/test/fixtures/public/javascripts/robber.js new file mode 100644 index 0000000000..eb82fcbdf4 --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/robber.js @@ -0,0 +1 @@ +// robber js \ No newline at end of file diff --git a/actionview/test/fixtures/public/javascripts/subdir/subdir.js b/actionview/test/fixtures/public/javascripts/subdir/subdir.js new file mode 100644 index 0000000000..9d23a67aa1 --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/subdir/subdir.js @@ -0,0 +1 @@ +// subdir js diff --git a/actionview/test/fixtures/public/javascripts/version.1.0.js b/actionview/test/fixtures/public/javascripts/version.1.0.js new file mode 100644 index 0000000000..cfd5fce70e --- /dev/null +++ b/actionview/test/fixtures/public/javascripts/version.1.0.js @@ -0,0 +1 @@ +// version.1.0 js \ No newline at end of file diff --git a/actionview/test/fixtures/public/stylesheets/bank.css b/actionview/test/fixtures/public/stylesheets/bank.css new file mode 100644 index 0000000000..ea161b12b2 --- /dev/null +++ b/actionview/test/fixtures/public/stylesheets/bank.css @@ -0,0 +1 @@ +/* bank.css */ \ No newline at end of file diff --git a/actionview/test/fixtures/public/stylesheets/random.styles b/actionview/test/fixtures/public/stylesheets/random.styles new file mode 100644 index 0000000000..d4eeead95c --- /dev/null +++ b/actionview/test/fixtures/public/stylesheets/random.styles @@ -0,0 +1 @@ +/* random.styles */ \ No newline at end of file diff --git a/actionview/test/fixtures/public/stylesheets/robber.css b/actionview/test/fixtures/public/stylesheets/robber.css new file mode 100644 index 0000000000..0fdd00a6a5 --- /dev/null +++ b/actionview/test/fixtures/public/stylesheets/robber.css @@ -0,0 +1 @@ +/* robber.css */ \ No newline at end of file diff --git a/actionview/test/fixtures/public/stylesheets/subdir/subdir.css b/actionview/test/fixtures/public/stylesheets/subdir/subdir.css new file mode 100644 index 0000000000..241152a905 --- /dev/null +++ b/actionview/test/fixtures/public/stylesheets/subdir/subdir.css @@ -0,0 +1 @@ +/* subdir.css */ diff --git a/actionview/test/fixtures/public/stylesheets/version.1.0.css b/actionview/test/fixtures/public/stylesheets/version.1.0.css new file mode 100644 index 0000000000..30f5f9ba6e --- /dev/null +++ b/actionview/test/fixtures/public/stylesheets/version.1.0.css @@ -0,0 +1 @@ +/* version.1.0.css */ \ No newline at end of file diff --git a/actionview/test/fixtures/quiz/questions/_question.html.erb b/actionview/test/fixtures/quiz/questions/_question.html.erb new file mode 100644 index 0000000000..fb4dcfee64 --- /dev/null +++ b/actionview/test/fixtures/quiz/questions/_question.html.erb @@ -0,0 +1 @@ +<%= question.name %> \ No newline at end of file diff --git a/actionview/test/fixtures/replies.yml b/actionview/test/fixtures/replies.yml new file mode 100644 index 0000000000..2a3454b8bf --- /dev/null +++ b/actionview/test/fixtures/replies.yml @@ -0,0 +1,15 @@ +witty_retort: + id: 1 + topic_id: 1 + developer_id: 1 + content: Birdman is better! + created_at: <%= 6.hours.ago.to_s(:db) %> + updated_at: nil + +another: + id: 2 + topic_id: 2 + developer_id: 1 + content: Nuh uh! + created_at: <%= 1.hour.ago.to_s(:db) %> + updated_at: nil diff --git a/actionview/test/fixtures/replies/_reply.erb b/actionview/test/fixtures/replies/_reply.erb new file mode 100644 index 0000000000..68baf548d8 --- /dev/null +++ b/actionview/test/fixtures/replies/_reply.erb @@ -0,0 +1 @@ +<%= reply.content %> \ No newline at end of file diff --git a/actionview/test/fixtures/reply.rb b/actionview/test/fixtures/reply.rb new file mode 100644 index 0000000000..047522c55b --- /dev/null +++ b/actionview/test/fixtures/reply.rb @@ -0,0 +1,7 @@ +class Reply < ActiveRecord::Base + scope :base, -> { all } + belongs_to :topic, -> { includes(:replies) } + belongs_to :developer + + validates_presence_of :content +end diff --git a/actionview/test/fixtures/respond_to/all_types_with_layout.html.erb b/actionview/test/fixtures/respond_to/all_types_with_layout.html.erb new file mode 100644 index 0000000000..84a84049f8 --- /dev/null +++ b/actionview/test/fixtures/respond_to/all_types_with_layout.html.erb @@ -0,0 +1 @@ +HTML for all_types_with_layout \ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb b/actionview/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb new file mode 100644 index 0000000000..0cdfa41494 --- /dev/null +++ b/actionview/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb @@ -0,0 +1 @@ +Mobile \ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/iphone_with_html_response_type.html.erb b/actionview/test/fixtures/respond_to/iphone_with_html_response_type.html.erb new file mode 100644 index 0000000000..1f3f1c6516 --- /dev/null +++ b/actionview/test/fixtures/respond_to/iphone_with_html_response_type.html.erb @@ -0,0 +1 @@ +Hello future from <%= @type -%>! \ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb b/actionview/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb new file mode 100644 index 0000000000..17888ac303 --- /dev/null +++ b/actionview/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb @@ -0,0 +1 @@ +Hello iPhone future from <%= @type -%>! \ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/layouts/missing.html.erb b/actionview/test/fixtures/respond_to/layouts/missing.html.erb new file mode 100644 index 0000000000..d6f92a3120 --- /dev/null +++ b/actionview/test/fixtures/respond_to/layouts/missing.html.erb @@ -0,0 +1 @@ +
<%= yield %>
\ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/layouts/standard.html.erb b/actionview/test/fixtures/respond_to/layouts/standard.html.erb new file mode 100644 index 0000000000..c6c1a586dd --- /dev/null +++ b/actionview/test/fixtures/respond_to/layouts/standard.html.erb @@ -0,0 +1 @@ +
<%= yield %>
\ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/layouts/standard.iphone.erb b/actionview/test/fixtures/respond_to/layouts/standard.iphone.erb new file mode 100644 index 0000000000..84444517f0 --- /dev/null +++ b/actionview/test/fixtures/respond_to/layouts/standard.iphone.erb @@ -0,0 +1 @@ +
<%= yield %>
\ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/using_defaults.html.erb b/actionview/test/fixtures/respond_to/using_defaults.html.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/respond_to/using_defaults.html.erb @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/using_defaults.xml.builder b/actionview/test/fixtures/respond_to/using_defaults.xml.builder new file mode 100644 index 0000000000..598d62e2fc --- /dev/null +++ b/actionview/test/fixtures/respond_to/using_defaults.xml.builder @@ -0,0 +1 @@ +xml.p "Hello world!" \ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/using_defaults_with_all.html.erb b/actionview/test/fixtures/respond_to/using_defaults_with_all.html.erb new file mode 100644 index 0000000000..9f1f855269 --- /dev/null +++ b/actionview/test/fixtures/respond_to/using_defaults_with_all.html.erb @@ -0,0 +1 @@ +HTML! diff --git a/actionview/test/fixtures/respond_to/using_defaults_with_type_list.html.erb b/actionview/test/fixtures/respond_to/using_defaults_with_type_list.html.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/respond_to/using_defaults_with_type_list.html.erb @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/actionview/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder b/actionview/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder new file mode 100644 index 0000000000..598d62e2fc --- /dev/null +++ b/actionview/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder @@ -0,0 +1 @@ +xml.p "Hello world!" \ No newline at end of file diff --git a/actionview/test/fixtures/respond_with/edit.html.erb b/actionview/test/fixtures/respond_with/edit.html.erb new file mode 100644 index 0000000000..ae82dfa4fc --- /dev/null +++ b/actionview/test/fixtures/respond_with/edit.html.erb @@ -0,0 +1 @@ +Edit world! diff --git a/actionview/test/fixtures/respond_with/new.html.erb b/actionview/test/fixtures/respond_with/new.html.erb new file mode 100644 index 0000000000..96c8f1b88b --- /dev/null +++ b/actionview/test/fixtures/respond_with/new.html.erb @@ -0,0 +1 @@ +New world! diff --git a/actionview/test/fixtures/respond_with/using_invalid_resource_with_template.xml.erb b/actionview/test/fixtures/respond_with/using_invalid_resource_with_template.xml.erb new file mode 100644 index 0000000000..bf5869ed22 --- /dev/null +++ b/actionview/test/fixtures/respond_with/using_invalid_resource_with_template.xml.erb @@ -0,0 +1 @@ +I should not be displayed \ No newline at end of file diff --git a/actionview/test/fixtures/respond_with/using_options_with_template.xml.erb b/actionview/test/fixtures/respond_with/using_options_with_template.xml.erb new file mode 100644 index 0000000000..b313017913 --- /dev/null +++ b/actionview/test/fixtures/respond_with/using_options_with_template.xml.erb @@ -0,0 +1 @@ +<%= @customer.name %> \ No newline at end of file diff --git a/actionview/test/fixtures/respond_with/using_resource.js.erb b/actionview/test/fixtures/respond_with/using_resource.js.erb new file mode 100644 index 0000000000..4417680bce --- /dev/null +++ b/actionview/test/fixtures/respond_with/using_resource.js.erb @@ -0,0 +1 @@ +alert("Hi"); \ No newline at end of file diff --git a/actionview/test/fixtures/respond_with/using_resource_with_block.html.erb b/actionview/test/fixtures/respond_with/using_resource_with_block.html.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/respond_with/using_resource_with_block.html.erb @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/actionview/test/fixtures/ruby_template.ruby b/actionview/test/fixtures/ruby_template.ruby new file mode 100644 index 0000000000..5097bce47c --- /dev/null +++ b/actionview/test/fixtures/ruby_template.ruby @@ -0,0 +1,2 @@ +body = "" +body << ["Hello", "from", "Ruby", "code"].join(" ") diff --git a/actionview/test/fixtures/scope/test/modgreet.erb b/actionview/test/fixtures/scope/test/modgreet.erb new file mode 100644 index 0000000000..8947726e89 --- /dev/null +++ b/actionview/test/fixtures/scope/test/modgreet.erb @@ -0,0 +1 @@ +

Beautiful modules!

\ No newline at end of file diff --git a/actionview/test/fixtures/session_autoload_test/session_autoload_test/foo.rb b/actionview/test/fixtures/session_autoload_test/session_autoload_test/foo.rb new file mode 100644 index 0000000000..4ee7a24561 --- /dev/null +++ b/actionview/test/fixtures/session_autoload_test/session_autoload_test/foo.rb @@ -0,0 +1,10 @@ +module SessionAutoloadTest + class Foo + def initialize(bar='baz') + @bar = bar + end + def inspect + "#<#{self.class} bar:#{@bar.inspect}>" + end + end +end diff --git a/actionview/test/fixtures/shared.html.erb b/actionview/test/fixtures/shared.html.erb new file mode 100644 index 0000000000..af262fc9f8 --- /dev/null +++ b/actionview/test/fixtures/shared.html.erb @@ -0,0 +1 @@ +Elastica \ No newline at end of file diff --git a/actionview/test/fixtures/star_star_mime/index.js.erb b/actionview/test/fixtures/star_star_mime/index.js.erb new file mode 100644 index 0000000000..4da4181f56 --- /dev/null +++ b/actionview/test/fixtures/star_star_mime/index.js.erb @@ -0,0 +1 @@ +function addition(a,b){ return a+b; } diff --git a/actionview/test/fixtures/symlink_parent/symlinked_layout.erb b/actionview/test/fixtures/symlink_parent/symlinked_layout.erb new file mode 100644 index 0000000000..bda57d0fae --- /dev/null +++ b/actionview/test/fixtures/symlink_parent/symlinked_layout.erb @@ -0,0 +1,5 @@ +This is my layout + +<%= yield %> + +End. diff --git a/actionview/test/fixtures/test/_200.html.erb b/actionview/test/fixtures/test/_200.html.erb new file mode 100644 index 0000000000..c9f45675dc --- /dev/null +++ b/actionview/test/fixtures/test/_200.html.erb @@ -0,0 +1 @@ +

Invalid partial

diff --git a/actionview/test/fixtures/test/_b_layout_for_partial.html.erb b/actionview/test/fixtures/test/_b_layout_for_partial.html.erb new file mode 100644 index 0000000000..e918ba8f83 --- /dev/null +++ b/actionview/test/fixtures/test/_b_layout_for_partial.html.erb @@ -0,0 +1 @@ +<%= yield %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_b_layout_for_partial_with_object.html.erb b/actionview/test/fixtures/test/_b_layout_for_partial_with_object.html.erb new file mode 100644 index 0000000000..bdd53014cd --- /dev/null +++ b/actionview/test/fixtures/test/_b_layout_for_partial_with_object.html.erb @@ -0,0 +1 @@ +<%= yield %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb b/actionview/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb new file mode 100644 index 0000000000..44d6121297 --- /dev/null +++ b/actionview/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb @@ -0,0 +1 @@ +<%= yield %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_changing_priority.html.erb b/actionview/test/fixtures/test/_changing_priority.html.erb new file mode 100644 index 0000000000..3225efc49a --- /dev/null +++ b/actionview/test/fixtures/test/_changing_priority.html.erb @@ -0,0 +1 @@ +HTML \ No newline at end of file diff --git a/actionview/test/fixtures/test/_changing_priority.json.erb b/actionview/test/fixtures/test/_changing_priority.json.erb new file mode 100644 index 0000000000..7fa41dce66 --- /dev/null +++ b/actionview/test/fixtures/test/_changing_priority.json.erb @@ -0,0 +1 @@ +JSON \ No newline at end of file diff --git a/actionview/test/fixtures/test/_content_tag_nested_in_content_tag.erb b/actionview/test/fixtures/test/_content_tag_nested_in_content_tag.erb new file mode 100644 index 0000000000..2f21a75dd9 --- /dev/null +++ b/actionview/test/fixtures/test/_content_tag_nested_in_content_tag.erb @@ -0,0 +1,3 @@ +<%= content_tag 'p' do %> + <%= content_tag 'b', 'Hello' %> +<% end %> diff --git a/actionview/test/fixtures/test/_counter.html.erb b/actionview/test/fixtures/test/_counter.html.erb new file mode 100644 index 0000000000..fd245bfc70 --- /dev/null +++ b/actionview/test/fixtures/test/_counter.html.erb @@ -0,0 +1 @@ +<%= counter_counter %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_customer.erb b/actionview/test/fixtures/test/_customer.erb new file mode 100644 index 0000000000..d8220afeda --- /dev/null +++ b/actionview/test/fixtures/test/_customer.erb @@ -0,0 +1 @@ +Hello: <%= customer.name rescue "Anonymous" %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_customer_counter.erb b/actionview/test/fixtures/test/_customer_counter.erb new file mode 100644 index 0000000000..3435979dba --- /dev/null +++ b/actionview/test/fixtures/test/_customer_counter.erb @@ -0,0 +1 @@ +<%= customer_counter.name %><%= customer_counter_counter %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_customer_counter_with_as.erb b/actionview/test/fixtures/test/_customer_counter_with_as.erb new file mode 100644 index 0000000000..1241eb604d --- /dev/null +++ b/actionview/test/fixtures/test/_customer_counter_with_as.erb @@ -0,0 +1 @@ +<%= client.name %><%= client_counter %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_customer_greeting.erb b/actionview/test/fixtures/test/_customer_greeting.erb new file mode 100644 index 0000000000..6acbcb20c4 --- /dev/null +++ b/actionview/test/fixtures/test/_customer_greeting.erb @@ -0,0 +1 @@ +<%= greeting %>: <%= customer_greeting.name %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_customer_with_var.erb b/actionview/test/fixtures/test/_customer_with_var.erb new file mode 100644 index 0000000000..00047dd20e --- /dev/null +++ b/actionview/test/fixtures/test/_customer_with_var.erb @@ -0,0 +1 @@ +<%= customer.name %> <%= customer.name %> <%= customer.name %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_directory/_partial_with_locales.html.erb b/actionview/test/fixtures/test/_directory/_partial_with_locales.html.erb new file mode 100644 index 0000000000..1cc8d41475 --- /dev/null +++ b/actionview/test/fixtures/test/_directory/_partial_with_locales.html.erb @@ -0,0 +1 @@ +Hello <%= name %> diff --git a/actionview/test/fixtures/test/_first_json_partial.json.erb b/actionview/test/fixtures/test/_first_json_partial.json.erb new file mode 100644 index 0000000000..790ee896db --- /dev/null +++ b/actionview/test/fixtures/test/_first_json_partial.json.erb @@ -0,0 +1 @@ +<%= render :partial => "test/second_json_partial" %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_form.erb b/actionview/test/fixtures/test/_form.erb new file mode 100644 index 0000000000..01107f1cb2 --- /dev/null +++ b/actionview/test/fixtures/test/_form.erb @@ -0,0 +1 @@ +<%= form.label :title %> diff --git a/actionview/test/fixtures/test/_from_helper.erb b/actionview/test/fixtures/test/_from_helper.erb new file mode 100644 index 0000000000..16de7c0f8a --- /dev/null +++ b/actionview/test/fixtures/test/_from_helper.erb @@ -0,0 +1 @@ +<%= render_from_helper %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_hash_greeting.erb b/actionview/test/fixtures/test/_hash_greeting.erb new file mode 100644 index 0000000000..fc54a36f2a --- /dev/null +++ b/actionview/test/fixtures/test/_hash_greeting.erb @@ -0,0 +1 @@ +<%= greeting %>: <%= hash_greeting[:first_name] %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_hash_object.erb b/actionview/test/fixtures/test/_hash_object.erb new file mode 100644 index 0000000000..34a92c6a56 --- /dev/null +++ b/actionview/test/fixtures/test/_hash_object.erb @@ -0,0 +1,2 @@ +<%= hash_object[:first_name] %> +<%= hash_object[:first_name].reverse %> diff --git a/actionview/test/fixtures/test/_hello.builder b/actionview/test/fixtures/test/_hello.builder new file mode 100644 index 0000000000..ef52f632d1 --- /dev/null +++ b/actionview/test/fixtures/test/_hello.builder @@ -0,0 +1 @@ +xm.hello \ No newline at end of file diff --git a/actionview/test/fixtures/test/_json_change_priority.json.erb b/actionview/test/fixtures/test/_json_change_priority.json.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/actionview/test/fixtures/test/_label_with_block.erb b/actionview/test/fixtures/test/_label_with_block.erb new file mode 100644 index 0000000000..40117e594e --- /dev/null +++ b/actionview/test/fixtures/test/_label_with_block.erb @@ -0,0 +1,4 @@ +<%= label 'post', 'message' do %> + Message + <%= text_field 'post', 'message' %> +<% end %> diff --git a/actionview/test/fixtures/test/_labelling_form.erb b/actionview/test/fixtures/test/_labelling_form.erb new file mode 100644 index 0000000000..1b95763165 --- /dev/null +++ b/actionview/test/fixtures/test/_labelling_form.erb @@ -0,0 +1 @@ +<%= labelling_form.label :title %> diff --git a/actionview/test/fixtures/test/_layout_for_block_with_args.html.erb b/actionview/test/fixtures/test/_layout_for_block_with_args.html.erb new file mode 100644 index 0000000000..307533208d --- /dev/null +++ b/actionview/test/fixtures/test/_layout_for_block_with_args.html.erb @@ -0,0 +1,3 @@ +Before +<%= yield 'arg1', 'arg2' %> +After \ No newline at end of file diff --git a/actionview/test/fixtures/test/_layout_for_partial.html.erb b/actionview/test/fixtures/test/_layout_for_partial.html.erb new file mode 100644 index 0000000000..666efadbb6 --- /dev/null +++ b/actionview/test/fixtures/test/_layout_for_partial.html.erb @@ -0,0 +1,3 @@ +Before (<%= name %>) +<%= yield %> +After \ No newline at end of file diff --git a/actionview/test/fixtures/test/_layout_with_partial_and_yield.html.erb b/actionview/test/fixtures/test/_layout_with_partial_and_yield.html.erb new file mode 100644 index 0000000000..820e7db789 --- /dev/null +++ b/actionview/test/fixtures/test/_layout_with_partial_and_yield.html.erb @@ -0,0 +1,4 @@ +Before +<%= render :partial => "test/partial" %> +<%= yield %> +After diff --git a/actionview/test/fixtures/test/_local_inspector.html.erb b/actionview/test/fixtures/test/_local_inspector.html.erb new file mode 100644 index 0000000000..e6765c0882 --- /dev/null +++ b/actionview/test/fixtures/test/_local_inspector.html.erb @@ -0,0 +1 @@ +<%= local_assigns.keys.map {|k| k.to_s }.sort.join(",") -%> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_object_inspector.erb b/actionview/test/fixtures/test/_object_inspector.erb new file mode 100644 index 0000000000..53af593821 --- /dev/null +++ b/actionview/test/fixtures/test/_object_inspector.erb @@ -0,0 +1 @@ +<%= object_inspector.inspect -%> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_one.html.erb b/actionview/test/fixtures/test/_one.html.erb new file mode 100644 index 0000000000..f796291cb4 --- /dev/null +++ b/actionview/test/fixtures/test/_one.html.erb @@ -0,0 +1 @@ +<%= render :partial => "two" %> world diff --git a/actionview/test/fixtures/test/_partial.erb b/actionview/test/fixtures/test/_partial.erb new file mode 100644 index 0000000000..e466dcbd8e --- /dev/null +++ b/actionview/test/fixtures/test/_partial.erb @@ -0,0 +1 @@ +invalid \ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial.html.erb b/actionview/test/fixtures/test/_partial.html.erb new file mode 100644 index 0000000000..e39f6c9827 --- /dev/null +++ b/actionview/test/fixtures/test/_partial.html.erb @@ -0,0 +1 @@ +partial html \ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial.js.erb b/actionview/test/fixtures/test/_partial.js.erb new file mode 100644 index 0000000000..b350cdd7ef --- /dev/null +++ b/actionview/test/fixtures/test/_partial.js.erb @@ -0,0 +1 @@ +partial js \ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial_for_use_in_layout.html.erb b/actionview/test/fixtures/test/_partial_for_use_in_layout.html.erb new file mode 100644 index 0000000000..3a03a64e31 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_for_use_in_layout.html.erb @@ -0,0 +1 @@ +Inside from partial (<%= name %>) \ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial_html_erb.html.erb b/actionview/test/fixtures/test/_partial_html_erb.html.erb new file mode 100644 index 0000000000..4b54875782 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_html_erb.html.erb @@ -0,0 +1 @@ +<%= "partial.html.erb" %> diff --git a/actionview/test/fixtures/test/_partial_name_local_variable.erb b/actionview/test/fixtures/test/_partial_name_local_variable.erb new file mode 100644 index 0000000000..cc3a91c89f --- /dev/null +++ b/actionview/test/fixtures/test/_partial_name_local_variable.erb @@ -0,0 +1 @@ +<%= partial_name_local_variable %> diff --git a/actionview/test/fixtures/test/_partial_only.erb b/actionview/test/fixtures/test/_partial_only.erb new file mode 100644 index 0000000000..a44b3eed40 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_only.erb @@ -0,0 +1 @@ +only partial \ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial_only_html.html b/actionview/test/fixtures/test/_partial_only_html.html new file mode 100644 index 0000000000..d2d630bd40 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_only_html.html @@ -0,0 +1 @@ +only html partial \ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial_with_layout.erb b/actionview/test/fixtures/test/_partial_with_layout.erb new file mode 100644 index 0000000000..2a50c834fe --- /dev/null +++ b/actionview/test/fixtures/test/_partial_with_layout.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'test/partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Bar!' } %> +partial with layout diff --git a/actionview/test/fixtures/test/_partial_with_layout_block_content.erb b/actionview/test/fixtures/test/_partial_with_layout_block_content.erb new file mode 100644 index 0000000000..65dafd93a8 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_with_layout_block_content.erb @@ -0,0 +1,4 @@ +<%= render :layout => 'test/layout_for_partial', :locals => { :name => 'Bar!' } do %> + Content from inside layout! +<% end %> +partial with layout diff --git a/actionview/test/fixtures/test/_partial_with_layout_block_partial.erb b/actionview/test/fixtures/test/_partial_with_layout_block_partial.erb new file mode 100644 index 0000000000..444197a7d0 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_with_layout_block_partial.erb @@ -0,0 +1,4 @@ +<%= render :layout => 'test/layout_for_partial', :locals => { :name => 'Bar!' } do %> + <%= render 'test/partial' %> +<% end %> +partial with layout diff --git a/actionview/test/fixtures/test/_partial_with_only_html_version.html.erb b/actionview/test/fixtures/test/_partial_with_only_html_version.html.erb new file mode 100644 index 0000000000..00e6b6d6da --- /dev/null +++ b/actionview/test/fixtures/test/_partial_with_only_html_version.html.erb @@ -0,0 +1 @@ +partial with only html version \ No newline at end of file diff --git a/actionview/test/fixtures/test/_partial_with_partial.erb b/actionview/test/fixtures/test/_partial_with_partial.erb new file mode 100644 index 0000000000..ee0d5037b6 --- /dev/null +++ b/actionview/test/fixtures/test/_partial_with_partial.erb @@ -0,0 +1,2 @@ +<%= render 'test/partial' %> +partial with partial diff --git a/actionview/test/fixtures/test/_person.erb b/actionview/test/fixtures/test/_person.erb new file mode 100644 index 0000000000..b2e5688956 --- /dev/null +++ b/actionview/test/fixtures/test/_person.erb @@ -0,0 +1,2 @@ +Second: <%= name %> +Third: <%= @name %> diff --git a/actionview/test/fixtures/test/_raise.html.erb b/actionview/test/fixtures/test/_raise.html.erb new file mode 100644 index 0000000000..68b08181d3 --- /dev/null +++ b/actionview/test/fixtures/test/_raise.html.erb @@ -0,0 +1 @@ +<%= doesnt_exist %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/_raise_indentation.html.erb b/actionview/test/fixtures/test/_raise_indentation.html.erb new file mode 100644 index 0000000000..f9a93728fe --- /dev/null +++ b/actionview/test/fixtures/test/_raise_indentation.html.erb @@ -0,0 +1,13 @@ +

First paragraph

+

Second paragraph

+

Third paragraph

+

Fourth paragraph

+

Fifth paragraph

+

Sixth paragraph

+

Seventh paragraph

+

Eight paragraph

+

Ninth paragraph

+

Tenth paragraph

+<%= raise "error here!" %> +

Eleventh paragraph

+

Twelfth paragraph

\ No newline at end of file diff --git a/actionview/test/fixtures/test/_second_json_partial.json.erb b/actionview/test/fixtures/test/_second_json_partial.json.erb new file mode 100644 index 0000000000..5ebb7f1afd --- /dev/null +++ b/actionview/test/fixtures/test/_second_json_partial.json.erb @@ -0,0 +1 @@ +Third level \ No newline at end of file diff --git a/actionview/test/fixtures/test/_two.html.erb b/actionview/test/fixtures/test/_two.html.erb new file mode 100644 index 0000000000..5ab2f8a432 --- /dev/null +++ b/actionview/test/fixtures/test/_two.html.erb @@ -0,0 +1 @@ +Hello \ No newline at end of file diff --git a/actionview/test/fixtures/test/_utf8_partial.html.erb b/actionview/test/fixtures/test/_utf8_partial.html.erb new file mode 100644 index 0000000000..8d717fd427 --- /dev/null +++ b/actionview/test/fixtures/test/_utf8_partial.html.erb @@ -0,0 +1 @@ +<%= "текст" %> diff --git a/actionview/test/fixtures/test/_utf8_partial_magic.html.erb b/actionview/test/fixtures/test/_utf8_partial_magic.html.erb new file mode 100644 index 0000000000..4e2224610a --- /dev/null +++ b/actionview/test/fixtures/test/_utf8_partial_magic.html.erb @@ -0,0 +1,2 @@ +<%# encoding: utf-8 -%> +<%= "текст" %> diff --git a/actionview/test/fixtures/test/action_talk_to_layout.erb b/actionview/test/fixtures/test/action_talk_to_layout.erb new file mode 100644 index 0000000000..36e896daa8 --- /dev/null +++ b/actionview/test/fixtures/test/action_talk_to_layout.erb @@ -0,0 +1,2 @@ +<% @title = "Talking to the layout" -%> +Action was here! \ No newline at end of file diff --git a/actionview/test/fixtures/test/basic.html.erb b/actionview/test/fixtures/test/basic.html.erb new file mode 100644 index 0000000000..ea696d7e01 --- /dev/null +++ b/actionview/test/fixtures/test/basic.html.erb @@ -0,0 +1 @@ +Hello from basic.html.erb \ No newline at end of file diff --git a/actionview/test/fixtures/test/calling_partial_with_layout.html.erb b/actionview/test/fixtures/test/calling_partial_with_layout.html.erb new file mode 100644 index 0000000000..ac44bc0d81 --- /dev/null +++ b/actionview/test/fixtures/test/calling_partial_with_layout.html.erb @@ -0,0 +1 @@ +<%= render(:layout => "layout_for_partial", :partial => "partial_for_use_in_layout", :locals => { :name => "David" }) %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/capturing.erb b/actionview/test/fixtures/test/capturing.erb new file mode 100644 index 0000000000..1addaa40d9 --- /dev/null +++ b/actionview/test/fixtures/test/capturing.erb @@ -0,0 +1,4 @@ +<% days = capture do %> + Dreamy days +<% end %> +<%= days %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/change_priority.html.erb b/actionview/test/fixtures/test/change_priority.html.erb new file mode 100644 index 0000000000..5618977d05 --- /dev/null +++ b/actionview/test/fixtures/test/change_priority.html.erb @@ -0,0 +1,2 @@ +<%= render :partial => "test/json_change_priority", formats: :json %> +HTML Template, but <%= render :partial => "test/changing_priority" %> partial \ No newline at end of file diff --git a/actionview/test/fixtures/test/content_for.erb b/actionview/test/fixtures/test/content_for.erb new file mode 100644 index 0000000000..1fb829f54c --- /dev/null +++ b/actionview/test/fixtures/test/content_for.erb @@ -0,0 +1 @@ +<% content_for :title do -%>Putting stuff in the title!<% end -%>Great stuff! \ No newline at end of file diff --git a/actionview/test/fixtures/test/content_for_concatenated.erb b/actionview/test/fixtures/test/content_for_concatenated.erb new file mode 100644 index 0000000000..e65f629574 --- /dev/null +++ b/actionview/test/fixtures/test/content_for_concatenated.erb @@ -0,0 +1,3 @@ +<% content_for :title, "Putting stuff " + content_for :title, "in the title!" -%> +Great stuff! \ No newline at end of file diff --git a/actionview/test/fixtures/test/content_for_with_parameter.erb b/actionview/test/fixtures/test/content_for_with_parameter.erb new file mode 100644 index 0000000000..aeb6f73ce0 --- /dev/null +++ b/actionview/test/fixtures/test/content_for_with_parameter.erb @@ -0,0 +1,2 @@ +<% content_for :title, "Putting stuff in the title!" -%> +Great stuff! \ No newline at end of file diff --git a/actionview/test/fixtures/test/dont_pick_me b/actionview/test/fixtures/test/dont_pick_me new file mode 100644 index 0000000000..0157c9e503 --- /dev/null +++ b/actionview/test/fixtures/test/dont_pick_me @@ -0,0 +1 @@ +non-template file \ No newline at end of file diff --git a/actionview/test/fixtures/test/dot.directory/render_file_with_ivar.erb b/actionview/test/fixtures/test/dot.directory/render_file_with_ivar.erb new file mode 100644 index 0000000000..8b8a449236 --- /dev/null +++ b/actionview/test/fixtures/test/dot.directory/render_file_with_ivar.erb @@ -0,0 +1 @@ +The secret is <%= @secret %> diff --git a/actionview/test/fixtures/test/formatted_html_erb.html.erb b/actionview/test/fixtures/test/formatted_html_erb.html.erb new file mode 100644 index 0000000000..1c64efabd8 --- /dev/null +++ b/actionview/test/fixtures/test/formatted_html_erb.html.erb @@ -0,0 +1 @@ +formatted html erb \ No newline at end of file diff --git a/actionview/test/fixtures/test/formatted_xml_erb.builder b/actionview/test/fixtures/test/formatted_xml_erb.builder new file mode 100644 index 0000000000..14fd3549fb --- /dev/null +++ b/actionview/test/fixtures/test/formatted_xml_erb.builder @@ -0,0 +1 @@ +xml.test 'failed' \ No newline at end of file diff --git a/actionview/test/fixtures/test/formatted_xml_erb.html.erb b/actionview/test/fixtures/test/formatted_xml_erb.html.erb new file mode 100644 index 0000000000..0c855a604b --- /dev/null +++ b/actionview/test/fixtures/test/formatted_xml_erb.html.erb @@ -0,0 +1 @@ +passed formatted html erb \ No newline at end of file diff --git a/actionview/test/fixtures/test/formatted_xml_erb.xml.erb b/actionview/test/fixtures/test/formatted_xml_erb.xml.erb new file mode 100644 index 0000000000..6ca09d5304 --- /dev/null +++ b/actionview/test/fixtures/test/formatted_xml_erb.xml.erb @@ -0,0 +1 @@ +passed formatted xml erb \ No newline at end of file diff --git a/actionview/test/fixtures/test/greeting.html.erb b/actionview/test/fixtures/test/greeting.html.erb new file mode 100644 index 0000000000..62fb0293f0 --- /dev/null +++ b/actionview/test/fixtures/test/greeting.html.erb @@ -0,0 +1 @@ +

This is grand!

diff --git a/actionview/test/fixtures/test/greeting.xml.erb b/actionview/test/fixtures/test/greeting.xml.erb new file mode 100644 index 0000000000..62fb0293f0 --- /dev/null +++ b/actionview/test/fixtures/test/greeting.xml.erb @@ -0,0 +1 @@ +

This is grand!

diff --git a/actionview/test/fixtures/test/hello,world.erb b/actionview/test/fixtures/test/hello,world.erb new file mode 100644 index 0000000000..bc8fa5e0ca --- /dev/null +++ b/actionview/test/fixtures/test/hello,world.erb @@ -0,0 +1 @@ +Hello w*rld! \ No newline at end of file diff --git a/actionview/test/fixtures/test/hello.builder b/actionview/test/fixtures/test/hello.builder new file mode 100644 index 0000000000..a471553941 --- /dev/null +++ b/actionview/test/fixtures/test/hello.builder @@ -0,0 +1,4 @@ +xml.html do + xml.p "Hello #{@name}" + xml << render(:file => "test/greeting") +end \ No newline at end of file diff --git a/actionview/test/fixtures/test/hello/hello.erb b/actionview/test/fixtures/test/hello/hello.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/test/hello/hello.erb @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/actionview/test/fixtures/test/hello_world.da.html.erb b/actionview/test/fixtures/test/hello_world.da.html.erb new file mode 100644 index 0000000000..10ec443291 --- /dev/null +++ b/actionview/test/fixtures/test/hello_world.da.html.erb @@ -0,0 +1 @@ +Hey verden \ No newline at end of file diff --git a/actionview/test/fixtures/test/hello_world.erb b/actionview/test/fixtures/test/hello_world.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/test/hello_world.erb @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/actionview/test/fixtures/test/hello_world.pt-BR.html.erb b/actionview/test/fixtures/test/hello_world.pt-BR.html.erb new file mode 100644 index 0000000000..773b3c8c6e --- /dev/null +++ b/actionview/test/fixtures/test/hello_world.pt-BR.html.erb @@ -0,0 +1 @@ +Ola mundo \ No newline at end of file diff --git a/actionview/test/fixtures/test/hello_world_container.builder b/actionview/test/fixtures/test/hello_world_container.builder new file mode 100644 index 0000000000..e48d75c405 --- /dev/null +++ b/actionview/test/fixtures/test/hello_world_container.builder @@ -0,0 +1,3 @@ +xml.test do + render :partial => 'hello', :locals => { :xm => xml } +end \ No newline at end of file diff --git a/actionview/test/fixtures/test/hello_world_from_rxml.builder b/actionview/test/fixtures/test/hello_world_from_rxml.builder new file mode 100644 index 0000000000..619a97ba96 --- /dev/null +++ b/actionview/test/fixtures/test/hello_world_from_rxml.builder @@ -0,0 +1,3 @@ +xml.html do + xml.p "Hello" +end diff --git a/actionview/test/fixtures/test/hello_world_with_layout_false.erb b/actionview/test/fixtures/test/hello_world_with_layout_false.erb new file mode 100644 index 0000000000..6769dd60bd --- /dev/null +++ b/actionview/test/fixtures/test/hello_world_with_layout_false.erb @@ -0,0 +1 @@ +Hello world! \ No newline at end of file diff --git a/actionview/test/fixtures/test/hello_world_with_partial.html.erb b/actionview/test/fixtures/test/hello_world_with_partial.html.erb new file mode 100644 index 0000000000..ec31545356 --- /dev/null +++ b/actionview/test/fixtures/test/hello_world_with_partial.html.erb @@ -0,0 +1,2 @@ +Hello world! +<%= render '/test/partial' %> diff --git a/actionview/test/fixtures/test/hello_xml_world.builder b/actionview/test/fixtures/test/hello_xml_world.builder new file mode 100644 index 0000000000..e7081b89fe --- /dev/null +++ b/actionview/test/fixtures/test/hello_xml_world.builder @@ -0,0 +1,11 @@ +xml.html do + xml.head do + xml.title "Hello World" + end + + xml.body do + xml.p "abes" + xml.p "monks" + xml.p "wiseguys" + end +end \ No newline at end of file diff --git a/actionview/test/fixtures/test/html_template.html.erb b/actionview/test/fixtures/test/html_template.html.erb new file mode 100644 index 0000000000..1bbc2b7f09 --- /dev/null +++ b/actionview/test/fixtures/test/html_template.html.erb @@ -0,0 +1 @@ +<%= render :partial => "test/first_json_partial", formats: :json %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/hyphen-ated.erb b/actionview/test/fixtures/test/hyphen-ated.erb new file mode 100644 index 0000000000..cd0875583a --- /dev/null +++ b/actionview/test/fixtures/test/hyphen-ated.erb @@ -0,0 +1 @@ +Hello world! diff --git a/actionview/test/fixtures/test/implicit_content_type.atom.builder b/actionview/test/fixtures/test/implicit_content_type.atom.builder new file mode 100644 index 0000000000..2fcb32d247 --- /dev/null +++ b/actionview/test/fixtures/test/implicit_content_type.atom.builder @@ -0,0 +1,2 @@ +xml.atom do +end diff --git a/actionview/test/fixtures/test/layout_render_file.erb b/actionview/test/fixtures/test/layout_render_file.erb new file mode 100644 index 0000000000..2f8e921c5f --- /dev/null +++ b/actionview/test/fixtures/test/layout_render_file.erb @@ -0,0 +1,2 @@ +<% content_for :title do %>title<% end -%> +<%= render :file => 'layouts/yield' -%> \ No newline at end of file diff --git a/actionview/test/fixtures/test/layout_render_object.erb b/actionview/test/fixtures/test/layout_render_object.erb new file mode 100644 index 0000000000..acc4453c08 --- /dev/null +++ b/actionview/test/fixtures/test/layout_render_object.erb @@ -0,0 +1 @@ +<%= render :layout => "layouts/customers" do |customer| %><%= customer.name %><% end %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/list.erb b/actionview/test/fixtures/test/list.erb new file mode 100644 index 0000000000..0a4bda58ee --- /dev/null +++ b/actionview/test/fixtures/test/list.erb @@ -0,0 +1 @@ +<%= @test_unchanged = 'goodbye' %><%= render :partial => 'customer', :collection => @customers %><%= @test_unchanged %> diff --git a/actionview/test/fixtures/test/nested_layout.erb b/actionview/test/fixtures/test/nested_layout.erb new file mode 100644 index 0000000000..6078f74b4c --- /dev/null +++ b/actionview/test/fixtures/test/nested_layout.erb @@ -0,0 +1,3 @@ +<% content_for :title, "title" -%> +<% content_for :column do -%>column<% end -%> +<%= render :layout => 'layouts/column' do -%>content<% end -%> \ No newline at end of file diff --git a/actionview/test/fixtures/test/nested_streaming.erb b/actionview/test/fixtures/test/nested_streaming.erb new file mode 100644 index 0000000000..55525e0c92 --- /dev/null +++ b/actionview/test/fixtures/test/nested_streaming.erb @@ -0,0 +1,3 @@ +<%- content_for :header do -%>?<%- end -%> +<%= render :template => "test/streaming" %> +? \ No newline at end of file diff --git a/actionview/test/fixtures/test/non_erb_block_content_for.builder b/actionview/test/fixtures/test/non_erb_block_content_for.builder new file mode 100644 index 0000000000..d539a425a4 --- /dev/null +++ b/actionview/test/fixtures/test/non_erb_block_content_for.builder @@ -0,0 +1,4 @@ +content_for :title do + 'Putting stuff in the title!' +end +xml << "Great stuff!" diff --git a/actionview/test/fixtures/test/one.html.erb b/actionview/test/fixtures/test/one.html.erb new file mode 100644 index 0000000000..0151874809 --- /dev/null +++ b/actionview/test/fixtures/test/one.html.erb @@ -0,0 +1 @@ +<%= render :partial => "test/two" %> world \ No newline at end of file diff --git a/actionview/test/fixtures/test/potential_conflicts.erb b/actionview/test/fixtures/test/potential_conflicts.erb new file mode 100644 index 0000000000..a5e964e359 --- /dev/null +++ b/actionview/test/fixtures/test/potential_conflicts.erb @@ -0,0 +1,4 @@ +First: <%= @name %> +<%= render :partial => "person", :locals => { :name => "Stephan" } -%> +Fourth: <%= @name %> +Fifth: <%= name %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/proper_block_detection.erb b/actionview/test/fixtures/test/proper_block_detection.erb new file mode 100644 index 0000000000..b55efbb25d --- /dev/null +++ b/actionview/test/fixtures/test/proper_block_detection.erb @@ -0,0 +1 @@ +<%= @todo %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/render_file_from_template.html.erb b/actionview/test/fixtures/test/render_file_from_template.html.erb new file mode 100644 index 0000000000..fde9f4bb64 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_from_template.html.erb @@ -0,0 +1 @@ +<%= render :file => @path %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/render_file_with_ivar.erb b/actionview/test/fixtures/test/render_file_with_ivar.erb new file mode 100644 index 0000000000..8b8a449236 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_with_ivar.erb @@ -0,0 +1 @@ +The secret is <%= @secret %> diff --git a/actionview/test/fixtures/test/render_file_with_locals.erb b/actionview/test/fixtures/test/render_file_with_locals.erb new file mode 100644 index 0000000000..ebe09faee6 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_with_locals.erb @@ -0,0 +1 @@ +The secret is <%= secret %> diff --git a/actionview/test/fixtures/test/render_file_with_locals_and_default.erb b/actionview/test/fixtures/test/render_file_with_locals_and_default.erb new file mode 100644 index 0000000000..9b4900acc5 --- /dev/null +++ b/actionview/test/fixtures/test/render_file_with_locals_and_default.erb @@ -0,0 +1 @@ +<%= secret ||= 'one' %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb b/actionview/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb new file mode 100644 index 0000000000..0740b2d07c --- /dev/null +++ b/actionview/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb @@ -0,0 +1 @@ +Hey HTML! diff --git a/actionview/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb b/actionview/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb new file mode 100644 index 0000000000..4a11845cfe --- /dev/null +++ b/actionview/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb @@ -0,0 +1 @@ +Hello HTML! \ No newline at end of file diff --git a/actionview/test/fixtures/test/render_implicit_js_template_without_layout.js.erb b/actionview/test/fixtures/test/render_implicit_js_template_without_layout.js.erb new file mode 100644 index 0000000000..892ae5eca2 --- /dev/null +++ b/actionview/test/fixtures/test/render_implicit_js_template_without_layout.js.erb @@ -0,0 +1 @@ +alert('hello'); \ No newline at end of file diff --git a/actionview/test/fixtures/test/render_partial_inside_directory.html.erb b/actionview/test/fixtures/test/render_partial_inside_directory.html.erb new file mode 100644 index 0000000000..1461b95186 --- /dev/null +++ b/actionview/test/fixtures/test/render_partial_inside_directory.html.erb @@ -0,0 +1 @@ +<%= render partial: 'test/_directory/partial_with_locales', locals: {'name' => 'Jane'} %> diff --git a/actionview/test/fixtures/test/render_to_string_test.erb b/actionview/test/fixtures/test/render_to_string_test.erb new file mode 100644 index 0000000000..6e267e8634 --- /dev/null +++ b/actionview/test/fixtures/test/render_to_string_test.erb @@ -0,0 +1 @@ +The value of foo is: ::<%= @foo %>:: diff --git a/actionview/test/fixtures/test/render_two_partials.html.erb b/actionview/test/fixtures/test/render_two_partials.html.erb new file mode 100644 index 0000000000..3db6025860 --- /dev/null +++ b/actionview/test/fixtures/test/render_two_partials.html.erb @@ -0,0 +1,2 @@ +<%= render :partial => 'partial', :locals => {'first' => '1'} %> +<%= render :partial => 'partial', :locals => {'second' => '2'} %> diff --git a/actionview/test/fixtures/test/streaming.erb b/actionview/test/fixtures/test/streaming.erb new file mode 100644 index 0000000000..fb9b8b1ade --- /dev/null +++ b/actionview/test/fixtures/test/streaming.erb @@ -0,0 +1,3 @@ +<%- provide :header do -%>Yes, <%- end -%> +this works +<%- content_for :footer, " like a charm" -%> diff --git a/actionview/test/fixtures/test/streaming_buster.erb b/actionview/test/fixtures/test/streaming_buster.erb new file mode 100644 index 0000000000..4221d56dcc --- /dev/null +++ b/actionview/test/fixtures/test/streaming_buster.erb @@ -0,0 +1,3 @@ +<%= yield :foo -%> +This won't look +<% provide :unknown, " good." -%> diff --git a/actionview/test/fixtures/test/sub_template_raise.html.erb b/actionview/test/fixtures/test/sub_template_raise.html.erb new file mode 100644 index 0000000000..f38c0bda90 --- /dev/null +++ b/actionview/test/fixtures/test/sub_template_raise.html.erb @@ -0,0 +1 @@ +<%= render :partial => "test/raise" %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/template.erb b/actionview/test/fixtures/test/template.erb new file mode 100644 index 0000000000..785afa8f6a --- /dev/null +++ b/actionview/test/fixtures/test/template.erb @@ -0,0 +1 @@ +<%= template.path %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/update_element_with_capture.erb b/actionview/test/fixtures/test/update_element_with_capture.erb new file mode 100644 index 0000000000..fa3ef200f9 --- /dev/null +++ b/actionview/test/fixtures/test/update_element_with_capture.erb @@ -0,0 +1,9 @@ +<% replacement_function = update_element_function("products", :action => :update) do %> +

Product 1

+

Product 2

+<% end %> +<%= javascript_tag(replacement_function) %> + +<% update_element_function("status", :action => :update, :binding => binding) do %> + You bought something! +<% end %> diff --git a/actionview/test/fixtures/test/using_layout_around_block.html.erb b/actionview/test/fixtures/test/using_layout_around_block.html.erb new file mode 100644 index 0000000000..3d6661df9a --- /dev/null +++ b/actionview/test/fixtures/test/using_layout_around_block.html.erb @@ -0,0 +1 @@ +<%= render(:layout => "layout_for_partial", :locals => { :name => "David" }) do %>Inside from block<% end %> \ No newline at end of file diff --git a/actionview/test/fixtures/test/utf8.html.erb b/actionview/test/fixtures/test/utf8.html.erb new file mode 100644 index 0000000000..ac98c2f012 --- /dev/null +++ b/actionview/test/fixtures/test/utf8.html.erb @@ -0,0 +1,4 @@ +Русский <%= render :partial => 'test/utf8_partial' %> +<%= "日".encoding %> +<%= @output_buffer.encoding %> +<%= __ENCODING__ %> diff --git a/actionview/test/fixtures/test/utf8_magic.html.erb b/actionview/test/fixtures/test/utf8_magic.html.erb new file mode 100644 index 0000000000..257279c29f --- /dev/null +++ b/actionview/test/fixtures/test/utf8_magic.html.erb @@ -0,0 +1,5 @@ +<%# encoding: utf-8 -%> +Русский <%= render :partial => 'test/utf8_partial_magic' %> +<%= "日".encoding %> +<%= @output_buffer.encoding %> +<%= __ENCODING__ %> diff --git a/actionview/test/fixtures/test/utf8_magic_with_bare_partial.html.erb b/actionview/test/fixtures/test/utf8_magic_with_bare_partial.html.erb new file mode 100644 index 0000000000..cb22692f9a --- /dev/null +++ b/actionview/test/fixtures/test/utf8_magic_with_bare_partial.html.erb @@ -0,0 +1,5 @@ +<%# encoding: utf-8 -%> +Русский <%= render :partial => 'test/utf8_partial' %> +<%= "日".encoding %> +<%= @output_buffer.encoding %> +<%= __ENCODING__ %> diff --git a/actionview/test/fixtures/test/with_html_partial.html.erb b/actionview/test/fixtures/test/with_html_partial.html.erb new file mode 100644 index 0000000000..d84d909d64 --- /dev/null +++ b/actionview/test/fixtures/test/with_html_partial.html.erb @@ -0,0 +1 @@ +<%= render :partial => "partial_only_html" %> diff --git a/actionview/test/fixtures/test/with_partial.html.erb b/actionview/test/fixtures/test/with_partial.html.erb new file mode 100644 index 0000000000..7502364cf5 --- /dev/null +++ b/actionview/test/fixtures/test/with_partial.html.erb @@ -0,0 +1 @@ +<%= render :partial => "partial_only" %> diff --git a/actionview/test/fixtures/test/with_partial.text.erb b/actionview/test/fixtures/test/with_partial.text.erb new file mode 100644 index 0000000000..5f068ebf27 --- /dev/null +++ b/actionview/test/fixtures/test/with_partial.text.erb @@ -0,0 +1 @@ +**<%= render :partial => "partial_only" %>** diff --git a/actionview/test/fixtures/test/with_xml_template.html.erb b/actionview/test/fixtures/test/with_xml_template.html.erb new file mode 100644 index 0000000000..e54a7cd001 --- /dev/null +++ b/actionview/test/fixtures/test/with_xml_template.html.erb @@ -0,0 +1 @@ +<%= render :template => "test/greeting", :formats => :xml %> diff --git a/actionview/test/fixtures/topic.rb b/actionview/test/fixtures/topic.rb new file mode 100644 index 0000000000..9fa9746535 --- /dev/null +++ b/actionview/test/fixtures/topic.rb @@ -0,0 +1,3 @@ +class Topic < ActiveRecord::Base + has_many :replies, :dependent => :destroy +end diff --git a/actionview/test/fixtures/topics.yml b/actionview/test/fixtures/topics.yml new file mode 100644 index 0000000000..7fdd49d54e --- /dev/null +++ b/actionview/test/fixtures/topics.yml @@ -0,0 +1,22 @@ +futurama: + id: 1 + title: Isnt futurama awesome? + subtitle: It really is, isnt it. + content: I like futurama + created_at: <%= 1.day.ago.to_s(:db) %> + updated_at: + +harvey_birdman: + id: 2 + title: Harvey Birdman is the king of all men + subtitle: yup + content: It really is + created_at: <%= 2.hours.ago.to_s(:db) %> + updated_at: + +rails: + id: 3 + title: Rails is nice + subtitle: It makes me happy + content: except when I have to hack internals to fix pagination. even then really. + created_at: <%= 20.minutes.ago.to_s(:db) %> diff --git a/actionview/test/fixtures/topics/_topic.html.erb b/actionview/test/fixtures/topics/_topic.html.erb new file mode 100644 index 0000000000..98659ca098 --- /dev/null +++ b/actionview/test/fixtures/topics/_topic.html.erb @@ -0,0 +1 @@ +<%= topic.title %> \ No newline at end of file diff --git a/actionview/test/fixtures/translations/templates/array.erb b/actionview/test/fixtures/translations/templates/array.erb new file mode 100644 index 0000000000..d86045a172 --- /dev/null +++ b/actionview/test/fixtures/translations/templates/array.erb @@ -0,0 +1 @@ +<%= t('.foo.bar') %> diff --git a/actionview/test/fixtures/translations/templates/default.erb b/actionview/test/fixtures/translations/templates/default.erb new file mode 100644 index 0000000000..8b70031071 --- /dev/null +++ b/actionview/test/fixtures/translations/templates/default.erb @@ -0,0 +1 @@ +<%= t('.missing', :default => :'.foo') %> diff --git a/actionview/test/fixtures/translations/templates/found.erb b/actionview/test/fixtures/translations/templates/found.erb new file mode 100644 index 0000000000..080c9c0aee --- /dev/null +++ b/actionview/test/fixtures/translations/templates/found.erb @@ -0,0 +1 @@ +<%= t('.foo') %> diff --git a/actionview/test/fixtures/translations/templates/missing.erb b/actionview/test/fixtures/translations/templates/missing.erb new file mode 100644 index 0000000000..0f3f17f8ef --- /dev/null +++ b/actionview/test/fixtures/translations/templates/missing.erb @@ -0,0 +1 @@ +<%= t('.missing') %> diff --git a/actionview/test/fixtures/with_format.json.erb b/actionview/test/fixtures/with_format.json.erb new file mode 100644 index 0000000000..a7f480ab1d --- /dev/null +++ b/actionview/test/fixtures/with_format.json.erb @@ -0,0 +1 @@ +<%= render :partial => 'missing', :formats => [:json] %> diff --git a/actionview/test/lib/controller/fake_controllers.rb b/actionview/test/lib/controller/fake_controllers.rb new file mode 100644 index 0000000000..1a2863b689 --- /dev/null +++ b/actionview/test/lib/controller/fake_controllers.rb @@ -0,0 +1,35 @@ +class ContentController < ActionController::Base; end + +module Admin + class AccountsController < ActionController::Base; end + class PostsController < ActionController::Base; end + class StuffController < ActionController::Base; end + class UserController < ActionController::Base; end + class UsersController < ActionController::Base; end +end + +module Api + class UsersController < ActionController::Base; end + class ProductsController < ActionController::Base; end +end + +class AccountController < ActionController::Base; end +class ArchiveController < ActionController::Base; end +class ArticlesController < ActionController::Base; end +class BarController < ActionController::Base; end +class BlogController < ActionController::Base; end +class BooksController < ActionController::Base; end +class CarsController < ActionController::Base; end +class CcController < ActionController::Base; end +class CController < ActionController::Base; end +class FooController < ActionController::Base; end +class GeocodeController < ActionController::Base; end +class NewsController < ActionController::Base; end +class NotesController < ActionController::Base; end +class PagesController < ActionController::Base; end +class PeopleController < ActionController::Base; end +class PostsController < ActionController::Base; end +class SubpathBooksController < ActionController::Base; end +class SymbolsController < ActionController::Base; end +class UserController < ActionController::Base; end +class UsersController < ActionController::Base; end diff --git a/actionview/test/lib/controller/fake_models.rb b/actionview/test/lib/controller/fake_models.rb new file mode 100644 index 0000000000..82f38b5309 --- /dev/null +++ b/actionview/test/lib/controller/fake_models.rb @@ -0,0 +1,219 @@ +require "active_model" + +class Customer < Struct.new(:name, :id) + extend ActiveModel::Naming + include ActiveModel::Conversion + + undef_method :to_json + + def to_xml(options={}) + if options[:builder] + options[:builder].name name + else + "#{name}" + end + end + + def to_js(options={}) + "name: #{name.inspect}" + end + alias :to_text :to_js + + def errors + [] + end + + def persisted? + id.present? + end +end + +class BadCustomer < Customer +end + +class GoodCustomer < Customer +end + +class ValidatedCustomer < Customer + def errors + if name =~ /Sikachu/i + [] + else + [{:name => "is invalid"}] + end + end +end + +module Quiz + class Question < Struct.new(:name, :id) + extend ActiveModel::Naming + include ActiveModel::Conversion + + def persisted? + id.present? + end + end + + class Store < Question + end +end + +class Post < Struct.new(:title, :author_name, :body, :secret, :persisted, :written_on, :cost) + extend ActiveModel::Naming + include ActiveModel::Conversion + extend ActiveModel::Translation + + alias_method :secret?, :secret + alias_method :persisted?, :persisted + + def initialize(*args) + super + @persisted = false + end + + attr_accessor :author + def author_attributes=(attributes); end + + attr_accessor :comments, :comment_ids + def comments_attributes=(attributes); end + + attr_accessor :tags + def tags_attributes=(attributes); end +end + +class Comment + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + attr_reader :post_id + def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end + def to_key; id ? [id] : nil end + def save; @id = 1; @post_id = 1 end + def persisted?; @id.present? end + def to_param; @id.to_s; end + def name + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end + + attr_accessor :relevances + def relevances_attributes=(attributes); end + + attr_accessor :body +end + +class Tag + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + attr_reader :post_id + def initialize(id = nil, post_id = nil); @id, @post_id = id, post_id end + def to_key; id ? [id] : nil end + def save; @id = 1; @post_id = 1 end + def persisted?; @id.present? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end + + attr_accessor :relevances + def relevances_attributes=(attributes); end + +end + +class CommentRelevance + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + attr_reader :comment_id + def initialize(id = nil, comment_id = nil); @id, @comment_id = id, comment_id end + def to_key; id ? [id] : nil end + def save; @id = 1; @comment_id = 1 end + def persisted?; @id.present? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end +end + +class Sheep + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + def to_key; id ? [id] : nil end + def save; @id = 1 end + def new_record?; @id.nil? end + def name + @id.nil? ? 'new sheep' : "sheep ##{@id}" + end +end + + +class TagRelevance + extend ActiveModel::Naming + include ActiveModel::Conversion + + attr_reader :id + attr_reader :tag_id + def initialize(id = nil, tag_id = nil); @id, @tag_id = id, tag_id end + def to_key; id ? [id] : nil end + def save; @id = 1; @tag_id = 1 end + def persisted?; @id.present? end + def to_param; @id; end + def value + @id.nil? ? "new #{self.class.name.downcase}" : "#{self.class.name.downcase} ##{@id}" + end +end + +class Author < Comment + attr_accessor :post + def post_attributes=(attributes); end +end + +class HashBackedAuthor < Hash + extend ActiveModel::Naming + include ActiveModel::Conversion + + def persisted?; false; end + + def name + "hash backed author" + end +end + +module Blog + def self.use_relative_model_naming? + true + end + + class Post < Struct.new(:title, :id) + extend ActiveModel::Naming + include ActiveModel::Conversion + + def persisted? + id.present? + end + end +end + +class ArelLike + def to_ary + true + end + def each + a = Array.new(2) { |id| Comment.new(id + 1) } + a.each { |i| yield i } + end +end + +class RenderJsonTestException < Exception + def to_json(options = nil) + return { :error => self.class.name, :message => self.to_s }.to_json + end +end + +class Car < Struct.new(:color) +end diff --git a/actionview/test/template/active_model_helper_test.rb b/actionview/test/template/active_model_helper_test.rb new file mode 100644 index 0000000000..86bccdfade --- /dev/null +++ b/actionview/test/template/active_model_helper_test.rb @@ -0,0 +1,99 @@ +require 'abstract_unit' + +class ActiveModelHelperTest < ActionView::TestCase + tests ActionView::Helpers::ActiveModelHelper + + silence_warnings do + class Post < Struct.new(:author_name, :body, :updated_at) + include ActiveModel::Conversion + include ActiveModel::Validations + + def persisted? + false + end + end + end + + def setup + super + + @post = Post.new + @post.errors[:author_name] << "can't be empty" + @post.errors[:body] << "foo" + @post.errors[:updated_at] << "bar" + + @post.author_name = "" + @post.body = "Back to the hill and over it again!" + @post.updated_at = Date.new(2004, 6, 15) + end + + def test_text_area_with_errors + assert_dom_equal( + %(
), + text_area("post", "body") + ) + end + + def test_text_field_with_errors + assert_dom_equal( + %(
), + text_field("post", "author_name") + ) + end + + def test_select_with_errors + assert_dom_equal( + %(
), + select("post", "author_name", [:a, :b]) + ) + end + + def test_select_with_errors_and_blank_option + expected_dom = %(
) + assert_dom_equal(expected_dom, select("post", "author_name", [:a, :b], :include_blank => 'Choose one...')) + assert_dom_equal(expected_dom, select("post", "author_name", [:a, :b], :prompt => 'Choose one...')) + end + + def test_date_select_with_errors + assert_dom_equal( + %(
\n\n\n
), + date_select("post", "updated_at", :discard_month => true, :discard_day => true, :start_year => 2004, :end_year => 2005) + ) + end + + def test_datetime_select_with_errors + assert_dom_equal( + %(
\n\n\n\n : \n
), + datetime_select("post", "updated_at", :discard_year => true, :discard_month => true, :discard_day => true, :minute_step => 60) + ) + end + + def test_time_select_with_errors + assert_dom_equal( + %(
\n\n\n\n : \n
), + time_select("post", "updated_at", :minute_step => 60) + ) + end + + def test_hidden_field_does_not_render_errors + assert_dom_equal( + %(), + hidden_field("post", "author_name") + ) + end + + def test_field_error_proc + old_proc = ActionView::Base.field_error_proc + ActionView::Base.field_error_proc = Proc.new do |html_tag, instance| + %(
#{html_tag} #{[instance.error_message].join(', ')}
).html_safe + end + + assert_dom_equal( + %(
can't be empty
), + text_field("post", "author_name") + ) + ensure + ActionView::Base.field_error_proc = old_proc if old_proc + end + +end diff --git a/actionview/test/template/asset_tag_helper_test.rb b/actionview/test/template/asset_tag_helper_test.rb new file mode 100644 index 0000000000..214a13654e --- /dev/null +++ b/actionview/test/template/asset_tag_helper_test.rb @@ -0,0 +1,762 @@ +require 'zlib' +require 'abstract_unit' +require 'active_support/ordered_options' + +class FakeController + attr_accessor :request + + def config + @config ||= ActiveSupport::InheritableOptions.new(ActionController::Base.config) + end +end + +class AssetTagHelperTest < ActionView::TestCase + tests ActionView::Helpers::AssetTagHelper + + attr_reader :request + + def setup + super + + @controller = BasicController.new + + @request = Class.new do + attr_accessor :script_name + def protocol() 'http://' end + def ssl?() false end + def host_with_port() 'localhost' end + def base_url() 'http://www.example.com' end + end.new + + @controller.request = @request + end + + def url_for(*args) + "http://www.example.com" + end + + AssetPathToTag = { + %(asset_path("foo")) => %(/foo), + %(asset_path("style.css")) => %(/style.css), + %(asset_path("xmlhr.js")) => %(/xmlhr.js), + %(asset_path("xml.png")) => %(/xml.png), + %(asset_path("dir/xml.png")) => %(/dir/xml.png), + %(asset_path("/dir/xml.png")) => %(/dir/xml.png), + + %(asset_path("script.min")) => %(/script.min), + %(asset_path("script.min.js")) => %(/script.min.js), + %(asset_path("style.min")) => %(/style.min), + %(asset_path("style.min.css")) => %(/style.min.css), + + %(asset_path("http://www.outside.com/image.jpg")) => %(http://www.outside.com/image.jpg), + %(asset_path("HTTP://www.outside.com/image.jpg")) => %(HTTP://www.outside.com/image.jpg), + + %(asset_path("style", type: :stylesheet)) => %(/stylesheets/style.css), + %(asset_path("xmlhr", type: :javascript)) => %(/javascripts/xmlhr.js), + %(asset_path("xml.png", type: :image)) => %(/images/xml.png) + } + + AutoDiscoveryToTag = { + %(auto_discovery_link_tag) => %(), + %(auto_discovery_link_tag(:rss)) => %(), + %(auto_discovery_link_tag(:atom)) => %(), + %(auto_discovery_link_tag(:rss, :action => "feed")) => %(), + %(auto_discovery_link_tag(:rss, "http://localhost/feed")) => %(), + %(auto_discovery_link_tag(:rss, "//localhost/feed")) => %(), + %(auto_discovery_link_tag(:rss, {:action => "feed"}, {:title => "My RSS"})) => %(), + %(auto_discovery_link_tag(:rss, {}, {:title => "My RSS"})) => %(), + %(auto_discovery_link_tag(nil, {}, {:type => "text/html"})) => %(), + %(auto_discovery_link_tag(nil, {}, {:title => "No stream.. really", :type => "text/html"})) => %(), + %(auto_discovery_link_tag(:rss, {}, {:title => "My RSS", :type => "text/html"})) => %(), + %(auto_discovery_link_tag(:atom, {}, {:rel => "Not so alternate"})) => %(), + } + + JavascriptPathToTag = { + %(javascript_path("xmlhr")) => %(/javascripts/xmlhr.js), + %(javascript_path("super/xmlhr")) => %(/javascripts/super/xmlhr.js), + %(javascript_path("/super/xmlhr.js")) => %(/super/xmlhr.js), + %(javascript_path("xmlhr.min")) => %(/javascripts/xmlhr.min.js), + %(javascript_path("xmlhr.min.js")) => %(/javascripts/xmlhr.min.js), + + %(javascript_path("xmlhr.js?123")) => %(/javascripts/xmlhr.js?123), + %(javascript_path("xmlhr.js?body=1")) => %(/javascripts/xmlhr.js?body=1), + %(javascript_path("xmlhr.js#hash")) => %(/javascripts/xmlhr.js#hash), + %(javascript_path("xmlhr.js?123#hash")) => %(/javascripts/xmlhr.js?123#hash) + } + + PathToJavascriptToTag = { + %(path_to_javascript("xmlhr")) => %(/javascripts/xmlhr.js), + %(path_to_javascript("super/xmlhr")) => %(/javascripts/super/xmlhr.js), + %(path_to_javascript("/super/xmlhr.js")) => %(/super/xmlhr.js) + } + + JavascriptUrlToTag = { + %(javascript_url("xmlhr")) => %(http://www.example.com/javascripts/xmlhr.js), + %(javascript_url("super/xmlhr")) => %(http://www.example.com/javascripts/super/xmlhr.js), + %(javascript_url("/super/xmlhr.js")) => %(http://www.example.com/super/xmlhr.js) + } + + UrlToJavascriptToTag = { + %(url_to_javascript("xmlhr")) => %(http://www.example.com/javascripts/xmlhr.js), + %(url_to_javascript("super/xmlhr")) => %(http://www.example.com/javascripts/super/xmlhr.js), + %(url_to_javascript("/super/xmlhr.js")) => %(http://www.example.com/super/xmlhr.js) + } + + JavascriptIncludeToTag = { + %(javascript_include_tag("bank")) => %(), + %(javascript_include_tag("bank.js")) => %(), + %(javascript_include_tag("bank", :lang => "vbscript")) => %(), + + %(javascript_include_tag("http://example.com/all")) => %(), + %(javascript_include_tag("http://example.com/all.js")) => %(), + %(javascript_include_tag("//example.com/all.js")) => %(), + } + + StylePathToTag = { + %(stylesheet_path("bank")) => %(/stylesheets/bank.css), + %(stylesheet_path("bank.css")) => %(/stylesheets/bank.css), + %(stylesheet_path('subdir/subdir')) => %(/stylesheets/subdir/subdir.css), + %(stylesheet_path('/subdir/subdir.css')) => %(/subdir/subdir.css), + %(stylesheet_path("style.min")) => %(/stylesheets/style.min.css), + %(stylesheet_path("style.min.css")) => %(/stylesheets/style.min.css) + } + + PathToStyleToTag = { + %(path_to_stylesheet("style")) => %(/stylesheets/style.css), + %(path_to_stylesheet("style.css")) => %(/stylesheets/style.css), + %(path_to_stylesheet('dir/file')) => %(/stylesheets/dir/file.css), + %(path_to_stylesheet('/dir/file.rcss', :extname => false)) => %(/dir/file.rcss), + %(path_to_stylesheet('/dir/file', :extname => '.rcss')) => %(/dir/file.rcss) + } + + StyleUrlToTag = { + %(stylesheet_url("bank")) => %(http://www.example.com/stylesheets/bank.css), + %(stylesheet_url("bank.css")) => %(http://www.example.com/stylesheets/bank.css), + %(stylesheet_url('subdir/subdir')) => %(http://www.example.com/stylesheets/subdir/subdir.css), + %(stylesheet_url('/subdir/subdir.css')) => %(http://www.example.com/subdir/subdir.css) + } + + UrlToStyleToTag = { + %(url_to_stylesheet("style")) => %(http://www.example.com/stylesheets/style.css), + %(url_to_stylesheet("style.css")) => %(http://www.example.com/stylesheets/style.css), + %(url_to_stylesheet('dir/file')) => %(http://www.example.com/stylesheets/dir/file.css), + %(url_to_stylesheet('/dir/file.rcss', :extname => false)) => %(http://www.example.com/dir/file.rcss), + %(url_to_stylesheet('/dir/file', :extname => '.rcss')) => %(http://www.example.com/dir/file.rcss) + } + + StyleLinkToTag = { + %(stylesheet_link_tag("bank")) => %(), + %(stylesheet_link_tag("bank.css")) => %(), + %(stylesheet_link_tag("/elsewhere/file")) => %(), + %(stylesheet_link_tag("subdir/subdir")) => %(), + %(stylesheet_link_tag("bank", :media => "all")) => %(), + + %(stylesheet_link_tag("http://www.example.com/styles/style")) => %(), + %(stylesheet_link_tag("http://www.example.com/styles/style.css")) => %(), + %(stylesheet_link_tag("//www.example.com/styles/style.css")) => %(), + } + + ImagePathToTag = { + %(image_path("xml")) => %(/images/xml), + %(image_path("xml.png")) => %(/images/xml.png), + %(image_path("dir/xml.png")) => %(/images/dir/xml.png), + %(image_path("/dir/xml.png")) => %(/dir/xml.png) + } + + PathToImageToTag = { + %(path_to_image("xml")) => %(/images/xml), + %(path_to_image("xml.png")) => %(/images/xml.png), + %(path_to_image("dir/xml.png")) => %(/images/dir/xml.png), + %(path_to_image("/dir/xml.png")) => %(/dir/xml.png) + } + + ImageUrlToTag = { + %(image_url("xml")) => %(http://www.example.com/images/xml), + %(image_url("xml.png")) => %(http://www.example.com/images/xml.png), + %(image_url("dir/xml.png")) => %(http://www.example.com/images/dir/xml.png), + %(image_url("/dir/xml.png")) => %(http://www.example.com/dir/xml.png) + } + + UrlToImageToTag = { + %(url_to_image("xml")) => %(http://www.example.com/images/xml), + %(url_to_image("xml.png")) => %(http://www.example.com/images/xml.png), + %(url_to_image("dir/xml.png")) => %(http://www.example.com/images/dir/xml.png), + %(url_to_image("/dir/xml.png")) => %(http://www.example.com/dir/xml.png) + } + + ImageLinkToTag = { + %(image_tag("xml.png")) => %(Xml), + %(image_tag("rss.gif", :alt => "rss syndication")) => %(rss syndication), + %(image_tag("gold.png", :size => "20")) => %(Gold), + %(image_tag("gold.png", :size => "45x70")) => %(Gold), + %(image_tag("gold.png", "size" => "45x70")) => %(Gold), + %(image_tag("error.png", "size" => "45 x 70")) => %(Error), + %(image_tag("error.png", "size" => "x")) => %(Error), + %(image_tag("google.com.png")) => %(Google.com), + %(image_tag("slash..png")) => %(Slash.), + %(image_tag(".pdf.png")) => %(.pdf), + %(image_tag("http://www.rubyonrails.com/images/rails.png")) => %(Rails), + %(image_tag("//www.rubyonrails.com/images/rails.png")) => %(Rails), + %(image_tag("mouse.png", :alt => nil)) => %(), + %(image_tag("data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", :alt => nil)) => %(), + %(image_tag("")) => %() + } + + FaviconLinkToTag = { + %(favicon_link_tag) => %(), + %(favicon_link_tag 'favicon.ico') => %(), + %(favicon_link_tag 'favicon.ico', :rel => 'foo') => %(), + %(favicon_link_tag 'favicon.ico', :rel => 'foo', :type => 'bar') => %(), + %(favicon_link_tag 'mb-icon.png', :rel => 'apple-touch-icon', :type => 'image/png') => %() + } + + VideoPathToTag = { + %(video_path("xml")) => %(/videos/xml), + %(video_path("xml.ogg")) => %(/videos/xml.ogg), + %(video_path("dir/xml.ogg")) => %(/videos/dir/xml.ogg), + %(video_path("/dir/xml.ogg")) => %(/dir/xml.ogg) + } + + PathToVideoToTag = { + %(path_to_video("xml")) => %(/videos/xml), + %(path_to_video("xml.ogg")) => %(/videos/xml.ogg), + %(path_to_video("dir/xml.ogg")) => %(/videos/dir/xml.ogg), + %(path_to_video("/dir/xml.ogg")) => %(/dir/xml.ogg) + } + + VideoUrlToTag = { + %(video_url("xml")) => %(http://www.example.com/videos/xml), + %(video_url("xml.ogg")) => %(http://www.example.com/videos/xml.ogg), + %(video_url("dir/xml.ogg")) => %(http://www.example.com/videos/dir/xml.ogg), + %(video_url("/dir/xml.ogg")) => %(http://www.example.com/dir/xml.ogg) + } + + UrlToVideoToTag = { + %(url_to_video("xml")) => %(http://www.example.com/videos/xml), + %(url_to_video("xml.ogg")) => %(http://www.example.com/videos/xml.ogg), + %(url_to_video("dir/xml.ogg")) => %(http://www.example.com/videos/dir/xml.ogg), + %(url_to_video("/dir/xml.ogg")) => %(http://www.example.com/dir/xml.ogg) + } + + VideoLinkToTag = { + %(video_tag("xml.ogg")) => %(), + %(video_tag("rss.m4v", :autoplay => true, :controls => true)) => %(), + %(video_tag("rss.m4v", :autobuffer => true)) => %(), + %(video_tag("gold.m4v", :size => "160x120")) => %(), + %(video_tag("gold.m4v", "size" => "320x240")) => %(), + %(video_tag("trailer.ogg", :poster => "screenshot.png")) => %(), + %(video_tag("error.avi", "size" => "100")) => %(), + %(video_tag("error.avi", "size" => "100 x 100")) => %(), + %(video_tag("error.avi", "size" => "x")) => %(), + %(video_tag("http://media.rubyonrails.org/video/rails_blog_2.mov")) => %(), + %(video_tag("//media.rubyonrails.org/video/rails_blog_2.mov")) => %(), + %(video_tag("multiple.ogg", "multiple.avi")) => %(), + %(video_tag(["multiple.ogg", "multiple.avi"])) => %(), + %(video_tag(["multiple.ogg", "multiple.avi"], :size => "160x120", :controls => true)) => %() + } + + AudioPathToTag = { + %(audio_path("xml")) => %(/audios/xml), + %(audio_path("xml.wav")) => %(/audios/xml.wav), + %(audio_path("dir/xml.wav")) => %(/audios/dir/xml.wav), + %(audio_path("/dir/xml.wav")) => %(/dir/xml.wav) + } + + PathToAudioToTag = { + %(path_to_audio("xml")) => %(/audios/xml), + %(path_to_audio("xml.wav")) => %(/audios/xml.wav), + %(path_to_audio("dir/xml.wav")) => %(/audios/dir/xml.wav), + %(path_to_audio("/dir/xml.wav")) => %(/dir/xml.wav) + } + + AudioUrlToTag = { + %(audio_url("xml")) => %(http://www.example.com/audios/xml), + %(audio_url("xml.wav")) => %(http://www.example.com/audios/xml.wav), + %(audio_url("dir/xml.wav")) => %(http://www.example.com/audios/dir/xml.wav), + %(audio_url("/dir/xml.wav")) => %(http://www.example.com/dir/xml.wav) + } + + UrlToAudioToTag = { + %(url_to_audio("xml")) => %(http://www.example.com/audios/xml), + %(url_to_audio("xml.wav")) => %(http://www.example.com/audios/xml.wav), + %(url_to_audio("dir/xml.wav")) => %(http://www.example.com/audios/dir/xml.wav), + %(url_to_audio("/dir/xml.wav")) => %(http://www.example.com/dir/xml.wav) + } + + AudioLinkToTag = { + %(audio_tag("xml.wav")) => %(), + %(audio_tag("rss.wav", :autoplay => true, :controls => true)) => %(), + %(audio_tag("http://media.rubyonrails.org/audio/rails_blog_2.mov")) => %(), + %(audio_tag("//media.rubyonrails.org/audio/rails_blog_2.mov")) => %(), + %(audio_tag("audio.mp3", "audio.ogg")) => %(), + %(audio_tag(["audio.mp3", "audio.ogg"])) => %(), + %(audio_tag(["audio.mp3", "audio.ogg"], :autobuffer => true, :controls => true)) => %() + } + + FontPathToTag = { + %(font_path("font.eot")) => %(/fonts/font.eot), + %(font_path("font.eot#iefix")) => %(/fonts/font.eot#iefix), + %(font_path("font.woff")) => %(/fonts/font.woff), + %(font_path("font.ttf")) => %(/fonts/font.ttf), + %(font_path("font.ttf?123")) => %(/fonts/font.ttf?123) + } + + def test_autodiscovery_link_tag_with_unknown_type_but_not_pass_type_option_key + assert_raise(ArgumentError) do + auto_discovery_link_tag(:xml) + end + end + + def test_autodiscovery_link_tag_with_unknown_type + result = auto_discovery_link_tag(:xml, '/feed.xml', :type => 'application/xml') + expected = %() + assert_equal expected, result + end + + def test_asset_path_tag + AssetPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_compute_asset_public_path + assert_equal "/robots.txt", compute_asset_path("robots.txt") + assert_equal "/robots.txt", compute_asset_path("/robots.txt") + assert_equal "/javascripts/foo.js", compute_asset_path("foo.js", :type => :javascript) + assert_equal "/javascripts/foo.js", compute_asset_path("/foo.js", :type => :javascript) + assert_equal "/stylesheets/foo.css", compute_asset_path("foo.css", :type => :stylesheet) + end + + def test_auto_discovery_link_tag + AutoDiscoveryToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_javascript_path + JavascriptPathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_path_to_javascript_alias_for_javascript_path + PathToJavascriptToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_javascript_url + JavascriptUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_url_to_javascript_alias_for_javascript_url + UrlToJavascriptToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_javascript_include_tag + JavascriptIncludeToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_javascript_include_tag_with_missing_source + assert_nothing_raised { + javascript_include_tag('missing_security_guard') + } + + assert_nothing_raised { + javascript_include_tag('http://example.com/css/missing_security_guard') + } + end + + def test_javascript_include_tag_is_html_safe + assert javascript_include_tag("prototype").html_safe? + end + + def test_javascript_include_tag_relative_protocol + @controller.config.asset_host = "assets.example.com" + assert_dom_equal %(), javascript_include_tag('prototype', protocol: :relative) + end + + def test_javascript_include_tag_default_protocol + @controller.config.asset_host = "assets.example.com" + @controller.config.default_asset_host_protocol = :relative + assert_dom_equal %(), javascript_include_tag('prototype') + end + + def test_stylesheet_path + StylePathToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_path_to_stylesheet_alias_for_stylesheet_path + PathToStyleToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_stylesheet_url + StyleUrlToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_url_to_stylesheet_alias_for_stylesheet_url + UrlToStyleToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_stylesheet_link_tag + StyleLinkToTag.each { |method, tag| assert_dom_equal(tag, eval(method)) } + end + + def test_stylesheet_link_tag_with_missing_source + assert_nothing_raised { + stylesheet_link_tag('missing_security_guard') + } + + assert_nothing_raised { + stylesheet_link_tag('http://example.com/css/missing_security_guard') + } + end + + def test_stylesheet_link_tag_is_html_safe + assert stylesheet_link_tag('dir/file').html_safe? + assert stylesheet_link_tag('dir/other/file', 'dir/file2').html_safe? + end + + def test_stylesheet_link_tag_escapes_options + assert_dom_equal %(), stylesheet_link_tag('/file', :media => '" + assert_equal expected_output, render_content("javascript_tag", "alert('Hello')") + end + + test "percent equals works for javascript_tag with options" do + expected_output = "" + assert_equal expected_output, render_content("javascript_tag(:id => 'the_js_tag')", "alert('Hello')") + end + + test "percent equals works with form tags" do + expected_output = %r{.*hello*} + assert_match expected_output, render_content("form_tag('foo')", "<%= 'hello' %>") + end + + test "percent equals works with fieldset tags" do + expected_output = "
foohello
" + assert_equal expected_output, render_content("field_set_tag('foo')", "<%= 'hello' %>") + end + end +end diff --git a/actionview/test/template/erb_util_test.rb b/actionview/test/template/erb_util_test.rb new file mode 100644 index 0000000000..3e5b029cea --- /dev/null +++ b/actionview/test/template/erb_util_test.rb @@ -0,0 +1,60 @@ +require 'abstract_unit' + +class ErbUtilTest < ActiveSupport::TestCase + include ERB::Util + + ERB::Util::HTML_ESCAPE.each do |given, expected| + define_method "test_html_escape_#{expected.gsub(/\W/, '')}" do + assert_equal expected, html_escape(given) + end + end + + ERB::Util::JSON_ESCAPE.each do |given, expected| + define_method "test_json_escape_#{expected.gsub(/\W/, '')}" do + assert_equal ERB::Util::JSON_ESCAPE[given], json_escape(given) + end + end + + def test_json_escape_returns_unsafe_strings_when_passed_unsafe_strings + value = json_escape("asdf") + assert !value.html_safe? + end + + def test_json_escape_returns_safe_strings_when_passed_safe_strings + value = json_escape("asdf".html_safe) + assert value.html_safe? + end + + def test_html_escape_is_html_safe + escaped = h("

") + assert_equal "<p>", escaped + assert escaped.html_safe? + end + + def test_html_escape_passes_html_escpe_unmodified + escaped = h("

".html_safe) + assert_equal "

", escaped + assert escaped.html_safe? + end + + def test_rest_in_ascii + (0..127).to_a.map {|int| int.chr }.each do |chr| + next if %('"&<>).include?(chr) + assert_equal chr, html_escape(chr) + end + end + + def test_html_escape_once + assert_equal '1 <>&"' 2 & 3', html_escape_once('1 <>&"\' 2 & 3') + end + + def test_html_escape_once_returns_unsafe_strings_when_passed_unsafe_strings + value = html_escape_once('1 < 2 & 3') + assert !value.html_safe? + end + + def test_html_escape_once_returns_safe_strings_when_passed_safe_strings + value = html_escape_once('1 < 2 & 3'.html_safe) + assert value.html_safe? + end +end diff --git a/actionview/test/template/form_collections_helper_test.rb b/actionview/test/template/form_collections_helper_test.rb new file mode 100644 index 0000000000..bc9c21dfd3 --- /dev/null +++ b/actionview/test/template/form_collections_helper_test.rb @@ -0,0 +1,358 @@ +require 'abstract_unit' + +class Category < Struct.new(:id, :name) +end + +class FormCollectionsHelperTest < ActionView::TestCase + def assert_no_select(selector, value = nil) + assert_select(selector, :text => value, :count => 0) + end + + def with_collection_radio_buttons(*args, &block) + @output_buffer = collection_radio_buttons(*args, &block) + end + + def with_collection_check_boxes(*args, &block) + @output_buffer = collection_check_boxes(*args, &block) + end + + # COLLECTION RADIO BUTTONS + test 'collection radio accepts a collection and generate inputs from value method' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s + + assert_select 'input[type=radio][value=true]#user_active_true' + assert_select 'input[type=radio][value=false]#user_active_false' + end + + test 'collection radio accepts a collection and generate inputs from label method' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s + + assert_select 'label[for=user_active_true]', 'true' + assert_select 'label[for=user_active_false]', 'false' + end + + test 'collection radio handles camelized collection values for labels correctly' do + with_collection_radio_buttons :user, :active, ['Yes', 'No'], :to_s, :to_s + + assert_select 'label[for=user_active_yes]', 'Yes' + assert_select 'label[for=user_active_no]', 'No' + end + + test 'colection radio should sanitize collection values for labels correctly' do + with_collection_radio_buttons :user, :name, ['$0.99', '$1.99'], :to_s, :to_s + assert_select 'label[for=user_name_099]', '$0.99' + assert_select 'label[for=user_name_199]', '$1.99' + end + + test 'collection radio accepts checked item' do + with_collection_radio_buttons :user, :active, [[1, true], [0, false]], :last, :first, :checked => true + + assert_select 'input[type=radio][value=true][checked=checked]' + assert_no_select 'input[type=radio][value=false][checked=checked]' + end + + test 'collection radio accepts multiple disabled items' do + collection = [[1, true], [0, false], [2, 'other']] + with_collection_radio_buttons :user, :active, collection, :last, :first, :disabled => [true, false] + + assert_select 'input[type=radio][value=true][disabled=disabled]' + assert_select 'input[type=radio][value=false][disabled=disabled]' + assert_no_select 'input[type=radio][value=other][disabled=disabled]' + end + + test 'collection radio accepts single disable item' do + collection = [[1, true], [0, false]] + with_collection_radio_buttons :user, :active, collection, :last, :first, :disabled => true + + assert_select 'input[type=radio][value=true][disabled=disabled]' + assert_no_select 'input[type=radio][value=false][disabled=disabled]' + end + + test 'collection radio accepts html options as input' do + collection = [[1, true], [0, false]] + with_collection_radio_buttons :user, :active, collection, :last, :first, {}, :class => 'special-radio' + + assert_select 'input[type=radio][value=true].special-radio#user_active_true' + assert_select 'input[type=radio][value=false].special-radio#user_active_false' + end + + test 'collection radio accepts html options as the last element of array' do + collection = [[1, true, {class: 'foo'}], [0, false, {class: 'bar'}]] + with_collection_radio_buttons :user, :active, collection, :second, :first + + assert_select 'input[type=radio][value=true].foo#user_active_true' + assert_select 'input[type=radio][value=false].bar#user_active_false' + end + + test 'collection radio does not wrap input inside the label' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s + + assert_select 'input[type=radio] + label' + assert_no_select 'label input' + end + + test 'collection radio accepts a block to render the label as radio button wrapper' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label { b.radio_button } + end + + assert_select 'label[for=user_active_true] > input#user_active_true[type=radio]' + assert_select 'label[for=user_active_false] > input#user_active_false[type=radio]' + end + + test 'collection radio accepts a block to change the order of label and radio button' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label + b.radio_button + end + + assert_select 'label[for=user_active_true] + input#user_active_true[type=radio]' + assert_select 'label[for=user_active_false] + input#user_active_false[type=radio]' + end + + test 'collection radio with block helpers accept extra html options' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:class => "radio_button") + b.radio_button(:class => "radio_button") + end + + assert_select 'label.radio_button[for=user_active_true] + input#user_active_true.radio_button[type=radio]' + assert_select 'label.radio_button[for=user_active_false] + input#user_active_false.radio_button[type=radio]' + end + + test 'collection radio with block helpers allows access to current text and value' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:"data-value" => b.value) { b.radio_button + b.text } + end + + assert_select 'label[for=user_active_true][data-value=true]', 'true' do + assert_select 'input#user_active_true[type=radio]' + end + assert_select 'label[for=user_active_false][data-value=false]', 'false' do + assert_select 'input#user_active_false[type=radio]' + end + end + + test 'collection radio with block helpers allows access to the current object item in the collection to access extra properties' do + with_collection_radio_buttons :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:class => b.object) { b.radio_button + b.text } + end + + assert_select 'label.true[for=user_active_true]', 'true' do + assert_select 'input#user_active_true[type=radio]' + end + assert_select 'label.false[for=user_active_false]', 'false' do + assert_select 'input#user_active_false[type=radio]' + end + end + + test 'collection radio buttons with fields for' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + @output_buffer = fields_for(:post) do |p| + p.collection_radio_buttons :category_id, collection, :id, :name + end + + assert_select 'input#post_category_id_1[type=radio][value=1]' + assert_select 'input#post_category_id_2[type=radio][value=2]' + + assert_select 'label[for=post_category_id_1]', 'Category 1' + assert_select 'label[for=post_category_id_2]', 'Category 2' + end + + test 'collection radio accepts checked item which has a value of false' do + with_collection_radio_buttons :user, :active, [[1, true], [0, false]], :last, :first, :checked => false + assert_no_select 'input[type=radio][value=true][checked=checked]' + assert_select 'input[type=radio][value=false][checked=checked]' + end + + # COLLECTION CHECK BOXES + test 'collection check boxes accepts a collection and generate a serie of checkboxes for value method' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_check_boxes :user, :category_ids, collection, :id, :name + + assert_select 'input#user_category_ids_1[type=checkbox][value=1]' + assert_select 'input#user_category_ids_2[type=checkbox][value=2]' + end + + test 'collection check boxes generates only one hidden field for the entire collection, to ensure something will be sent back to the server when posting an empty collection' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_check_boxes :user, :category_ids, collection, :id, :name + + assert_select "input[type=hidden][name='user[category_ids][]'][value=]", :count => 1 + end + + test 'collection check boxes accepts a collection and generate a serie of checkboxes with labels for label method' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + with_collection_check_boxes :user, :category_ids, collection, :id, :name + + assert_select 'label[for=user_category_ids_1]', 'Category 1' + assert_select 'label[for=user_category_ids_2]', 'Category 2' + end + + test 'collection check boxes handles camelized collection values for labels correctly' do + with_collection_check_boxes :user, :active, ['Yes', 'No'], :to_s, :to_s + + assert_select 'label[for=user_active_yes]', 'Yes' + assert_select 'label[for=user_active_no]', 'No' + end + + test 'colection check box should sanitize collection values for labels correctly' do + with_collection_check_boxes :user, :name, ['$0.99', '$1.99'], :to_s, :to_s + assert_select 'label[for=user_name_099]', '$0.99' + assert_select 'label[for=user_name_199]', '$1.99' + end + + test 'collection check boxes accepts html options as the last element of array' do + collection = [[1, 'Category 1', {class: 'foo'}], [2, 'Category 2', {class: 'bar'}]] + with_collection_check_boxes :user, :active, collection, :first, :second + + assert_select 'input[type=checkbox][value=1].foo' + assert_select 'input[type=checkbox][value=2].bar' + end + + test 'collection check boxes accepts selected values as :checked option' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => [1, 3] + + assert_select 'input[type=checkbox][value=1][checked=checked]' + assert_select 'input[type=checkbox][value=3][checked=checked]' + assert_no_select 'input[type=checkbox][value=2][checked=checked]' + end + + test 'collection check boxes accepts selected string values as :checked option' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => ['1', '3'] + + assert_select 'input[type=checkbox][value=1][checked=checked]' + assert_select 'input[type=checkbox][value=3][checked=checked]' + assert_no_select 'input[type=checkbox][value=2][checked=checked]' + end + + test 'collection check boxes accepts a single checked value' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :checked => 3 + + assert_select 'input[type=checkbox][value=3][checked=checked]' + assert_no_select 'input[type=checkbox][value=1][checked=checked]' + assert_no_select 'input[type=checkbox][value=2][checked=checked]' + end + + test 'collection check boxes accepts selected values as :checked option and override the model values' do + user = Struct.new(:category_ids).new(2) + collection = (1..3).map{|i| [i, "Category #{i}"] } + + @output_buffer = fields_for(:user, user) do |p| + p.collection_check_boxes :category_ids, collection, :first, :last, :checked => [1, 3] + end + + assert_select 'input[type=checkbox][value=1][checked=checked]' + assert_select 'input[type=checkbox][value=3][checked=checked]' + assert_no_select 'input[type=checkbox][value=2][checked=checked]' + end + + test 'collection check boxes accepts multiple disabled items' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => [1, 3] + + assert_select 'input[type=checkbox][value=1][disabled=disabled]' + assert_select 'input[type=checkbox][value=3][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=2][disabled=disabled]' + end + + test 'collection check boxes accepts single disable item' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => 1 + + assert_select 'input[type=checkbox][value=1][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=3][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=2][disabled=disabled]' + end + + test 'collection check boxes accepts a proc to disabled items' do + collection = (1..3).map{|i| [i, "Category #{i}"] } + with_collection_check_boxes :user, :category_ids, collection, :first, :last, :disabled => proc { |i| i.first == 1 } + + assert_select 'input[type=checkbox][value=1][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=3][disabled=disabled]' + assert_no_select 'input[type=checkbox][value=2][disabled=disabled]' + end + + test 'collection check boxes accepts html options' do + collection = [[1, 'Category 1'], [2, 'Category 2']] + with_collection_check_boxes :user, :category_ids, collection, :first, :last, {}, :class => 'check' + + assert_select 'input.check[type=checkbox][value=1]' + assert_select 'input.check[type=checkbox][value=2]' + end + + test 'collection check boxes with fields for' do + collection = [Category.new(1, 'Category 1'), Category.new(2, 'Category 2')] + @output_buffer = fields_for(:post) do |p| + p.collection_check_boxes :category_ids, collection, :id, :name + end + + assert_select 'input#post_category_ids_1[type=checkbox][value=1]' + assert_select 'input#post_category_ids_2[type=checkbox][value=2]' + + assert_select 'label[for=post_category_ids_1]', 'Category 1' + assert_select 'label[for=post_category_ids_2]', 'Category 2' + end + + test 'collection check boxes does not wrap input inside the label' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s + + assert_select 'input[type=checkbox] + label' + assert_no_select 'label input' + end + + test 'collection check boxes accepts a block to render the label as check box wrapper' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label { b.check_box } + end + + assert_select 'label[for=user_active_true] > input#user_active_true[type=checkbox]' + assert_select 'label[for=user_active_false] > input#user_active_false[type=checkbox]' + end + + test 'collection check boxes accepts a block to change the order of label and check box' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label + b.check_box + end + + assert_select 'label[for=user_active_true] + input#user_active_true[type=checkbox]' + assert_select 'label[for=user_active_false] + input#user_active_false[type=checkbox]' + end + + test 'collection check boxes with block helpers accept extra html options' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:class => "check_box") + b.check_box(:class => "check_box") + end + + assert_select 'label.check_box[for=user_active_true] + input#user_active_true.check_box[type=checkbox]' + assert_select 'label.check_box[for=user_active_false] + input#user_active_false.check_box[type=checkbox]' + end + + test 'collection check boxes with block helpers allows access to current text and value' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:"data-value" => b.value) { b.check_box + b.text } + end + + assert_select 'label[for=user_active_true][data-value=true]', 'true' do + assert_select 'input#user_active_true[type=checkbox]' + end + assert_select 'label[for=user_active_false][data-value=false]', 'false' do + assert_select 'input#user_active_false[type=checkbox]' + end + end + + test 'collection check boxes with block helpers allows access to the current object item in the collection to access extra properties' do + with_collection_check_boxes :user, :active, [true, false], :to_s, :to_s do |b| + b.label(:class => b.object) { b.check_box + b.text } + end + + assert_select 'label.true[for=user_active_true]', 'true' do + assert_select 'input#user_active_true[type=checkbox]' + end + assert_select 'label.false[for=user_active_false]', 'false' do + assert_select 'input#user_active_false[type=checkbox]' + end + end +end diff --git a/actionview/test/template/form_helper_test.rb b/actionview/test/template/form_helper_test.rb new file mode 100644 index 0000000000..1ff320224d --- /dev/null +++ b/actionview/test/template/form_helper_test.rb @@ -0,0 +1,2959 @@ +require 'abstract_unit' +require 'controller/fake_models' + +class FormHelperTest < ActionView::TestCase + include RenderERBUtils + + tests ActionView::Helpers::FormHelper + + def form_for(*) + @output_buffer = super + end + + def setup + super + + # Create "label" locale for testing I18n label helpers + I18n.backend.store_translations 'label', { + activemodel: { + attributes: { + post: { + cost: "Total cost" + } + } + }, + helpers: { + label: { + post: { + body: "Write entire text here", + color: { + red: "Rojo" + }, + comments: { + body: "Write body here" + } + }, + tag: { + value: "Tag" + } + } + } + } + + # Create "submit" locale for testing I18n submit helpers + I18n.backend.store_translations 'submit', { + helpers: { + submit: { + create: 'Create %{model}', + update: 'Confirm %{model} changes', + submit: 'Save changes', + another_post: { + update: 'Update your %{model}' + } + } + } + } + + @post = Post.new + @comment = Comment.new + def @post.errors() + Class.new { + def [](field); field == "author_name" ? ["can't be empty"] : [] end + def empty?() false end + def count() 1 end + def full_messages() ["Author name can't be empty"] end + }.new + end + def @post.to_key; [123]; end + def @post.id_before_type_cast; 123; end + def @post.to_param; '123'; end + + @post.persisted = true + @post.title = "Hello World" + @post.author_name = "" + @post.body = "Back to the hill and over it again!" + @post.secret = 1 + @post.written_on = Date.new(2004, 6, 15) + + @post.comments = [] + @post.comments << @comment + + @post.tags = [] + @post.tags << Tag.new + + @car = Car.new("#000FFF") + end + + Routes = ActionDispatch::Routing::RouteSet.new + Routes.draw do + resources :posts do + resources :comments + end + + namespace :admin do + resources :posts do + resources :comments + end + end + + get "/foo", to: "controller#action" + root to: "main#index" + end + + def _routes + Routes + end + + include Routes.url_helpers + + def url_for(object) + @url_for_options = object + + if object.is_a?(Hash) && object[:use_route].blank? && object[:controller].blank? + object.merge!(controller: "main", action: "index") + end + + super + end + + class FooTag < ActionView::Helpers::Tags::Base + def initialize; end + end + + def test_tags_base_child_without_render_method + assert_raise(NotImplementedError) { FooTag.new.render } + end + + def test_label + assert_dom_equal('', label("post", "title")) + assert_dom_equal( + '', + label("post", "title", "The title goes here") + ) + assert_dom_equal( + '', + label("post", "title", nil, class: 'title_label') + ) + assert_dom_equal('', label("post", "secret?")) + end + + def test_label_with_symbols + assert_dom_equal('', label(:post, :title)) + assert_dom_equal('', label(:post, :secret?)) + end + + def test_label_with_locales_strings + old_locale, I18n.locale = I18n.locale, :label + assert_dom_equal('', label("post", "body")) + ensure + I18n.locale = old_locale + end + + def test_label_with_human_attribute_name + old_locale, I18n.locale = I18n.locale, :label + assert_dom_equal('', label(:post, :cost)) + ensure + I18n.locale = old_locale + end + + def test_label_with_locales_symbols + old_locale, I18n.locale = I18n.locale, :label + assert_dom_equal('', label(:post, :body)) + ensure + I18n.locale = old_locale + end + + def test_label_with_locales_and_options + old_locale, I18n.locale = I18n.locale, :label + assert_dom_equal( + '', + label(:post, :body, class: "post_body") + ) + ensure + I18n.locale = old_locale + end + + def test_label_with_locales_and_value + old_locale, I18n.locale = I18n.locale, :label + assert_dom_equal('', label(:post, :color, value: "red")) + ensure + I18n.locale = old_locale + end + + def test_label_with_locales_and_nested_attributes + old_locale, I18n.locale = I18n.locale, :label + form_for(@post, html: { id: 'create-post' }) do |f| + f.fields_for(:comments) do |cf| + concat cf.label(:body) + end + end + + expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do + '' + end + + assert_dom_equal expected, output_buffer + ensure + I18n.locale = old_locale + end + + def test_label_with_locales_fallback_and_nested_attributes + old_locale, I18n.locale = I18n.locale, :label + form_for(@post, html: { id: 'create-post' }) do |f| + f.fields_for(:tags) do |cf| + concat cf.label(:value) + end + end + + expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do + '' + end + + assert_dom_equal expected, output_buffer + ensure + I18n.locale = old_locale + end + + def test_label_with_for_attribute_as_symbol + assert_dom_equal('', label(:post, :title, nil, for: "my_for")) + end + + def test_label_with_for_attribute_as_string + assert_dom_equal('', label(:post, :title, nil, "for" => "my_for")) + end + + def test_label_does_not_generate_for_attribute_when_given_nil + assert_dom_equal('', label(:post, :title, for: nil)) + end + + def test_label_with_id_attribute_as_symbol + assert_dom_equal( + '', + label(:post, :title, nil, id: "my_id") + ) + end + + def test_label_with_id_attribute_as_string + assert_dom_equal( + '', + label(:post, :title, nil, "id" => "my_id") + ) + end + + def test_label_with_for_and_id_attributes_as_symbol + assert_dom_equal( + '', + label(:post, :title, nil, for: "my_for", id: "my_id") + ) + end + + def test_label_with_for_and_id_attributes_as_string + assert_dom_equal( + '', + label(:post, :title, nil, "for" => "my_for", "id" => "my_id") + ) + end + + def test_label_for_radio_buttons_with_value + assert_dom_equal( + '', + label("post", "title", "The title goes here", value: "great_title") + ) + assert_dom_equal( + '', + label("post", "title", "The title goes here", value: "great title") + ) + end + + def test_label_with_block + assert_dom_equal( + '', + label(:post, :title) { "The title, please:" } + ) + end + + def test_label_with_block_and_options + assert_dom_equal( + '', + label(:post, :title, "for" => "my_for") { "The title, please:" } + ) + end + + def test_label_with_block_in_erb + assert_equal( + %{}, + view.render("test/label_with_block") + ) + end + + def test_text_field + assert_dom_equal( + '', + text_field("post", "title") + ) + assert_dom_equal( + '', + password_field("post", "title") + ) + assert_dom_equal( + '', + password_field("post", "title", value: @post.title) + ) + assert_dom_equal( + '', + password_field("person", "name") + ) + end + + def test_text_field_with_escapes + @post.title = "Hello World" + assert_dom_equal( + '', + text_field("post", "title") + ) + end + + def test_text_field_with_html_entities + @post.title = "The HTML Entity for & is &" + assert_dom_equal( + '', + text_field("post", "title") + ) + end + + def test_text_field_with_options + expected = '' + assert_dom_equal expected, text_field("post", "title", "size" => 35) + assert_dom_equal expected, text_field("post", "title", size: 35) + end + + def test_text_field_assuming_size + expected = '' + assert_dom_equal expected, text_field("post", "title", "maxlength" => 35) + assert_dom_equal expected, text_field("post", "title", maxlength: 35) + end + + def test_text_field_removing_size + expected = '' + assert_dom_equal expected, text_field("post", "title", "maxlength" => 35, "size" => nil) + assert_dom_equal expected, text_field("post", "title", maxlength: 35, size: nil) + end + + def test_text_field_with_nil_value + expected = '' + assert_dom_equal expected, text_field("post", "title", value: nil) + end + + def test_text_field_with_nil_name + expected = '' + assert_dom_equal expected, text_field("post", "title", name: nil) + end + + def test_text_field_doesnt_change_param_values + object_name = 'post[]' + expected = '' + assert_equal expected, text_field(object_name, "title") + assert_equal object_name, "post[]" + end + + def test_file_field_has_no_size + expected = '' + assert_dom_equal expected, file_field("user", "avatar") + end + + def test_file_field_with_multiple_behavior + expected = '' + assert_dom_equal expected, file_field("import", "file", :multiple => true) + end + + def test_file_field_with_multiple_behavior_and_explicit_name + expected = '' + assert_dom_equal expected, file_field("import", "file", :multiple => true, :name => "custom") + end + + def test_hidden_field + assert_dom_equal( + '', + hidden_field("post", "title") + ) + assert_dom_equal( + '', + hidden_field("post", "secret?") + ) + end + + def test_hidden_field_with_escapes + @post.title = "Hello World" + assert_dom_equal( + '', + hidden_field("post", "title") + ) + end + + def test_hidden_field_with_nil_value + expected = '' + assert_dom_equal expected, hidden_field("post", "title", value: nil) + end + + def test_hidden_field_with_options + assert_dom_equal( + '', + hidden_field("post", "title", value: "Something Else") + ) + end + + def test_text_field_with_custom_type + assert_dom_equal( + '', + text_field("user", "email", type: "email") + ) + end + + def test_check_box_is_html_safe + assert check_box("post", "secret").html_safe? + end + + def test_check_box_checked_if_object_value_is_same_that_check_value + assert_dom_equal( + '', + check_box("post", "secret") + ) + end + + def test_check_box_not_checked_if_object_value_is_same_that_unchecked_value + @post.secret = 0 + assert_dom_equal( + '', + check_box("post", "secret") + ) + end + + def test_check_box_checked_if_option_checked_is_present + assert_dom_equal( + '', + check_box("post", "secret", "checked"=>"checked") + ) + end + + def test_check_box_checked_if_object_value_is_true + @post.secret = true + assert_dom_equal( + '', + check_box("post", "secret") + ) + + assert_dom_equal( + '', + check_box("post", "secret?") + ) + end + + def test_check_box_checked_if_object_value_includes_checked_value + @post.secret = ['0'] + assert_dom_equal( + '', + check_box("post", "secret") + ) + + @post.secret = ['1'] + assert_dom_equal( + '', + check_box("post", "secret") + ) + + @post.secret = Set.new(['1']) + assert_dom_equal( + '', + check_box("post", "secret") + ) + end + + def test_check_box_with_include_hidden_false + @post.secret = false + assert_dom_equal( + '', + check_box("post", "secret", include_hidden: false) + ) + end + + def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_string + @post.secret = "on" + assert_dom_equal( + '', + check_box("post", "secret", {}, "on", "off") + ) + + @post.secret = "off" + assert_dom_equal( + '', + check_box("post", "secret", {}, "on", "off") + ) + end + + def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_boolean + @post.secret = false + assert_dom_equal( + '', + check_box("post", "secret", {}, false, true) + ) + + @post.secret = true + assert_dom_equal( + '', + check_box("post", "secret", {}, false, true) + ) + end + + def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_integer + @post.secret = 0 + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + + @post.secret = 1 + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + + @post.secret = 2 + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + end + + def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_float + @post.secret = 0.0 + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + + @post.secret = 1.1 + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + + @post.secret = 2.2 + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + end + + def test_check_box_with_explicit_checked_and_unchecked_values_when_object_value_is_big_decimal + @post.secret = BigDecimal.new(0) + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + + @post.secret = BigDecimal.new(1) + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + + @post.secret = BigDecimal.new(2.2, 1) + assert_dom_equal( + '', + check_box("post", "secret", {}, 0, 1) + ) + end + + def test_check_box_with_nil_unchecked_value + @post.secret = "on" + assert_dom_equal( + '', + check_box("post", "secret", {}, "on", nil) + ) + end + + def test_check_box_with_nil_unchecked_value_is_html_safe + assert check_box("post", "secret", {}, "on", nil).html_safe? + end + + def test_check_box_with_multiple_behavior + @post.comment_ids = [2,3] + assert_dom_equal( + '', + check_box("post", "comment_ids", { multiple: true }, 1) + ) + assert_dom_equal( + '', + check_box("post", "comment_ids", { multiple: true }, 3) + ) + end + + def test_check_box_with_multiple_behavior_and_index + @post.comment_ids = [2,3] + assert_dom_equal( + '', + check_box("post", "comment_ids", { multiple: true, index: "foo" }, 1) + ) + assert_dom_equal( + '', + check_box("post", "comment_ids", { multiple: true, index: "bar" }, 3) + ) + + end + + def test_checkbox_disabled_disables_hidden_field + assert_dom_equal( + '', + check_box("post", "secret", { disabled: true }) + ) + end + + def test_checkbox_form_html5_attribute + assert_dom_equal( + '', + check_box("post", "secret", form: "new_form") + ) + end + + def test_radio_button + assert_dom_equal('', + radio_button("post", "title", "Hello World") + ) + assert_dom_equal('', + radio_button("post", "title", "Goodbye World") + ) + assert_dom_equal('', + radio_button("item[subobject]", "title", "inside world") + ) + end + + def test_radio_button_is_checked_with_integers + assert_dom_equal('', + radio_button("post", "secret", "1") + ) + end + + def test_radio_button_with_negative_integer_value + assert_dom_equal('', + radio_button("post", "secret", "-1")) + end + + def test_radio_button_respects_passed_in_id + assert_dom_equal('', + radio_button("post", "secret", "1", id: "foo") + ) + end + + def test_radio_button_with_booleans + assert_dom_equal('', + radio_button("post", "secret", true) + ) + + assert_dom_equal('', + radio_button("post", "secret", false) + ) + end + + def test_text_area + assert_dom_equal( + %{}, + text_area("post", "body") + ) + end + + def test_text_area_with_escapes + @post.body = "Back to the hill and over it again!" + assert_dom_equal( + %{}, + text_area("post", "body") + ) + end + + def test_text_area_with_alternate_value + assert_dom_equal( + %{}, + text_area("post", "body", value: "Testing alternate values.") + ) + end + + def test_text_area_with_html_entities + @post.body = "The HTML Entity for & is &" + assert_dom_equal( + %{}, + text_area("post", "body") + ) + end + + def test_text_area_with_size_option + assert_dom_equal( + %{}, + text_area("post", "body", size: "183x820") + ) + end + + def test_color_field_with_valid_hex_color_string + expected = %{} + assert_dom_equal(expected, color_field("car", "color")) + end + + def test_color_field_with_invalid_hex_color_string + expected = %{} + @car.color = "#1234TR" + assert_dom_equal(expected, color_field("car", "color")) + end + + def test_search_field + expected = %{} + assert_dom_equal(expected, search_field("contact", "notes_query")) + end + + def test_telephone_field + expected = %{} + assert_dom_equal(expected, telephone_field("user", "cell")) + end + + def test_date_field + expected = %{} + assert_dom_equal(expected, date_field("post", "written_on")) + end + + def test_date_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, date_field("post", "written_on")) + end + + def test_date_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15) + min_value = DateTime.new(2000, 6, 15) + max_value = DateTime.new(2010, 8, 15) + step = 2 + assert_dom_equal(expected, date_field("post", "written_on", min: min_value, max: max_value, step: step)) + end + + def test_date_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, date_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_date_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, date_field("post", "written_on")) + end + + def test_time_field + expected = %{} + assert_dom_equal(expected, time_field("post", "written_on")) + end + + def test_time_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, time_field("post", "written_on")) + end + + def test_time_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 6, 15, 20, 45, 30) + max_value = DateTime.new(2010, 8, 15, 10, 25, 00) + step = 60 + assert_dom_equal(expected, time_field("post", "written_on", min: min_value, max: max_value, step: step)) + end + + def test_time_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 01:02:03') + assert_dom_equal(expected, time_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_time_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, time_field("post", "written_on")) + end + + def test_datetime_field + expected = %{} + assert_dom_equal(expected, datetime_field("post", "written_on")) + end + + def test_datetime_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, datetime_field("post", "written_on")) + end + + def test_datetime_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 6, 15, 20, 45, 30) + max_value = DateTime.new(2010, 8, 15, 10, 25, 00) + step = 60 + assert_dom_equal(expected, datetime_field("post", "written_on", min: min_value, max: max_value, step: step)) + end + + def test_datetime_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, datetime_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_datetime_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, datetime_field("post", "written_on")) + end + + def test_datetime_local_field + expected = %{} + assert_dom_equal(expected, datetime_local_field("post", "written_on")) + end + + def test_datetime_local_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, datetime_local_field("post", "written_on")) + end + + def test_datetime_local_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 6, 15, 20, 45, 30) + max_value = DateTime.new(2010, 8, 15, 10, 25, 00) + step = 60 + assert_dom_equal(expected, datetime_local_field("post", "written_on", min: min_value, max: max_value, step: step)) + end + + def test_datetime_local_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, datetime_local_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_datetime_local_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, datetime_local_field("post", "written_on")) + end + + def test_month_field + expected = %{} + assert_dom_equal(expected, month_field("post", "written_on")) + end + + def test_month_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, month_field("post", "written_on")) + end + + def test_month_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, month_field("post", "written_on")) + end + + def test_month_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 2, 13) + max_value = DateTime.new(2010, 12, 23) + step = 2 + assert_dom_equal(expected, month_field("post", "written_on", min: min_value, max: max_value, step: step)) + end + + def test_month_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, month_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_week_field + expected = %{} + assert_dom_equal(expected, week_field("post", "written_on")) + end + + def test_week_field_with_nil_value + expected = %{} + @post.written_on = nil + assert_dom_equal(expected, week_field("post", "written_on")) + end + + def test_week_field_with_datetime_value + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + assert_dom_equal(expected, week_field("post", "written_on")) + end + + def test_week_field_with_extra_attrs + expected = %{} + @post.written_on = DateTime.new(2004, 6, 15, 1, 2, 3) + min_value = DateTime.new(2000, 2, 13) + max_value = DateTime.new(2010, 12, 23) + step = 2 + assert_dom_equal(expected, week_field("post", "written_on", min: min_value, max: max_value, step: step)) + end + + def test_week_field_with_timewithzone_value + previous_time_zone, Time.zone = Time.zone, 'UTC' + expected = %{} + @post.written_on = Time.zone.parse('2004-06-15 15:30:45') + assert_dom_equal(expected, week_field("post", "written_on")) + ensure + Time.zone = previous_time_zone + end + + def test_url_field + expected = %{} + assert_dom_equal(expected, url_field("user", "homepage")) + end + + def test_email_field + expected = %{} + assert_dom_equal(expected, email_field("user", "address")) + end + + def test_number_field + expected = %{} + assert_dom_equal(expected, number_field("order", "quantity", in: 1...10)) + expected = %{} + assert_dom_equal(expected, number_field("order", "quantity", size: 30, in: 1...10)) + end + + def test_range_input + expected = %{} + assert_dom_equal(expected, range_field("hifi", "volume", in: 0..11, step: 0.1)) + expected = %{} + assert_dom_equal(expected, range_field("hifi", "volume", size: 30, in: 0..11, step: 0.1)) + end + + def test_explicit_name + assert_dom_equal( + '', + text_field("post", "title", "name" => "dont guess") + ) + assert_dom_equal( + %{}, + text_area("post", "body", "name" => "really!") + ) + assert_dom_equal( + '', + check_box("post", "secret", "name" => "i mean it") + ) + assert_dom_equal( + text_field("post", "title", "name" => "dont guess"), + text_field("post", "title", name: "dont guess") + ) + assert_dom_equal( + text_area("post", "body", "name" => "really!"), + text_area("post", "body", name: "really!") + ) + assert_dom_equal( + check_box("post", "secret", "name" => "i mean it"), + check_box("post", "secret", name: "i mean it") + ) + end + + def test_explicit_id + assert_dom_equal( + '', + text_field("post", "title", "id" => "dont guess") + ) + assert_dom_equal( + %{}, + text_area("post", "body", "id" => "really!") + ) + assert_dom_equal( + '', + check_box("post", "secret", "id" => "i mean it") + ) + assert_dom_equal( + text_field("post", "title", "id" => "dont guess"), + text_field("post", "title", id: "dont guess") + ) + assert_dom_equal( + text_area("post", "body", "id" => "really!"), + text_area("post", "body", id: "really!") + ) + assert_dom_equal( + check_box("post", "secret", "id" => "i mean it"), + check_box("post", "secret", id: "i mean it") + ) + end + + def test_nil_id + assert_dom_equal( + '', + text_field("post", "title", "id" => nil) + ) + assert_dom_equal( + %{}, + text_area("post", "body", "id" => nil) + ) + assert_dom_equal( + '', + check_box("post", "secret", "id" => nil) + ) + assert_dom_equal( + '', + radio_button("post", "secret", "0", "id" => nil) + ) + assert_dom_equal( + '', + select("post", "secret", [], {}, "id" => nil) + ) + assert_dom_equal( + text_field("post", "title", "id" => nil), + text_field("post", "title", id: nil) + ) + assert_dom_equal( + text_area("post", "body", "id" => nil), + text_area("post", "body", id: nil) + ) + assert_dom_equal( + check_box("post", "secret", "id" => nil), + check_box("post", "secret", id: nil) + ) + assert_dom_equal( + radio_button("post", "secret", "0", "id" => nil), + radio_button("post", "secret", "0", id: nil) + ) + end + + def test_index + assert_dom_equal( + '', + text_field("post", "title", "index" => 5) + ) + assert_dom_equal( + %{}, + text_area("post", "body", "index" => 5) + ) + assert_dom_equal( + '', + check_box("post", "secret", "index" => 5) + ) + assert_dom_equal( + text_field("post", "title", "index" => 5), + text_field("post", "title", "index" => 5) + ) + assert_dom_equal( + text_area("post", "body", "index" => 5), + text_area("post", "body", "index" => 5) + ) + assert_dom_equal( + check_box("post", "secret", "index" => 5), + check_box("post", "secret", "index" => 5) + ) + end + + def test_index_with_nil_id + assert_dom_equal( + '', + text_field("post", "title", "index" => 5, 'id' => nil) + ) + assert_dom_equal( + %{}, + text_area("post", "body", "index" => 5, 'id' => nil) + ) + assert_dom_equal( + '', + check_box("post", "secret", "index" => 5, 'id' => nil) + ) + assert_dom_equal( + text_field("post", "title", "index" => 5, 'id' => nil), + text_field("post", "title", index: 5, id: nil) + ) + assert_dom_equal( + text_area("post", "body", "index" => 5, 'id' => nil), + text_area("post", "body", index: 5, id: nil) + ) + assert_dom_equal( + check_box("post", "secret", "index" => 5, 'id' => nil), + check_box("post", "secret", index: 5, id: nil) + ) + end + + def test_auto_index + pid = 123 + assert_dom_equal( + %{}, + label("post[]", "title") + ) + assert_dom_equal( + %{}, + text_field("post[]","title") + ) + assert_dom_equal( + %{}, + text_area("post[]", "body") + ) + assert_dom_equal( + %{}, + check_box("post[]", "secret") + ) + assert_dom_equal( + %{}, + radio_button("post[]", "title", "Hello World") + ) + assert_dom_equal( + %{}, + radio_button("post[]", "title", "Goodbye World") + ) + end + + def test_auto_index_with_nil_id + pid = 123 + assert_dom_equal( + %{}, + text_field("post[]", "title", id: nil) + ) + assert_dom_equal( + %{}, + text_area("post[]", "body", id: nil) + ) + assert_dom_equal( + %{}, + check_box("post[]", "secret", id: nil) + ) + assert_dom_equal( + %{}, + radio_button("post[]", "title", "Hello World", id: nil) + ) + assert_dom_equal( + %{}, + radio_button("post[]", "title", "Goodbye World", id: nil) + ) + end + + def test_form_for_requires_block + assert_raises(ArgumentError) do + form_for(:post, @post, html: { id: 'create-post' }) + end + end + + def test_form_for_requires_arguments + error = assert_raises(ArgumentError) do + form_for(nil, html: { id: 'create-post' }) do + end + end + assert_equal "First argument in form cannot contain nil or be empty", error.message + + error = assert_raises(ArgumentError) do + form_for([nil, nil], html: { id: 'create-post' }) do + end + end + assert_equal "First argument in form cannot contain nil or be empty", error.message + end + + def test_form_for + form_for(@post, html: { id: 'create-post' }) do |f| + concat f.label(:title) { "The Title" } + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + concat f.submit('Create post') + concat f.button('Create post') + concat f.button { + concat content_tag(:span, 'Create post') + } + end + + expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch") do + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_collection_radio_buttons + post = Post.new + def post.active; false; end + form_for(post) do |f| + concat f.collection_radio_buttons(:active, [true, false], :to_s, :to_s) + end + + expected = whole_form("/posts", "new_post", "new_post") do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_collection_radio_buttons_with_custom_builder_block + post = Post.new + def post.active; false; end + + form_for(post) do |f| + rendered_radio_buttons = f.collection_radio_buttons(:active, [true, false], :to_s, :to_s) do |b| + b.label { b.radio_button + b.text } + end + concat rendered_radio_buttons + end + + expected = whole_form("/posts", "new_post", "new_post") do + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_collection_radio_buttons_with_custom_builder_block_does_not_leak_the_template + post = Post.new + def post.active; false; end + def post.id; 1; end + + form_for(post) do |f| + rendered_radio_buttons = f.collection_radio_buttons(:active, [true, false], :to_s, :to_s) do |b| + b.label { b.radio_button + b.text } + end + concat rendered_radio_buttons + concat f.hidden_field :id + end + + expected = whole_form("/posts", "new_post_1", "new_post") do + "" + + ""+ + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_collection_check_boxes + post = Post.new + def post.tag_ids; [1, 3]; end + collection = (1..3).map { |i| [i, "Tag #{i}"] } + form_for(post) do |f| + concat f.collection_check_boxes(:tag_ids, collection, :first, :last) + end + + expected = whole_form("/posts", "new_post", "new_post") do + "" + + "" + + "" + + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_collection_check_boxes_with_custom_builder_block + post = Post.new + def post.tag_ids; [1, 3]; end + collection = (1..3).map { |i| [i, "Tag #{i}"] } + form_for(post) do |f| + rendered_check_boxes = f.collection_check_boxes(:tag_ids, collection, :first, :last) do |b| + b.label { b.check_box + b.text } + end + concat rendered_check_boxes + end + + expected = whole_form("/posts", "new_post", "new_post") do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_collection_check_boxes_with_custom_builder_block_does_not_leak_the_template + post = Post.new + def post.tag_ids; [1, 3]; end + def post.id; 1; end + collection = (1..3).map { |i| [i, "Tag #{i}"] } + + form_for(post) do |f| + rendered_check_boxes = f.collection_check_boxes(:tag_ids, collection, :first, :last) do |b| + b.label { b.check_box + b.text } + end + concat rendered_check_boxes + concat f.hidden_field :id + end + + expected = whole_form("/posts", "new_post_1", "new_post") do + "" + + "" + + "" + + ""+ + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_file_field_generate_multipart + Post.send :attr_accessor, :file + + form_for(@post, html: { id: 'create-post' }) do |f| + concat f.file_field(:file) + end + + expected = whole_form("/posts/123", "create-post", "edit_post", method: "patch", multipart: true) do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_fields_for_with_file_field_generate_multipart + Comment.send :attr_accessor, :file + + form_for(@post) do |f| + concat f.fields_for(:comment, @post) { |c| + concat c.file_field(:file) + } + end + + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch", multipart: true) do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_format + form_for(@post, format: :json, html: { id: "edit_post_123", class: "edit_post" }) do |f| + concat f.label(:title) + end + + expected = whole_form("/posts/123.json", "edit_post_123", "edit_post", method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_model_using_relative_model_naming + blog_post = Blog::Post.new("And his name will be forty and four.", 44) + + form_for(blog_post) do |f| + concat f.text_field :title + concat f.submit('Edit post') + end + + expected = whole_form("/posts/44", "edit_post_44", "edit_post", method: "patch") do + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_symbol_object_name + form_for(@post, as: "other_name", html: { id: "create-post" }) do |f| + concat f.label(:title, class: 'post_title') + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + concat f.submit('Create post') + end + + expected = whole_form("/posts/123", "create-post", "edit_other_name", method: "patch") do + "" + + "" + + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_method_as_part_of_html_options + form_for(@post, url: '/', html: { id: 'create-post', method: :delete }) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form("/", "create-post", "edit_post", method: "delete") do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_method + form_for(@post, url: '/', method: :delete, html: { id: 'create-post' }) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form("/", "create-post", "edit_post", method: "delete") do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_search_field + # Test case for bug which would emit an "object" attribute + # when used with form_for using a search_field form helper + form_for(Post.new, url: "/search", html: { id: "search-post", method: :get }) do |f| + concat f.search_field(:title) + end + + expected = whole_form("/search", "search-post", "new_post", method: "get") do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_remote + form_for(@post, url: '/', remote: true, html: { id: 'create-post', method: :patch }) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form("/", "create-post", "edit_post", method: "patch", remote: true) do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_remote_in_html + form_for(@post, url: '/', html: { remote: true, id: 'create-post', method: :patch }) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form("/", "create-post", "edit_post", method: "patch", remote: true) do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_remote_without_html + @post.persisted = false + @post.stubs(:to_key).returns(nil) + form_for(@post, remote: true) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form("/posts", "new_post", "new_post", remote: true) do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_without_object + form_for(:post, html: { id: 'create-post' }) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form("/", "create-post") do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_index + form_for(@post, as: "post[]") do |f| + concat f.label(:title) + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + "" + + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_nil_index_option_override + form_for(@post, as: "post[]", index: nil) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_label_error_wrapping + form_for(@post) do |f| + concat f.label(:author_name, class: 'label') + concat f.text_field(:author_name) + concat f.submit('Create post') + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "

" + + "
" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_label_error_wrapping_without_conventional_instance_variable + post = remove_instance_variable :@post + + form_for(post) do |f| + concat f.label(:author_name, class: 'label') + concat f.text_field(:author_name) + concat f.submit('Create post') + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "
" + + "
" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_label_error_wrapping_block_and_non_block_versions + form_for(@post) do |f| + concat f.label(:author_name, 'Name', class: 'label') + concat f.label(:author_name, class: 'label') { 'Name' } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "
" + + "
" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_namespace + form_for(@post, namespace: 'namespace') do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', method: 'patch') do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_namespace_with_date_select + form_for(@post, namespace: 'namespace') do |f| + concat f.date_select(:written_on) + end + + assert_select 'select#namespace_post_written_on_1i' + end + + def test_form_for_with_namespace_with_label + form_for(@post, namespace: 'namespace') do |f| + concat f.label(:title) + concat f.text_field(:title) + end + + expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', method: 'patch') do + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_two_form_for_with_namespace + form_for(@post, namespace: 'namespace_1') do |f| + concat f.label(:title) + concat f.text_field(:title) + end + + expected_1 = whole_form('/posts/123', 'namespace_1_edit_post_123', 'edit_post', method: 'patch') do + "" + + "" + end + + assert_dom_equal expected_1, output_buffer + + form_for(@post, namespace: 'namespace_2') do |f| + concat f.label(:title) + concat f.text_field(:title) + end + + expected_2 = whole_form('/posts/123', 'namespace_2_edit_post_123', 'edit_post', method: 'patch') do + "" + + "" + end + + assert_dom_equal expected_2, output_buffer + end + + def test_fields_for_with_namespace + @comment.body = 'Hello World' + form_for(@post, namespace: 'namespace') do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.fields_for(@comment) { |c| + concat c.text_field(:body) + } + end + + expected = whole_form('/posts/123', 'namespace_edit_post_123', 'edit_post', method: 'patch') do + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_submit_with_object_as_new_record_and_locale_strings + old_locale, I18n.locale = I18n.locale, :submit + + @post.persisted = false + @post.stubs(:to_key).returns(nil) + form_for(@post) do |f| + concat f.submit + end + + expected = whole_form('/posts', 'new_post', 'new_post') do + "" + end + + assert_dom_equal expected, output_buffer + ensure + I18n.locale = old_locale + end + + def test_submit_with_object_as_existing_record_and_locale_strings + old_locale, I18n.locale = I18n.locale, :submit + + form_for(@post) do |f| + concat f.submit + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + ensure + I18n.locale = old_locale + end + + def test_submit_without_object_and_locale_strings + old_locale, I18n.locale = I18n.locale, :submit + + form_for(:post) do |f| + concat f.submit class: "extra" + end + + expected = whole_form do + "" + end + + assert_dom_equal expected, output_buffer + ensure + I18n.locale = old_locale + end + + def test_submit_with_object_and_nested_lookup + old_locale, I18n.locale = I18n.locale, :submit + + form_for(@post, as: :another_post) do |f| + concat f.submit + end + + expected = whole_form('/posts/123', 'edit_another_post', 'edit_another_post', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + ensure + I18n.locale = old_locale + end + + def test_nested_fields_for + @comment.body = 'Hello World' + form_for(@post) do |f| + concat f.fields_for(@comment) { |c| + concat c.text_field(:body) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_nested_collections + form_for(@post, as: 'post[]') do |f| + concat f.text_field(:title) + concat f.fields_for('comment[]', @comment) { |c| + concat c.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_index_and_parent_fields + form_for(@post, index: 1) do |c| + concat c.text_field(:title) + concat c.fields_for('comment', @comment, index: 1) { |r| + concat r.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_index_and_nested_fields_for + output_buffer = form_for(@post, index: 1) do |f| + concat f.fields_for(:comment, @post) { |c| + concat c.text_field(:title) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_index_on_both + form_for(@post, index: 1) do |f| + concat f.fields_for(:comment, @post, index: 5) { |c| + concat c.text_field(:title) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_auto_index + form_for(@post, as: "post[]") do |f| + concat f.fields_for(:comment, @post) { |c| + concat c.text_field(:title) + } + end + + expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_index_radio_button + form_for(@post) do |f| + concat f.fields_for(:comment, @post, index: 5) { |c| + concat c.radio_button(:title, "hello") + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_auto_index_on_both + form_for(@post, as: "post[]") do |f| + concat f.fields_for("comment[]", @post) { |c| + concat c.text_field(:title) + } + end + + expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_index_and_auto_index + output_buffer = form_for(@post, as: "post[]") do |f| + concat f.fields_for(:comment, @post, index: 5) { |c| + concat c.text_field(:title) + } + end + + output_buffer << form_for(@post, as: :post, index: 1) do |f| + concat f.fields_for("comment[]", @post) { |c| + concat c.text_field(:title) + } + end + + expected = whole_form('/posts/123', 'edit_post[]', 'edit_post[]', method: 'patch') do + "" + end + whole_form('/posts/123', 'edit_post', 'edit_post', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_a_new_record_on_a_nested_attributes_one_to_one_association + @post.author = Author.new + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:author) { |af| + concat af.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_explicitly_passed_object_on_a_nested_attributes_one_to_one_association + form_for(@post) do |f| + f.fields_for(:author, Author.new(123)) do |af| + assert_not_nil af.object + assert_equal 123, af.object.id + end + end + end + + def test_nested_fields_for_with_an_existing_record_on_a_nested_attributes_one_to_one_association + @post.author = Author.new(321) + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:author) { |af| + concat af.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_an_existing_record_on_a_nested_attributes_one_to_one_association_using_erb_and_inline_block + @post.author = Author.new(321) + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:author) { |af| + af.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_an_existing_record_on_a_nested_attributes_one_to_one_association_with_disabled_hidden_id + @post.author = Author.new(321) + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:author, include_id: false) { |af| + af.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_an_existing_record_on_a_nested_attributes_one_to_one_association_with_disabled_hidden_id_inherited + @post.author = Author.new(321) + + form_for(@post, include_id: false) do |f| + concat f.text_field(:title) + concat f.fields_for(:author) { |af| + af.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_an_existing_record_on_a_nested_attributes_one_to_one_association_with_disabled_hidden_id_override + @post.author = Author.new(321) + + form_for(@post, include_id: false) do |f| + concat f.text_field(:title) + concat f.fields_for(:author, include_id: true) { |af| + af.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_nested_attributes_one_to_one_association_with_explicit_hidden_field_placement + @post.author = Author.new(321) + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:author) { |af| + concat af.hidden_field(:id) + concat af.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + + form_for(@post) do |f| + concat f.text_field(:title) + @post.comments.each do |comment| + concat f.fields_for(:comments, comment) { |cf| + concat cf.text_field(:name) + } + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association_with_disabled_hidden_id + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + @post.author = Author.new(321) + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:author) { |af| + concat af.text_field(:name) + } + @post.comments.each do |comment| + concat f.fields_for(:comments, comment, include_id: false) { |cf| + concat cf.text_field(:name) + } + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association_with_disabled_hidden_id_inherited + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + @post.author = Author.new(321) + + form_for(@post, include_id: false) do |f| + concat f.text_field(:title) + concat f.fields_for(:author) { |af| + concat af.text_field(:name) + } + @post.comments.each do |comment| + concat f.fields_for(:comments, comment) { |cf| + concat cf.text_field(:name) + } + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association_with_disabled_hidden_id_override + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + @post.author = Author.new(321) + + form_for(@post, include_id: false) do |f| + concat f.text_field(:title) + concat f.fields_for(:author, include_id: true) { |af| + concat af.text_field(:name) + } + @post.comments.each do |comment| + concat f.fields_for(:comments, comment) { |cf| + concat cf.text_field(:name) + } + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association_using_erb_and_inline_block + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + + form_for(@post) do |f| + concat f.text_field(:title) + @post.comments.each do |comment| + concat f.fields_for(:comments, comment) { |cf| + cf.text_field(:name) + } + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_nested_attributes_collection_association_with_explicit_hidden_field_placement + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + + form_for(@post) do |f| + concat f.text_field(:title) + @post.comments.each do |comment| + concat f.fields_for(:comments, comment) { |cf| + concat cf.hidden_field(:id) + concat cf.text_field(:name) + } + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_new_records_on_a_nested_attributes_collection_association + @post.comments = [Comment.new, Comment.new] + + form_for(@post) do |f| + concat f.text_field(:title) + @post.comments.each do |comment| + concat f.fields_for(:comments, comment) { |cf| + concat cf.text_field(:name) + } + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_and_new_records_on_a_nested_attributes_collection_association + @post.comments = [Comment.new(321), Comment.new] + + form_for(@post) do |f| + concat f.text_field(:title) + @post.comments.each do |comment| + concat f.fields_for(:comments, comment) { |cf| + concat cf.text_field(:name) + } + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_an_empty_supplied_attributes_collection + form_for(@post) do |f| + concat f.text_field(:title) + f.fields_for(:comments, []) do |cf| + concat cf.text_field(:name) + end + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_supplied_nested_attributes_collection + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:comments, @post.comments) { |cf| + concat cf.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_arel_like + @post.comments = ArelLike.new + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:comments, @post.comments) { |cf| + concat cf.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_existing_records_on_a_supplied_nested_attributes_collection_different_from_record_one + comments = Array.new(2) { |id| Comment.new(id + 1) } + @post.comments = [] + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:comments, comments) { |cf| + concat cf.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_on_a_nested_attributes_collection_association_yields_only_builder + @post.comments = [Comment.new(321), Comment.new] + yielded_comments = [] + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.fields_for(:comments) { |cf| + concat cf.text_field(:name) + yielded_comments << cf.object + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + assert_equal yielded_comments, @post.comments + end + + def test_nested_fields_for_with_child_index_option_override_on_a_nested_attributes_collection_association + @post.comments = [] + + form_for(@post) do |f| + concat f.fields_for(:comments, Comment.new(321), child_index: 'abc') { |cf| + concat cf.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + class FakeAssociationProxy + def to_ary + [1, 2, 3] + end + end + + def test_nested_fields_for_with_child_index_option_override_on_a_nested_attributes_collection_association_with_proxy + @post.comments = FakeAssociationProxy.new + + form_for(@post) do |f| + concat f.fields_for(:comments, Comment.new(321), child_index: 'abc') { |cf| + concat cf.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_index_method_with_existing_records_on_a_nested_attributes_collection_association + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + + form_for(@post) do |f| + expected = 0 + @post.comments.each do |comment| + f.fields_for(:comments, comment) { |cf| + assert_equal cf.index, expected + expected += 1 + } + end + end + end + + def test_nested_fields_for_index_method_with_existing_and_new_records_on_a_nested_attributes_collection_association + @post.comments = [Comment.new(321), Comment.new] + + form_for(@post) do |f| + expected = 0 + @post.comments.each do |comment| + f.fields_for(:comments, comment) { |cf| + assert_equal cf.index, expected + expected += 1 + } + end + end + end + + def test_nested_fields_for_index_method_with_existing_records_on_a_supplied_nested_attributes_collection + @post.comments = Array.new(2) { |id| Comment.new(id + 1) } + + form_for(@post) do |f| + expected = 0 + f.fields_for(:comments, @post.comments) { |cf| + assert_equal cf.index, expected + expected += 1 + } + end + end + + def test_nested_fields_for_index_method_with_child_index_option_override_on_a_nested_attributes_collection_association + @post.comments = [] + + form_for(@post) do |f| + f.fields_for(:comments, Comment.new(321), child_index: 'abc') { |cf| + assert_equal cf.index, 'abc' + } + end + end + + def test_nested_fields_uses_unique_indices_for_different_collection_associations + @post.comments = [Comment.new(321)] + @post.tags = [Tag.new(123), Tag.new(456)] + @post.comments[0].relevances = [] + @post.tags[0].relevances = [] + @post.tags[1].relevances = [] + + form_for(@post) do |f| + concat f.fields_for(:comments, @post.comments[0]) { |cf| + concat cf.text_field(:name) + concat cf.fields_for(:relevances, CommentRelevance.new(314)) { |crf| + concat crf.text_field(:value) + } + } + concat f.fields_for(:tags, @post.tags[0]) { |tf| + concat tf.text_field(:value) + concat tf.fields_for(:relevances, TagRelevance.new(3141)) { |trf| + concat trf.text_field(:value) + } + } + concat f.fields_for('tags', @post.tags[1]) { |tf| + concat tf.text_field(:value) + concat tf.fields_for(:relevances, TagRelevance.new(31415)) { |trf| + concat trf.text_field(:value) + } + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_nested_fields_for_with_hash_like_model + @author = HashBackedAuthor.new + + form_for(@post) do |f| + concat f.fields_for(:author, @author) { |af| + concat af.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + '' + end + + assert_dom_equal expected, output_buffer + end + + def test_fields_for + output_buffer = fields_for(:post, @post) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = + "" + + "" + + "" + + "" + + assert_dom_equal expected, output_buffer + end + + def test_fields_for_with_index + output_buffer = fields_for("post[]", @post) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = + "" + + "" + + "" + + "" + + assert_dom_equal expected, output_buffer + end + + def test_fields_for_with_nil_index_option_override + output_buffer = fields_for("post[]", @post, index: nil) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = + "" + + "" + + "" + + "" + + assert_dom_equal expected, output_buffer + end + + def test_fields_for_with_index_option_override + output_buffer = fields_for("post[]", @post, index: "abc") do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = + "" + + "" + + "" + + "" + + assert_dom_equal expected, output_buffer + end + + def test_fields_for_without_object + output_buffer = fields_for(:post) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = + "" + + "" + + "" + + "" + + assert_dom_equal expected, output_buffer + end + + def test_fields_for_with_only_object + output_buffer = fields_for(@post) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = + "" + + "" + + "" + + "" + + assert_dom_equal expected, output_buffer + end + + def test_fields_for_object_with_bracketed_name + output_buffer = fields_for("author[post]", @post) do |f| + concat f.label(:title) + concat f.text_field(:title) + end + + assert_dom_equal "" + + "", + output_buffer + end + + def test_fields_for_object_with_bracketed_name_and_index + output_buffer = fields_for("author[post]", @post, index: 1) do |f| + concat f.label(:title) + concat f.text_field(:title) + end + + assert_dom_equal "" + + "", + output_buffer + end + + def test_form_builder_does_not_have_form_for_method + assert !ActionView::Helpers::FormBuilder.instance_methods.include?(:form_for) + end + + def test_form_for_and_fields_for + form_for(@post, as: :post, html: { id: 'create-post' }) do |post_form| + concat post_form.text_field(:title) + concat post_form.text_area(:body) + + concat fields_for(:parent_post, @post) { |parent_fields| + concat parent_fields.check_box(:secret) + } + end + + expected = whole_form('/posts/123', 'create-post', 'edit_post', method: 'patch') do + "" + + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_and_fields_for_with_object + form_for(@post, as: :post, html: { id: 'create-post' }) do |post_form| + concat post_form.text_field(:title) + concat post_form.text_area(:body) + + concat post_form.fields_for(@comment) { |comment_fields| + concat comment_fields.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'create-post', 'edit_post', method: 'patch') do + "" + + "" + + "" + end + + assert_dom_equal expected, output_buffer + end + + def test_form_for_and_fields_for_with_non_nested_association_and_without_object + form_for(@post) do |f| + concat f.fields_for(:category) { |c| + concat c.text_field(:name) + } + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "" + end + + assert_dom_equal expected, output_buffer + end + + class LabelledFormBuilder < ActionView::Helpers::FormBuilder + (field_helpers - %w(hidden_field)).each do |selector| + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{selector}(field, *args, &proc) + (" " + super + "
").html_safe + end + RUBY_EVAL + end + end + + def test_form_for_with_labelled_builder + form_for(@post, builder: LabelledFormBuilder) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "
" + + "
" + + "
" + end + + assert_dom_equal expected, output_buffer + end + + def test_default_form_builder + old_default_form_builder, ActionView::Base.default_form_builder = + ActionView::Base.default_form_builder, LabelledFormBuilder + + form_for(@post) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "
" + + "
" + + "
" + end + + assert_dom_equal expected, output_buffer + ensure + ActionView::Base.default_form_builder = old_default_form_builder + end + + def test_lazy_loading_default_form_builder + old_default_form_builder, ActionView::Base.default_form_builder = + ActionView::Base.default_form_builder, "FormHelperTest::LabelledFormBuilder" + + form_for(@post) do |f| + concat f.text_field(:title) + end + + expected = whole_form('/posts/123', 'edit_post_123', 'edit_post', method: 'patch') do + "
" + end + + assert_dom_equal expected, output_buffer + ensure + ActionView::Base.default_form_builder = old_default_form_builder + end + + def test_fields_for_with_labelled_builder + output_buffer = fields_for(:post, @post, builder: LabelledFormBuilder) do |f| + concat f.text_field(:title) + concat f.text_area(:body) + concat f.check_box(:secret) + end + + expected = + "
" + + "
" + + "
" + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_labelled_builder_with_nested_fields_for_without_options_hash + klass = nil + + form_for(@post, builder: LabelledFormBuilder) do |f| + f.fields_for(:comments, Comment.new) do |nested_fields| + klass = nested_fields.class + '' + end + end + + assert_equal LabelledFormBuilder, klass + end + + def test_form_for_with_labelled_builder_with_nested_fields_for_with_options_hash + klass = nil + + form_for(@post, builder: LabelledFormBuilder) do |f| + f.fields_for(:comments, Comment.new, index: 'foo') do |nested_fields| + klass = nested_fields.class + '' + end + end + + assert_equal LabelledFormBuilder, klass + end + + def test_form_for_with_labelled_builder_path + path = nil + + form_for(@post, builder: LabelledFormBuilder) do |f| + path = f.to_partial_path + '' + end + + assert_equal 'labelled_form', path + end + + class LabelledFormBuilderSubclass < LabelledFormBuilder; end + + def test_form_for_with_labelled_builder_with_nested_fields_for_with_custom_builder + klass = nil + + form_for(@post, builder: LabelledFormBuilder) do |f| + f.fields_for(:comments, Comment.new, builder: LabelledFormBuilderSubclass) do |nested_fields| + klass = nested_fields.class + '' + end + end + + assert_equal LabelledFormBuilderSubclass, klass + end + + def test_form_for_with_html_options_adds_options_to_form_tag + form_for(@post, html: { id: 'some_form', class: 'some_class', multipart: true }) do |f| end + expected = whole_form("/posts/123", "some_form", "some_class", method: "patch", multipart: "multipart/form-data") + + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_string_url_option + form_for(@post, url: 'http://www.otherdomain.com') do |f| end + + assert_equal whole_form("http://www.otherdomain.com", "edit_post_123", "edit_post", method: "patch"), output_buffer + end + + def test_form_for_with_hash_url_option + form_for(@post, url: { controller: 'controller', action: 'action' }) do |f| end + + assert_equal 'controller', @url_for_options[:controller] + assert_equal 'action', @url_for_options[:action] + end + + def test_form_for_with_record_url_option + form_for(@post, url: @post) do |f| end + + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") + assert_equal expected, output_buffer + end + + def test_form_for_with_existing_object + form_for(@post) do |f| end + + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") + assert_equal expected, output_buffer + end + + def test_form_for_with_new_object + post = Post.new + post.persisted = false + def post.to_key; nil; end + + form_for(post) do |f| end + + expected = whole_form("/posts", "new_post", "new_post") + assert_equal expected, output_buffer + end + + def test_form_for_with_existing_object_in_list + @comment.save + form_for([@post, @comment]) {} + + expected = whole_form(post_comment_path(@post, @comment), "edit_comment_1", "edit_comment", method: "patch") + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_new_object_in_list + form_for([@post, @comment]) {} + + expected = whole_form(post_comments_path(@post), "new_comment", "new_comment") + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_existing_object_and_namespace_in_list + @comment.save + form_for([:admin, @post, @comment]) {} + + expected = whole_form(admin_post_comment_path(@post, @comment), "edit_comment_1", "edit_comment", method: "patch") + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_new_object_and_namespace_in_list + form_for([:admin, @post, @comment]) {} + + expected = whole_form(admin_post_comments_path(@post), "new_comment", "new_comment") + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_existing_object_and_custom_url + form_for(@post, url: "/super_posts") do |f| end + + expected = whole_form("/super_posts", "edit_post_123", "edit_post", method: "patch") + assert_equal expected, output_buffer + end + + def test_form_for_with_default_method_as_patch + form_for(@post) {} + expected = whole_form("/posts/123", "edit_post_123", "edit_post", method: "patch") + assert_dom_equal expected, output_buffer + end + + def test_form_for_with_data_attributes + form_for(@post, data: { behavior: "stuff" }, remote: true) {} + assert_match %r|data-behavior="stuff"|, output_buffer + assert_match %r|data-remote="true"|, output_buffer + end + + def test_fields_for_returns_block_result + output = fields_for(Post.new) { |f| "fields" } + assert_equal "fields", output + end + + def test_form_builder_block_argument_deprecation + builder_class = Class.new(ActionView::Helpers::FormBuilder) do + def initialize(object_name, object, template, options, block) + super + end + end + + assert_deprecated(/Giving a block to FormBuilder is deprecated and has no effect anymore/) do + builder_class.new(:foo, nil, nil, {}, proc {}) + end + end + + def test_form_for_only_instantiates_builder_once + initialization_count = 0 + builder_class = Class.new(ActionView::Helpers::FormBuilder) do + define_method :initialize do |*args| + super(*args) + initialization_count += 1 + end + end + + form_for(@post, builder: builder_class) { } + assert_equal 1, initialization_count, 'form builder instantiated more than once' + end + + protected + + def hidden_fields(method = nil) + txt = %{
} + txt << %{} + if method && !%w(get post).include?(method.to_s) + txt << %{} + end + txt << %{
} + end + + def form_text(action = "/", id = nil, html_class = nil, remote = nil, multipart = nil, method = nil) + txt = %{
} + end + + def whole_form(action = "/", id = nil, html_class = nil, options = {}) + contents = block_given? ? yield : "" + + method, remote, multipart = options.values_at(:method, :remote, :multipart) + + form_text(action, id, html_class, remote, multipart, method) + hidden_fields(method) + contents + "
" + end + + def protect_against_forgery? + false + end +end diff --git a/actionview/test/template/form_options_helper_i18n_test.rb b/actionview/test/template/form_options_helper_i18n_test.rb new file mode 100644 index 0000000000..4972ea6511 --- /dev/null +++ b/actionview/test/template/form_options_helper_i18n_test.rb @@ -0,0 +1,27 @@ +require 'abstract_unit' + +class FormOptionsHelperI18nTests < ActionView::TestCase + tests ActionView::Helpers::FormOptionsHelper + + def setup + @prompt_message = 'Select!' + I18n.backend.send(:init_translations) + I18n.backend.store_translations :en, :helpers => { :select => { :prompt => @prompt_message } } + end + + def teardown + I18n.backend = I18n::Backend::Simple.new + end + + def test_select_with_prompt_true_translates_prompt_message + I18n.expects(:translate).with('helpers.select.prompt', { :default => 'Please select' }) + select('post', 'category', [], :prompt => true) + end + + def test_select_with_translated_prompt + assert_dom_equal( + %Q(), + select('post', 'category', [], :prompt => true) + ) + end +end diff --git a/actionview/test/template/form_options_helper_test.rb b/actionview/test/template/form_options_helper_test.rb new file mode 100644 index 0000000000..1715902927 --- /dev/null +++ b/actionview/test/template/form_options_helper_test.rb @@ -0,0 +1,1304 @@ +require 'abstract_unit' +require 'tzinfo' + +class Map < Hash + def category + "" + end +end + +TZInfo::Timezone.cattr_reader :loaded_zones + +class FormOptionsHelperTest < ActionView::TestCase + tests ActionView::Helpers::FormOptionsHelper + + silence_warnings do + Post = Struct.new('Post', :title, :author_name, :body, :secret, :written_on, :category, :origin, :allow_comments) + Continent = Struct.new('Continent', :continent_name, :countries) + Country = Struct.new('Country', :country_id, :country_name) + Firm = Struct.new('Firm', :time_zone) + Album = Struct.new('Album', :id, :title, :genre) + end + + def setup + @fake_timezones = %w(A B C D E).map do |id| + tz = TZInfo::Timezone.loaded_zones[id] = stub(:name => id, :to_s => id) + ActiveSupport::TimeZone.stubs(:[]).with(id).returns(tz) + tz + end + ActiveSupport::TimeZone.stubs(:all).returns(@fake_timezones) + end + + def test_collection_options + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", "title") + ) + end + + + def test_collection_options_with_preselected_value + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", "title", "Babe") + ) + end + + def test_collection_options_with_preselected_value_array + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", "title", [ "Babe", "Cabe" ]) + ) + end + + def test_collection_options_with_proc_for_selected + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", "title", lambda{|p| p.author_name == 'Babe' }) + ) + end + + def test_collection_options_with_disabled_value + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", "title", :disabled => "Babe") + ) + end + + def test_collection_options_with_disabled_array + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", "title", :disabled => [ "Babe", "Cabe" ]) + ) + end + + def test_collection_options_with_preselected_and_disabled_value + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", "title", :selected => "Cabe", :disabled => "Babe") + ) + end + + def test_collection_options_with_proc_for_disabled + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", "title", :disabled => lambda {|p| %w(Babe Cabe).include?(p.author_name)}) + ) + end + + def test_collection_options_with_proc_for_value_method + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, lambda { |p| p.author_name }, "title") + ) + end + + def test_collection_options_with_proc_for_text_method + assert_dom_equal( + "\n\n", + options_from_collection_for_select(dummy_posts, "author_name", lambda { |p| p.title }) + ) + end + + def test_collection_options_with_element_attributes + assert_dom_equal( + "", + options_from_collection_for_select([[ "USA", "USA", { :class => 'bold' } ]], :first, :second) + ) + end + + def test_string_options_for_select + options = "" + assert_dom_equal( + options, + options_for_select(options) + ) + end + + def test_array_options_for_select + assert_dom_equal( + "\n\n", + options_for_select([ "", "USA", "Sweden" ]) + ) + end + + def test_array_options_for_select_with_selection + assert_dom_equal( + "\n\n", + options_for_select([ "Denmark", "", "Sweden" ], "") + ) + end + + def test_array_options_for_select_with_selection_array + assert_dom_equal( + "\n\n", + options_for_select([ "Denmark", "", "Sweden" ], [ "", "Sweden" ]) + ) + end + + def test_array_options_for_select_with_disabled_value + assert_dom_equal( + "\n\n", + options_for_select([ "Denmark", "", "Sweden" ], :disabled => "") + ) + end + + def test_array_options_for_select_with_disabled_array + assert_dom_equal( + "\n\n", + options_for_select([ "Denmark", "", "Sweden" ], :disabled => ["", "Sweden"]) + ) + end + + def test_array_options_for_select_with_selection_and_disabled_value + assert_dom_equal( + "\n\n", + options_for_select([ "Denmark", "", "Sweden" ], :selected => "Denmark", :disabled => "") + ) + end + + def test_boolean_array_options_for_select_with_selection_and_disabled_value + assert_dom_equal( + "\n", + options_for_select([ true, false ], :selected => false, :disabled => nil) + ) + end + + def test_range_options_for_select + assert_dom_equal( + "\n\n", + options_for_select(1..3) + ) + end + + def test_array_options_for_string_include_in_other_string_bug_fix + assert_dom_equal( + "\n", + options_for_select([ "ruby", "rubyonrails" ], "rubyonrails") + ) + assert_dom_equal( + "\n", + options_for_select([ "ruby", "rubyonrails" ], "ruby") + ) + assert_dom_equal( + %(\n\n), + options_for_select([ "ruby", "rubyonrails", nil ], "ruby") + ) + end + + def test_hash_options_for_select + assert_dom_equal( + "\n", + options_for_select("$" => "Dollar", "" => "").split("\n").join("\n") + ) + assert_dom_equal( + "\n", + options_for_select({ "$" => "Dollar", "" => "" }, "Dollar").split("\n").join("\n") + ) + assert_dom_equal( + "\n", + options_for_select({ "$" => "Dollar", "" => "" }, [ "Dollar", "" ]).split("\n").join("\n") + ) + end + + def test_ducktyped_options_for_select + quack = Struct.new(:first, :last) + assert_dom_equal( + "\n", + options_for_select([quack.new("", ""), quack.new("$", "Dollar")]) + ) + assert_dom_equal( + "\n", + options_for_select([quack.new("", ""), quack.new("$", "Dollar")], "Dollar") + ) + assert_dom_equal( + "\n", + options_for_select([quack.new("", ""), quack.new("$", "Dollar")], ["Dollar", ""]) + ) + end + + def test_collection_options_with_preselected_value_as_string_and_option_value_is_integer + albums = [ Album.new(1, "first","rap"), Album.new(2, "second","pop")] + assert_dom_equal( + %(\n), + options_from_collection_for_select(albums, "id", "genre", :selected => "1") + ) + end + + def test_collection_options_with_preselected_value_as_integer_and_option_value_is_string + albums = [ Album.new("1", "first","rap"), Album.new("2", "second","pop")] + + assert_dom_equal( + %(\n), + options_from_collection_for_select(albums, "id", "genre", :selected => 1) + ) + end + + def test_collection_options_with_preselected_value_as_string_and_option_value_is_float + albums = [ Album.new(1.0, "first","rap"), Album.new(2.0, "second","pop")] + + assert_dom_equal( + %(\n), + options_from_collection_for_select(albums, "id", "genre", :selected => "2.0") + ) + end + + def test_collection_options_with_preselected_value_as_nil + albums = [ Album.new(1.0, "first","rap"), Album.new(2.0, "second","pop")] + + assert_dom_equal( + %(\n), + options_from_collection_for_select(albums, "id", "genre", :selected => nil) + ) + end + + def test_collection_options_with_disabled_value_as_nil + albums = [ Album.new(1.0, "first","rap"), Album.new(2.0, "second","pop")] + + assert_dom_equal( + %(\n), + options_from_collection_for_select(albums, "id", "genre", :disabled => nil) + ) + end + + def test_collection_options_with_disabled_value_as_array + albums = [ Album.new(1.0, "first","rap"), Album.new(2.0, "second","pop")] + + assert_dom_equal( + %(\n), + options_from_collection_for_select(albums, "id", "genre", :disabled => ["1.0", 2.0]) + ) + end + + def test_collection_options_with_preselected_values_as_string_array_and_option_value_is_float + albums = [ Album.new(1.0, "first","rap"), Album.new(2.0, "second","pop"), Album.new(3.0, "third","country") ] + + assert_dom_equal( + %(\n\n), + options_from_collection_for_select(albums, "id", "genre", ["1.0","3.0"]) + ) + end + + def test_option_groups_from_collection_for_select + assert_dom_equal( + "\n\n", + option_groups_from_collection_for_select(dummy_continents, "countries", "continent_name", "country_id", "country_name", "dk") + ) + end + + def test_option_groups_from_collection_for_select_returns_html_safe_string + assert option_groups_from_collection_for_select(dummy_continents, "countries", "continent_name", "country_id", "country_name", "dk").html_safe? + end + + def test_grouped_options_for_select_with_array + assert_dom_equal( + "\n\n", + grouped_options_for_select([ + ["North America", + [['United States','US'],"Canada"]], + ["Europe", + [["Great Britain","GB"], "Germany"]] + ]) + ) + end + + def test_grouped_options_for_select_with_optional_divider + assert_dom_equal( + "\n\n", + + grouped_options_for_select([['US',"Canada"] , ["GB", "Germany"]], nil, divider: "----------") + ) + end + + def test_grouped_options_for_select_with_selected_and_prompt_deprecated + assert_deprecated 'Passing the prompt to grouped_options_for_select as an argument is deprecated. Please use an options hash like `{ prompt: "Choose a product..." }`.' do + assert_dom_equal( + "\n", + grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", "Choose a product...") + ) + end + end + + def test_grouped_options_for_select_with_selected_and_prompt + assert_dom_equal( + "\n", + grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", prompt: "Choose a product...") + ) + end + + def test_grouped_options_for_select_with_selected_and_prompt_true + assert_dom_equal( + "\n", + grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], "Cowboy Hat", prompt: true) + ) + end + + def test_grouped_options_for_select_returns_html_safe_string + assert grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]]).html_safe? + end + + def test_grouped_options_for_select_with_prompt_returns_html_escaped_string_deprecated + ActiveSupport::Deprecation.silence do + assert_dom_equal( + "\n", + grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, '')) + end + end + + def test_grouped_options_for_select_with_prompt_returns_html_escaped_string + assert_dom_equal( + "\n", + grouped_options_for_select([["Hats", ["Baseball Cap","Cowboy Hat"]]], nil, prompt: '')) + end + + def test_optgroups_with_with_options_with_hash + assert_dom_equal( + "\n\n", + grouped_options_for_select({'North America' => ['United States','Canada'], 'Europe' => ['Denmark','Germany']}) + ) + end + + def test_time_zone_options_no_params + opts = time_zone_options_for_select + assert_dom_equal "\n" + + "\n" + + "\n" + + "\n" + + "", + opts + end + + def test_time_zone_options_with_selected + opts = time_zone_options_for_select( "D" ) + assert_dom_equal "\n" + + "\n" + + "\n" + + "\n" + + "", + opts + end + + def test_time_zone_options_with_unknown_selected + opts = time_zone_options_for_select( "K" ) + assert_dom_equal "\n" + + "\n" + + "\n" + + "\n" + + "", + opts + end + + def test_time_zone_options_with_priority_zones + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] + opts = time_zone_options_for_select( nil, zones ) + assert_dom_equal "\n" + + "" + + "\n" + + "\n" + + "\n" + + "", + opts + end + + def test_time_zone_options_with_selected_priority_zones + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] + opts = time_zone_options_for_select( "E", zones ) + assert_dom_equal "\n" + + "" + + "\n" + + "\n" + + "\n" + + "", + opts + end + + def test_time_zone_options_with_unselected_priority_zones + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] + opts = time_zone_options_for_select( "C", zones ) + assert_dom_equal "\n" + + "" + + "\n" + + "\n" + + "\n" + + "", + opts + end + + def test_time_zone_options_with_priority_zones_does_not_mutate_time_zones + original_zones = ActiveSupport::TimeZone.all.dup + zones = [ ActiveSupport::TimeZone.new( "B" ), ActiveSupport::TimeZone.new( "E" ) ] + time_zone_options_for_select(nil, zones) + assert_equal original_zones, ActiveSupport::TimeZone.all + end + + def test_time_zone_options_returns_html_safe_string + assert time_zone_options_for_select.html_safe? + end + + def test_select + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest)) + ) + end + + def test_select_without_multiple + assert_dom_equal( + "", + select(:post, :category, "", {}, :multiple => false) + ) + end + + def test_select_with_grouped_collection_as_nested_array + @post = Post.new + + countries_by_continent = [ + ["", [["", ""], ["Somalia", "so"]]], + ["Europe", [["Denmark", "dk"], ["Ireland", "ie"]]], + ] + + assert_dom_equal( + [ + %Q{}, + ].join("\n"), + select("post", "origin", countries_by_continent) + ) + end + + def test_select_with_grouped_collection_as_hash + @post = Post.new + + countries_by_continent = { + "" => [["", ""], ["Somalia", "so"]], + "Europe" => [["Denmark", "dk"], ["Ireland", "ie"]], + } + + assert_dom_equal( + [ + %Q{}, + ].join("\n"), + select("post", "origin", countries_by_continent) + ) + end + + def test_select_with_boolean_method + @post = Post.new + @post.allow_comments = false + assert_dom_equal( + "", + select("post", "allow_comments", %w( true false )) + ) + end + + def test_select_under_fields_for + @post = Post.new + @post.category = "" + + output_buffer = fields_for :post, @post do |f| + concat f.select(:category, %w( abe hest)) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_fields_for_with_record_inherited_from_hash + map = Map.new + + output_buffer = fields_for :map, map do |f| + concat f.select(:category, %w( abe hest)) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_select_under_fields_for_with_index + @post = Post.new + @post.category = "" + + output_buffer = fields_for :post, @post, :index => 108 do |f| + concat f.select(:category, %w( abe hest)) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_select_under_fields_for_with_auto_index + @post = Post.new + @post.category = "" + def @post.to_param; 108; end + + output_buffer = fields_for "post[]", @post do |f| + concat f.select(:category, %w( abe hest)) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_select_under_fields_for_with_string_and_given_prompt + @post = Post.new + options = "".html_safe + + output_buffer = fields_for :post, @post do |f| + concat f.select(:category, options, :prompt => 'The prompt') + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_select_with_multiple_to_add_hidden_input + output_buffer = select(:post, :category, "", {}, :multiple => true) + assert_dom_equal( + "", + output_buffer + ) + end + + def test_select_with_multiple_and_without_hidden_input + output_buffer = select(:post, :category, "", {:include_hidden => false}, :multiple => true) + assert_dom_equal( + "", + output_buffer + ) + end + + def test_select_with_multiple_and_with_explicit_name_ending_with_brackets + output_buffer = select(:post, :category, [], {include_hidden: false}, multiple: true, name: 'post[category][]') + assert_dom_equal( + "", + output_buffer + ) + end + + def test_select_with_multiple_and_disabled_to_add_disabled_hidden_input + output_buffer = select(:post, :category, "", {}, :multiple => true, :disabled => true) + assert_dom_equal( + "", + output_buffer + ) + end + + def test_select_with_blank + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest), :include_blank => true) + ) + end + + def test_select_with_blank_as_string + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest), :include_blank => 'None') + ) + end + + def test_select_with_blank_as_string_escaped + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest), :include_blank => '') + ) + end + + def test_select_with_default_prompt + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest), :prompt => true) + ) + end + + def test_select_no_prompt_when_select_has_value + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest), :prompt => true) + ) + end + + def test_select_with_given_prompt + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest), :prompt => 'The prompt') + ) + end + + def test_select_with_given_prompt_escaped + @post = Post.new + assert_dom_equal( + "", + select("post", "category", %w( abe hest), :prompt => '') + ) + end + + def test_select_with_prompt_and_blank + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest), :prompt => true, :include_blank => true) + ) + end + + def test_empty + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", [], :prompt => true, :include_blank => true) + ) + end + + def test_select_with_nil + @post = Post.new + @post.category = "othervalue" + assert_dom_equal( + "", + select("post", "category", [nil, "othervalue"]) + ) + end + + def test_required_select + assert_dom_equal( + %(), + select("post", "category", %w(abe mus hest), {}, required: true) + ) + end + + def test_required_select_with_include_blank_prompt + assert_dom_equal( + %(), + select("post", "category", %w(abe mus hest), { include_blank: "Select one" }, required: true) + ) + end + + def test_required_select_with_prompt + assert_dom_equal( + %(), + select("post", "category", %w(abe mus hest), { prompt: "Select one" }, required: true) + ) + end + + def test_required_select_display_size_equals_to_one + assert_dom_equal( + %(), + select("post", "category", %w(abe mus hest), {}, required: true, size: 1) + ) + end + + def test_required_select_with_display_size_bigger_than_one + assert_dom_equal( + %(), + select("post", "category", %w(abe mus hest), {}, required: true, size: 2) + ) + end + + def test_required_select_with_multiple_option + assert_dom_equal( + %(), + select("post", "category", %w(abe mus hest), {}, required: true, multiple: true) + ) + end + + def test_select_with_fixnum + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", [1], :prompt => true, :include_blank => true) + ) + end + + def test_list_of_lists + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", [["Number", "number"], ["Text", "text"], ["Yes/No", "boolean"]], :prompt => true, :include_blank => true) + ) + end + + def test_select_with_selected_value + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest ), :selected => 'abe') + ) + end + + def test_select_with_index_option + @album = Album.new + @album.id = 1 + + expected = "" + + assert_dom_equal( + expected, + select("album[]", "genre", %w[rap rock country], {}, { :index => nil }) + ) + end + + def test_select_escapes_options + assert_dom_equal( + '', + select('post', 'title', '') + ) + end + + def test_select_with_selected_nil + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest ), :selected => nil) + ) + end + + def test_select_with_disabled_value + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest ), :disabled => 'hest') + ) + end + + def test_select_with_disabled_array + @post = Post.new + @post.category = "" + assert_dom_equal( + "", + select("post", "category", %w( abe hest ), :disabled => ['hest', 'abe']) + ) + end + + def test_select_with_range + @post = Post.new + @post.category = 0 + assert_dom_equal( + "", + select("post", "category", 1..3) + ) + end + + def test_collection_select + @post = Post.new + @post.author_name = "Babe" + + assert_dom_equal( + "", + collection_select("post", "author_name", dummy_posts, "author_name", "author_name") + ) + end + + def test_collection_select_under_fields_for + @post = Post.new + @post.author_name = "Babe" + + output_buffer = fields_for :post, @post do |f| + concat f.collection_select(:author_name, dummy_posts, :author_name, :author_name) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_collection_select_under_fields_for_with_index + @post = Post.new + @post.author_name = "Babe" + + output_buffer = fields_for :post, @post, :index => 815 do |f| + concat f.collection_select(:author_name, dummy_posts, :author_name, :author_name) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_collection_select_under_fields_for_with_auto_index + @post = Post.new + @post.author_name = "Babe" + def @post.to_param; 815; end + + output_buffer = fields_for "post[]", @post do |f| + concat f.collection_select(:author_name, dummy_posts, :author_name, :author_name) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_collection_select_with_blank_and_style + @post = Post.new + @post.author_name = "Babe" + + assert_dom_equal( + "", + collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { :include_blank => true }, "style" => "width: 200px") + ) + end + + def test_collection_select_with_blank_as_string_and_style + @post = Post.new + @post.author_name = "Babe" + + assert_dom_equal( + "", + collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { :include_blank => 'No Selection' }, "style" => "width: 200px") + ) + end + + def test_collection_select_with_multiple_option_appends_array_brackets_and_hidden_input + @post = Post.new + @post.author_name = "Babe" + + expected = "" + + # Should suffix default name with []. + assert_dom_equal expected, collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { :include_blank => true }, :multiple => true) + + # Shouldn't suffix custom name with []. + assert_dom_equal expected, collection_select("post", "author_name", dummy_posts, "author_name", "author_name", { :include_blank => true, :name => 'post[author_name][]' }, :multiple => true) + end + + def test_collection_select_with_blank_and_selected + @post = Post.new + @post.author_name = "Babe" + + assert_dom_equal( + %{}, + collection_select("post", "author_name", dummy_posts, "author_name", "author_name", {:include_blank => true, :selected => ""}) + ) + end + + def test_collection_select_with_disabled + @post = Post.new + @post.author_name = "Babe" + + assert_dom_equal( + "", + collection_select("post", "author_name", dummy_posts, "author_name", "author_name", :disabled => 'Cabe') + ) + end + + def test_collection_select_with_proc_for_value_method + @post = Post.new + + assert_dom_equal( + "", + collection_select("post", "author_name", dummy_posts, lambda { |p| p.author_name }, "title") + ) + end + + def test_collection_select_with_proc_for_text_method + @post = Post.new + + assert_dom_equal( + "", + collection_select("post", "author_name", dummy_posts, "author_name", lambda { |p| p.title }) + ) + end + + def test_time_zone_select + @firm = Firm.new("D") + html = time_zone_select( "firm", "time_zone" ) + assert_dom_equal "", + html + end + + def test_time_zone_select_under_fields_for + @firm = Firm.new("D") + + output_buffer = fields_for :firm, @firm do |f| + concat f.time_zone_select(:time_zone) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_time_zone_select_under_fields_for_with_index + @firm = Firm.new("D") + + output_buffer = fields_for :firm, @firm, :index => 305 do |f| + concat f.time_zone_select(:time_zone) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_time_zone_select_under_fields_for_with_auto_index + @firm = Firm.new("D") + def @firm.to_param; 305; end + + output_buffer = fields_for "firm[]", @firm do |f| + concat f.time_zone_select(:time_zone) + end + + assert_dom_equal( + "", + output_buffer + ) + end + + def test_time_zone_select_with_blank + @firm = Firm.new("D") + html = time_zone_select("firm", "time_zone", nil, :include_blank => true) + assert_dom_equal "", + html + end + + def test_time_zone_select_with_blank_as_string + @firm = Firm.new("D") + html = time_zone_select("firm", "time_zone", nil, :include_blank => 'No Zone') + assert_dom_equal "", + html + end + + def test_time_zone_select_with_style + @firm = Firm.new("D") + html = time_zone_select("firm", "time_zone", nil, {}, + "style" => "color: red") + assert_dom_equal "", + html + assert_dom_equal html, time_zone_select("firm", "time_zone", nil, {}, + :style => "color: red") + end + + def test_time_zone_select_with_blank_and_style + @firm = Firm.new("D") + html = time_zone_select("firm", "time_zone", nil, + { :include_blank => true }, "style" => "color: red") + assert_dom_equal "", + html + assert_dom_equal html, time_zone_select("firm", "time_zone", nil, + { :include_blank => true }, :style => "color: red") + end + + def test_time_zone_select_with_blank_as_string_and_style + @firm = Firm.new("D") + html = time_zone_select("firm", "time_zone", nil, + { :include_blank => 'No Zone' }, "style" => "color: red") + assert_dom_equal "", + html + assert_dom_equal html, time_zone_select("firm", "time_zone", nil, + { :include_blank => 'No Zone' }, :style => "color: red") + end + + def test_time_zone_select_with_priority_zones + @firm = Firm.new("D") + zones = [ ActiveSupport::TimeZone.new("A"), ActiveSupport::TimeZone.new("D") ] + html = time_zone_select("firm", "time_zone", zones ) + assert_dom_equal "", + html + end + + def test_time_zone_select_with_priority_zones_as_regexp + @firm = Firm.new("D") + + @fake_timezones.each_with_index do |tz, i| + tz.stubs(:=~).returns(i.zero? || i == 3) + end + + html = time_zone_select("firm", "time_zone", /A|D/) + assert_dom_equal "", + html + end + + def test_time_zone_select_with_priority_zones_as_regexp_using_grep_finds_no_zones + @firm = Firm.new("D") + + priority_zones = /A|D/ + @fake_timezones.each do |tz| + priority_zones.stubs(:===).with(tz).raises(Exception) + end + + html = time_zone_select("firm", "time_zone", priority_zones) + assert_dom_equal "", + html + end + + def test_time_zone_select_with_default_time_zone_and_nil_value + @firm = Firm.new() + @firm.time_zone = nil + + html = time_zone_select( "firm", "time_zone", nil, :default => 'B' ) + assert_dom_equal "", + html + end + + def test_time_zone_select_with_default_time_zone_and_value + @firm = Firm.new('D') + + html = time_zone_select( "firm", "time_zone", nil, :default => 'B' ) + assert_dom_equal "", + html + end + + def test_options_for_select_with_element_attributes + assert_dom_equal( + "\n\n\n", + options_for_select([ [ "", { :class => 'bold' } ], [ "USA", { :onclick => "alert('Hello World');" } ], [ "Sweden" ], "Germany" ]) + ) + end + + def test_options_for_select_with_data_element + assert_dom_equal( + "", + options_for_select([ [ "", { :data => { :test => 'bold' } } ] ]) + ) + end + + def test_options_for_select_with_data_element_with_special_characters + assert_dom_equal( + "", + options_for_select([ [ "", { :data => { :test => '' } } ] ]) + ) + end + + def test_options_for_select_with_element_attributes_and_selection + assert_dom_equal( + "\n\n", + options_for_select([ "", [ "USA", { :class => 'bold' } ], "Sweden" ], "USA") + ) + end + + def test_options_for_select_with_element_attributes_and_selection_array + assert_dom_equal( + "\n\n", + options_for_select([ "", [ "USA", { :class => 'bold' } ], "Sweden" ], [ "USA", "Sweden" ]) + ) + end + + def test_options_for_select_with_special_characters + assert_dom_equal( + "", + options_for_select([ [ "", { :onclick => %(alert("")) } ] ]) + ) + end + + def test_option_html_attributes_with_no_array_element + assert_equal({}, option_html_attributes('foo')) + end + + def test_option_html_attributes_without_hash + assert_equal({}, option_html_attributes([ 'foo', 'bar' ])) + end + + def test_option_html_attributes_with_single_element_hash + assert_equal( + {:class => 'fancy'}, + option_html_attributes([ 'foo', 'bar', { :class => 'fancy' } ]) + ) + end + + def test_option_html_attributes_with_multiple_element_hash + assert_equal( + {:class => 'fancy', 'onclick' => "alert('Hello World');"}, + option_html_attributes([ 'foo', 'bar', { :class => 'fancy', 'onclick' => "alert('Hello World');" } ]) + ) + end + + def test_option_html_attributes_with_multiple_hashes + assert_equal( + {:class => 'fancy', 'onclick' => "alert('Hello World');"}, + option_html_attributes([ 'foo', 'bar', { :class => 'fancy' }, { 'onclick' => "alert('Hello World');" } ]) + ) + end + + def test_option_html_attributes_with_multiple_hashes_does_not_modify_them + options1 = { class: 'fancy' } + options2 = { onclick: "alert('Hello World');" } + option_html_attributes([ 'foo', 'bar', options1, options2 ]) + + assert_equal({ class: 'fancy' }, options1) + assert_equal({ onclick: "alert('Hello World');" }, options2) + end + + def test_grouped_collection_select + @post = Post.new + @post.origin = 'dk' + + assert_dom_equal( + %Q{}, + grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name) + ) + end + + def test_grouped_collection_select_with_selected + @post = Post.new + + assert_dom_equal( + %Q{}, + grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name, :selected => 'dk') + ) + end + + def test_grouped_collection_select_with_disabled_value + @post = Post.new + + assert_dom_equal( + %Q{}, + grouped_collection_select("post", "origin", dummy_continents, :countries, :continent_name, :country_id, :country_name, :disabled => 'dk') + ) + end + + def test_grouped_collection_select_under_fields_for + @post = Post.new + @post.origin = 'dk' + + output_buffer = fields_for :post, @post do |f| + concat f.grouped_collection_select("origin", dummy_continents, :countries, :continent_name, :country_id, :country_name) + end + + assert_dom_equal( + %Q{}, + output_buffer + ) + end + + private + + def dummy_posts + [ Post.new(" went home", "", "To a little house", "shh!"), + Post.new("Babe went home", "Babe", "To a little house", "shh!"), + Post.new("Cabe went home", "Cabe", "To a little house", "shh!") ] + end + + def dummy_continents + [ Continent.new("", [Country.new("", ""), Country.new("so", "Somalia")]), + Continent.new("Europe", [Country.new("dk", "Denmark"), Country.new("ie", "Ireland")]) ] + end +end diff --git a/actionview/test/template/form_tag_helper_test.rb b/actionview/test/template/form_tag_helper_test.rb new file mode 100644 index 0000000000..70fc6a588b --- /dev/null +++ b/actionview/test/template/form_tag_helper_test.rb @@ -0,0 +1,614 @@ +require 'abstract_unit' + +class FormTagHelperTest < ActionView::TestCase + include RenderERBUtils + + tests ActionView::Helpers::FormTagHelper + + def setup + super + @controller = BasicController.new + end + + def hidden_fields(options = {}) + method = options[:method] + + txt = %{
} + txt << %{} + if method && !%w(get post).include?(method.to_s) + txt << %{} + end + txt << %{
} + end + + def form_text(action = "http://www.example.com", options = {}) + remote, enctype, html_class, id, method = options.values_at(:remote, :enctype, :html_class, :id, :method) + + method = method.to_s == "get" ? "get" : "post" + + txt = %{
} + end + + def whole_form(action = "http://www.example.com", options = {}) + out = form_text(action, options) + hidden_fields(options) + + if block_given? + out << yield << "
" + end + + out + end + + def url_for(options) + if options.is_a?(Hash) + "http://www.example.com" + else + super + end + end + + VALID_HTML_ID = /^[A-Za-z][-_:.A-Za-z0-9]*$/ # see http://www.w3.org/TR/html4/types.html#type-name + + def test_check_box_tag + actual = check_box_tag "admin" + expected = %() + assert_dom_equal expected, actual + end + + def test_check_box_tag_id_sanitized + label_elem = root_elem(check_box_tag("project[2][admin]")) + assert_match VALID_HTML_ID, label_elem['id'] + end + + def test_form_tag + actual = form_tag + expected = whole_form + assert_dom_equal expected, actual + end + + def test_form_tag_multipart + actual = form_tag({}, { 'multipart' => true }) + expected = whole_form("http://www.example.com", :enctype => true) + assert_dom_equal expected, actual + end + + def test_form_tag_with_method_patch + actual = form_tag({}, { :method => :patch }) + expected = whole_form("http://www.example.com", :method => :patch) + assert_dom_equal expected, actual + end + + def test_form_tag_with_method_put + actual = form_tag({}, { :method => :put }) + expected = whole_form("http://www.example.com", :method => :put) + assert_dom_equal expected, actual + end + + def test_form_tag_with_method_delete + actual = form_tag({}, { :method => :delete }) + + expected = whole_form("http://www.example.com", :method => :delete) + assert_dom_equal expected, actual + end + + def test_form_tag_with_remote + actual = form_tag({}, :remote => true) + + expected = whole_form("http://www.example.com", :remote => true) + assert_dom_equal expected, actual + end + + def test_form_tag_with_remote_false + actual = form_tag({}, :remote => false) + + expected = whole_form + assert_dom_equal expected, actual + end + + def test_form_tag_with_block_in_erb + output_buffer = render_erb("<%= form_tag('http://www.example.com') do %>Hello world!<% end %>") + + expected = whole_form { "Hello world!" } + assert_dom_equal expected, output_buffer + end + + def test_form_tag_with_block_and_method_in_erb + output_buffer = render_erb("<%= form_tag('http://www.example.com', :method => :put) do %>Hello world!<% end %>") + + expected = whole_form("http://www.example.com", :method => "put") do + "Hello world!" + end + + assert_dom_equal expected, output_buffer + end + + def test_hidden_field_tag + actual = hidden_field_tag "id", 3 + expected = %() + assert_dom_equal expected, actual + end + + def test_hidden_field_tag_id_sanitized + input_elem = root_elem(hidden_field_tag("item[][title]")) + assert_match VALID_HTML_ID, input_elem['id'] + end + + def test_file_field_tag + assert_dom_equal "", file_field_tag("picsplz") + end + + def test_file_field_tag_with_options + assert_dom_equal "", file_field_tag("picsplz", :class => "pix") + end + + def test_password_field_tag + actual = password_field_tag + expected = %() + assert_dom_equal expected, actual + end + + def test_radio_button_tag + actual = radio_button_tag "people", "david" + expected = %() + assert_dom_equal expected, actual + + actual = radio_button_tag("num_people", 5) + expected = %() + assert_dom_equal expected, actual + + actual = radio_button_tag("gender", "m") + radio_button_tag("gender", "f") + expected = %() + assert_dom_equal expected, actual + + actual = radio_button_tag("opinion", "-1") + radio_button_tag("opinion", "1") + expected = %() + assert_dom_equal expected, actual + + actual = radio_button_tag("person[gender]", "m") + expected = %() + assert_dom_equal expected, actual + + actual = radio_button_tag('ctrlname', 'apache2.2') + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag + actual = select_tag "people", "".html_safe + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag_with_multiple + actual = select_tag "colors", "".html_safe, :multiple => :true + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag_disabled + actual = select_tag "places", "".html_safe, :disabled => :true + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag_id_sanitized + input_elem = root_elem(select_tag("project[1]people", "")) + assert_match VALID_HTML_ID, input_elem['id'] + end + + def test_select_tag_with_include_blank + actual = select_tag "places", "".html_safe, :include_blank => true + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag_with_prompt + actual = select_tag "places", "".html_safe, :prompt => "string" + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag_escapes_prompt + actual = select_tag "places", "".html_safe, :prompt => "" + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag_with_prompt_and_include_blank + actual = select_tag "places", "".html_safe, :prompt => "string", :include_blank => true + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag_with_nil_option_tags_and_include_blank + actual = select_tag "places", nil, :include_blank => true + expected = %() + assert_dom_equal expected, actual + end + + def test_select_tag_with_nil_option_tags_and_prompt + actual = select_tag "places", nil, :prompt => "string" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_area_tag_size_string + actual = text_area_tag "body", "hello world", "size" => "20x40" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_area_tag_size_symbol + actual = text_area_tag "body", "hello world", :size => "20x40" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_area_tag_should_disregard_size_if_its_given_as_an_integer + actual = text_area_tag "body", "hello world", :size => 20 + expected = %() + assert_dom_equal expected, actual + end + + def test_text_area_tag_id_sanitized + input_elem = root_elem(text_area_tag("item[][description]")) + assert_match VALID_HTML_ID, input_elem['id'] + end + + def test_text_area_tag_escape_content + actual = text_area_tag "body", "hello world", :size => "20x40" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_area_tag_unescaped_content + actual = text_area_tag "body", "hello world", :size => "20x40", :escape => false + expected = %() + assert_dom_equal expected, actual + end + + def test_text_area_tag_unescaped_nil_content + actual = text_area_tag "body", nil, :escape => false + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_tag + actual = text_field_tag "title", "Hello!" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_tag_class_string + actual = text_field_tag "title", "Hello!", "class" => "admin" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_tag_size_symbol + actual = text_field_tag "title", "Hello!", :size => 75 + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_tag_size_string + actual = text_field_tag "title", "Hello!", "size" => "75" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_tag_maxlength_symbol + actual = text_field_tag "title", "Hello!", :maxlength => 75 + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_tag_maxlength_string + actual = text_field_tag "title", "Hello!", "maxlength" => "75" + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_disabled + actual = text_field_tag "title", "Hello!", :disabled => :true + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_tag_with_multiple_options + actual = text_field_tag "title", "Hello!", :size => 70, :maxlength => 80 + expected = %() + assert_dom_equal expected, actual + end + + def test_text_field_tag_id_sanitized + input_elem = root_elem(text_field_tag("item[][title]")) + assert_match VALID_HTML_ID, input_elem['id'] + end + + def test_label_tag_without_text + actual = label_tag "title" + expected = %() + assert_dom_equal expected, actual + end + + def test_label_tag_with_symbol + actual = label_tag :title + expected = %() + assert_dom_equal expected, actual + end + + def test_label_tag_with_text + actual = label_tag "title", "My Title" + expected = %() + assert_dom_equal expected, actual + end + + def test_label_tag_class_string + actual = label_tag "title", "My Title", "class" => "small_label" + expected = %() + assert_dom_equal expected, actual + end + + def test_label_tag_id_sanitized + label_elem = root_elem(label_tag("item[title]")) + assert_match VALID_HTML_ID, label_elem['for'] + end + + def test_label_tag_with_block + assert_dom_equal('', label_tag { "Blocked" }) + end + + def test_label_tag_with_block_and_argument + output = label_tag("clock") { "Grandfather" } + assert_dom_equal('', output) + end + + def test_label_tag_with_block_and_argument_and_options + output = label_tag("clock", :id => "label_clock") { "Grandfather" } + assert_dom_equal('', output) + end + + def test_boolean_options + assert_dom_equal %(), check_box_tag("admin", 1, true, 'disabled' => true, :readonly => "yes") + assert_dom_equal %(), check_box_tag("admin", 1, true, :disabled => false, :readonly => nil) + assert_dom_equal %(), tag(:input, :type => "checkbox", :checked => false) + assert_dom_equal %(), select_tag("people", "".html_safe, :multiple => true) + assert_dom_equal %(), select_tag("people[]", "".html_safe, :multiple => true) + assert_dom_equal %(), select_tag("people", "".html_safe, :multiple => nil) + end + + def test_stringify_symbol_keys + actual = text_field_tag "title", "Hello!", :id => "admin" + expected = %() + assert_dom_equal expected, actual + end + + def test_submit_tag + assert_dom_equal( + %(), + submit_tag("Save", :onclick => "alert('hello!')", :data => { :disable_with => "Saving..." }) + ) + end + + def test_submit_tag_with_no_onclick_options + assert_dom_equal( + %(), + submit_tag("Save", :data => { :disable_with => "Saving..." }) + ) + end + + def test_submit_tag_with_confirmation + assert_dom_equal( + %(), + submit_tag("Save", :data => { :confirm => "Are you sure?" }) + ) + end + + def test_button_tag + assert_dom_equal( + %(), + button_tag + ) + end + + def test_button_tag_with_submit_type + assert_dom_equal( + %(), + button_tag("Save", :type => "submit") + ) + end + + def test_button_tag_with_button_type + assert_dom_equal( + %(), + button_tag("Button", :type => "button") + ) + end + + def test_button_tag_with_reset_type + assert_dom_equal( + %(), + button_tag("Reset", :type => "reset") + ) + end + + def test_button_tag_with_disabled_option + assert_dom_equal( + %(), + button_tag("Reset", :type => "reset", :disabled => true) + ) + end + + def test_button_tag_escape_content + assert_dom_equal( + %(), + button_tag("Reset", :type => "reset", :disabled => true) + ) + end + + def test_button_tag_with_block + assert_dom_equal('', button_tag { 'Content' }) + end + + def test_button_tag_with_block_and_options + output = button_tag(:name => 'temptation', :type => 'button') { content_tag(:strong, 'Do not press me') } + assert_dom_equal('', output) + end + + def test_button_tag_with_confirmation + assert_dom_equal( + %(), + button_tag("Save", :type => "submit", :data => { :confirm => "Are you sure?" }) + ) + end + + def test_image_submit_tag_with_confirmation + assert_dom_equal( + %(), + image_submit_tag("save.gif", :data => { :confirm => "Are you sure?" }) + ) + end + + def test_color_field_tag + expected = %{} + assert_dom_equal(expected, color_field_tag("car")) + end + + def test_search_field_tag + expected = %{} + assert_dom_equal(expected, search_field_tag("query")) + end + + def test_telephone_field_tag + expected = %{} + assert_dom_equal(expected, telephone_field_tag("cell")) + end + + def test_date_field_tag + expected = %{} + assert_dom_equal(expected, date_field_tag("cell")) + end + + def test_time_field_tag + expected = %{} + assert_dom_equal(expected, time_field_tag("cell")) + end + + def test_datetime_field_tag + expected = %{} + assert_dom_equal(expected, datetime_field_tag("appointment")) + end + + def test_datetime_local_field_tag + expected = %{} + assert_dom_equal(expected, datetime_local_field_tag("appointment")) + end + + def test_month_field_tag + expected = %{} + assert_dom_equal(expected, month_field_tag("birthday")) + end + + def test_week_field_tag + expected = %{} + assert_dom_equal(expected, week_field_tag("birthday")) + end + + def test_url_field_tag + expected = %{} + assert_dom_equal(expected, url_field_tag("homepage")) + end + + def test_email_field_tag + expected = %{} + assert_dom_equal(expected, email_field_tag("address")) + end + + def test_number_field_tag + expected = %{} + assert_dom_equal(expected, number_field_tag("quantity", nil, :in => 1...10)) + end + + def test_range_input_tag + expected = %{} + assert_dom_equal(expected, range_field_tag("volume", nil, :in => 0..11, :step => 0.1)) + end + + def test_field_set_tag_in_erb + output_buffer = render_erb("<%= field_set_tag('Your details') do %>Hello world!<% end %>") + + expected = %(
Your detailsHello world!
) + assert_dom_equal expected, output_buffer + + output_buffer = render_erb("<%= field_set_tag do %>Hello world!<% end %>") + + expected = %(
Hello world!
) + assert_dom_equal expected, output_buffer + + output_buffer = render_erb("<%= field_set_tag('') do %>Hello world!<% end %>") + + expected = %(
Hello world!
) + assert_dom_equal expected, output_buffer + + output_buffer = render_erb("<%= field_set_tag('', :class => 'format') do %>Hello world!<% end %>") + + expected = %(
Hello world!
) + assert_dom_equal expected, output_buffer + + output_buffer = render_erb("<%= field_set_tag %>") + + expected = %(
) + assert_dom_equal expected, output_buffer + + output_buffer = render_erb("<%= field_set_tag('You legend!') %>") + + expected = %(
You legend!
) + assert_dom_equal expected, output_buffer + end + + def test_text_area_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + text_area_tag "body", "hello world", options + assert_equal options, { :option => "random_option" } + end + + def test_submit_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + submit_tag "submit value", options + assert_equal options, { :option => "random_option" } + end + + def test_button_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + button_tag "button value", options + assert_equal options, { :option => "random_option" } + end + + def test_image_submit_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + image_submit_tag "submit source", options + assert_equal options, { :option => "random_option" } + end + + def test_image_label_tag_options_symbolize_keys_side_effects + options = { :option => "random_option" } + label_tag "submit source", "title", options + assert_equal options, { :option => "random_option" } + end + + def protect_against_forgery? + false + end + + private + + def root_elem(rendered_content) + HTML::Document.new(rendered_content).root.children[0] + end +end diff --git a/actionview/test/template/html-scanner/cdata_node_test.rb b/actionview/test/template/html-scanner/cdata_node_test.rb new file mode 100644 index 0000000000..9b58174641 --- /dev/null +++ b/actionview/test/template/html-scanner/cdata_node_test.rb @@ -0,0 +1,15 @@ +require 'abstract_unit' + +class CDATANodeTest < ActiveSupport::TestCase + def setup + @node = HTML::CDATA.new(nil, 0, 0, "

howdy

") + end + + def test_to_s + assert_equal "howdy

]]>", @node.to_s + end + + def test_content + assert_equal "

howdy

", @node.content + end +end diff --git a/actionview/test/template/html-scanner/document_test.rb b/actionview/test/template/html-scanner/document_test.rb new file mode 100644 index 0000000000..17f045d549 --- /dev/null +++ b/actionview/test/template/html-scanner/document_test.rb @@ -0,0 +1,148 @@ +require 'abstract_unit' + +class DocumentTest < ActiveSupport::TestCase + def test_handle_doctype + doc = nil + assert_nothing_raised do + doc = HTML::Document.new <<-HTML.strip + + + + HTML + end + assert_equal 3, doc.root.children.length + assert_equal %{}, doc.root.children[0].content + assert_match %r{\s+}m, doc.root.children[1].content + assert_equal "html", doc.root.children[2].name + end + + def test_find_img + doc = HTML::Document.new <<-HTML.strip + + +

+ + + HTML + assert doc.find(:tag=>"img", :attributes=>{"src"=>"hello.gif"}) + end + + def test_find_all + doc = HTML::Document.new <<-HTML.strip + + +

+
+

something

+

here is more

+
+ + + HTML + all = doc.find_all :attributes => { :class => "test" } + assert_equal 3, all.length + assert_equal [ "p", "p", "em" ], all.map { |n| n.name } + end + + def test_find_with_text + doc = HTML::Document.new <<-HTML.strip + + +

Some text

+ + + HTML + assert doc.find(:content => "Some text") + assert doc.find(:tag => "p", :child => { :content => "Some text" }) + assert doc.find(:tag => "p", :child => "Some text") + assert doc.find(:tag => "p", :content => "Some text") + end + + def test_parse_xml + assert_nothing_raised { HTML::Document.new("", true, true) } + assert_nothing_raised { HTML::Document.new("something", true, true) } + end + + def test_parse_document + doc = HTML::Document.new(<<-HTML) +
+

blah

+ +
+
+ HTML + assert_not_nil doc.find(:tag => "div", :children => { :count => 1, :only => { :tag => "table" } }) + end + + def test_tag_nesting_nothing_to_s + doc = HTML::Document.new("") + assert_equal "", doc.root.to_s + end + + def test_tag_nesting_space_to_s + doc = HTML::Document.new(" ") + assert_equal " ", doc.root.to_s + end + + def test_tag_nesting_text_to_s + doc = HTML::Document.new("text") + assert_equal "text", doc.root.to_s + end + + def test_tag_nesting_tag_to_s + doc = HTML::Document.new("") + assert_equal "", doc.root.to_s + end + + def test_parse_cdata + doc = HTML::Document.new(<<-HTML) + + + + <![CDATA[<br>]]> + + +

this document has <br> for a title

+ + +HTML + + assert_nil doc.find(:tag => "title", :descendant => { :tag => "br" }) + assert doc.find(:tag => "title", :child => "
") + end + + def test_find_empty_tag + doc = HTML::Document.new("
") + assert_nil doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /./) + assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /\A\Z/) + assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => /^$/) + assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => "") + assert doc.find(:tag => "div", :attributes => { :id => "map" }, :content => nil) + end + + def test_parse_invalid_document + assert_nothing_raised do + HTML::Document.new(" + + + + +
About Us
+ ") + end + end + + def test_invalid_document_raises_exception_when_strict + assert_raise RuntimeError do + HTML::Document.new(" + + + + +
About Us
+ ", true) + end + end + +end diff --git a/actionview/test/template/html-scanner/node_test.rb b/actionview/test/template/html-scanner/node_test.rb new file mode 100644 index 0000000000..5b5d092036 --- /dev/null +++ b/actionview/test/template/html-scanner/node_test.rb @@ -0,0 +1,89 @@ +require 'abstract_unit' + +class NodeTest < ActiveSupport::TestCase + + class MockNode + def initialize(matched, value) + @matched = matched + @value = value + end + + def find(conditions) + @matched && self + end + + def to_s + @value.to_s + end + end + + def setup + @node = HTML::Node.new("parent") + @node.children.concat [MockNode.new(false,1), MockNode.new(true,"two"), MockNode.new(false,:three)] + end + + def test_match + assert !@node.match("foo") + end + + def test_tag + assert !@node.tag? + end + + def test_to_s + assert_equal "1twothree", @node.to_s + end + + def test_find + assert_equal "two", @node.find('blah').to_s + end + + def test_parse_strict + s = "" + assert_raise(RuntimeError) { HTML::Node.parse(nil,0,0,s) } + end + + def test_parse_relaxed + s = "" + node = nil + assert_nothing_raised { node = HTML::Node.parse(nil,0,0,s,false) } + assert node.attributes.has_key?("foo") + assert !node.attributes.has_key?("bar") + end + + def test_to_s_with_boolean_attrs + s = "" + node = HTML::Node.parse(nil,0,0,s) + assert node.attributes.has_key?("foo") + assert node.attributes.has_key?("bar") + assert "", node.to_s + end + + def test_parse_with_unclosed_tag + s = "contents', node.content + end + + def test_parse_strict_with_unterminated_cdata_section + s = " hi' + + assert_equal ' hi', sanitizer.sanitize(string) + end + + def test_strip_tags + sanitizer = HTML::FullSanitizer.new + assert_equal("<<")) + assert_equal("Dont touch me", sanitizer.sanitize("Dont touch me")) + assert_equal("This is a test.", sanitizer.sanitize("

This is a test.

")) + assert_equal("Weirdos", sanitizer.sanitize("Wei<a onclick='alert(document.cookie);'/>rdos")) + assert_equal("This is a test.", sanitizer.sanitize("This is a test.")) + assert_equal( + %{This is a test.\n\n\nIt no longer contains any HTML.\n}, sanitizer.sanitize( + %{This is <b>a <a href="" target="_blank">test</a></b>.\n\n\n\n

It no longer contains any HTML.

\n})) + assert_equal "This has a here.", sanitizer.sanitize("This has a here.") + assert_equal "This has a here.", sanitizer.sanitize("This has a ]]> here.") + assert_equal "This has an unclosed ", sanitizer.sanitize("This has an unclosed ]] here...") + [nil, '', ' '].each { |blank| assert_equal blank, sanitizer.sanitize(blank) } + assert_nothing_raised { sanitizer.sanitize("This is a frozen string with no tags".freeze) } + end + + def test_strip_links + sanitizer = HTML::LinkSanitizer.new + assert_equal "Dont touch me", sanitizer.sanitize("Dont touch me") + assert_equal "on my mind\nall day long", sanitizer.sanitize("on my mind\nall day long") + assert_equal "0wn3d", sanitizer.sanitize("0wn3d") + assert_equal "Magic", sanitizer.sanitize("Magic") + assert_equal "FrrFox", sanitizer.sanitize("FrrFox") + assert_equal "My mind\nall day long", sanitizer.sanitize("My mind\nall day long") + assert_equal "all day long", sanitizer.sanitize("<a href='hello'>all day long</a>") + + assert_equal "", '' + end + + def test_sanitize_plaintext + raw = "<span>foo</span></plaintext>" + assert_sanitized raw, "<span>foo</span>" + end + + def test_sanitize_script + assert_sanitized "a b c<script language=\"Javascript\">blah blah blah</script>d e f", "a b cd e f" + end + + def test_sanitize_js_handlers + raw = %{onthis="do that" <a href="#" onclick="hello" name="foo" onbogus="remove me">hello</a>} + assert_sanitized raw, %{onthis="do that" <a name="foo" href="#">hello</a>} + end + + def test_sanitize_javascript_href + raw = %{href="javascript:bang" <a href="javascript:bang" name="hello">foo</a>, <span href="javascript:bang">bar</span>} + assert_sanitized raw, %{href="javascript:bang" <a name="hello">foo</a>, <span>bar</span>} + end + + def test_sanitize_image_src + raw = %{src="javascript:bang" <img src="javascript:bang" width="5">foo</img>, <span src="javascript:bang">bar</span>} + assert_sanitized raw, %{src="javascript:bang" <img width="5">foo</img>, <span>bar</span>} + end + + HTML::WhiteListSanitizer.allowed_tags.each do |tag_name| + define_method "test_should_allow_#{tag_name}_tag" do + assert_sanitized "start <#{tag_name} title=\"1\" onclick=\"foo\">foo <bad>bar</bad> baz</#{tag_name}> end", %(start <#{tag_name} title="1">foo bar baz</#{tag_name}> end) + end + end + + def test_should_allow_anchors + assert_sanitized %(<a href="foo" onclick="bar"><script>baz</script></a>), %(<a href="foo"></a>) + end + + # RFC 3986, sec 4.2 + def test_allow_colons_in_path_component + assert_sanitized("<a href=\"./this:that\">foo</a>") + end + + %w(src width height alt).each do |img_attr| + define_method "test_should_allow_image_#{img_attr}_attribute" do + assert_sanitized %(<img #{img_attr}="foo" onclick="bar" />), %(<img #{img_attr}="foo" />) + end + end + + def test_should_handle_non_html + assert_sanitized 'abc' + end + + def test_should_handle_blank_text + assert_sanitized nil + assert_sanitized '' + end + + def test_should_allow_custom_tags + text = "<u>foo</u>" + sanitizer = HTML::WhiteListSanitizer.new + assert_equal(text, sanitizer.sanitize(text, :tags => %w(u))) + end + + def test_should_allow_only_custom_tags + text = "<u>foo</u> with <i>bar</i>" + sanitizer = HTML::WhiteListSanitizer.new + assert_equal("<u>foo</u> with bar", sanitizer.sanitize(text, :tags => %w(u))) + end + + def test_should_allow_custom_tags_with_attributes + text = %(<blockquote cite="http://example.com/">foo</blockquote>) + sanitizer = HTML::WhiteListSanitizer.new + assert_equal(text, sanitizer.sanitize(text)) + end + + def test_should_allow_custom_tags_with_custom_attributes + text = %(<blockquote foo="bar">Lorem ipsum</blockquote>) + sanitizer = HTML::WhiteListSanitizer.new + assert_equal(text, sanitizer.sanitize(text, :attributes => ['foo'])) + end + + def test_should_raise_argument_error_if_tags_is_not_enumerable + sanitizer = HTML::WhiteListSanitizer.new + e = assert_raise(ArgumentError) do + sanitizer.sanitize('', :tags => 'foo') + end + + assert_equal "You should pass :tags as an Enumerable", e.message + end + + def test_should_raise_argument_error_if_attributes_is_not_enumerable + sanitizer = HTML::WhiteListSanitizer.new + e = assert_raise(ArgumentError) do + sanitizer.sanitize('', :attributes => 'foo') + end + + assert_equal "You should pass :attributes as an Enumerable", e.message + end + + [%w(img src), %w(a href)].each do |(tag, attr)| + define_method "test_should_strip_#{attr}_attribute_in_#{tag}_with_bad_protocols" do + assert_sanitized %(<#{tag} #{attr}="javascript:bang" title="1">boo</#{tag}>), %(<#{tag} title="1">boo</#{tag}>) + end + end + + def test_should_flag_bad_protocols + sanitizer = HTML::WhiteListSanitizer.new + %w(about chrome data disk hcp help javascript livescript lynxcgi lynxexec ms-help ms-its mhtml mocha opera res resource shell vbscript view-source vnd.ms.radio wysiwyg).each do |proto| + assert sanitizer.send(:contains_bad_protocols?, 'src', "#{proto}://bad") + end + end + + def test_should_accept_good_protocols_ignoring_case + sanitizer = HTML::WhiteListSanitizer.new + HTML::WhiteListSanitizer.allowed_protocols.each do |proto| + assert !sanitizer.send(:contains_bad_protocols?, 'src', "#{proto.capitalize}://good") + end + end + + def test_should_accept_good_protocols_ignoring_space + sanitizer = HTML::WhiteListSanitizer.new + HTML::WhiteListSanitizer.allowed_protocols.each do |proto| + assert !sanitizer.send(:contains_bad_protocols?, 'src', " #{proto}://good") + end + end + + def test_should_accept_good_protocols + sanitizer = HTML::WhiteListSanitizer.new + HTML::WhiteListSanitizer.allowed_protocols.each do |proto| + assert !sanitizer.send(:contains_bad_protocols?, 'src', "#{proto}://good") + end + end + + def test_should_reject_hex_codes_in_protocol + assert_sanitized %(<a href="&#37;6A&#37;61&#37;76&#37;61&#37;73&#37;63&#37;72&#37;69&#37;70&#37;74&#37;3A&#37;61&#37;6C&#37;65&#37;72&#37;74&#37;28&#37;22&#37;58&#37;53&#37;53&#37;22&#37;29">1</a>), "<a>1</a>" + assert @sanitizer.send(:contains_bad_protocols?, 'src', "%6A%61%76%61%73%63%72%69%70%74%3A%61%6C%65%72%74%28%22%58%53%53%22%29") + end + + def test_should_block_script_tag + assert_sanitized %(<SCRIPT\nSRC=http://ha.ckers.org/xss.js></SCRIPT>), "" + end + + [%(<IMG SRC="javascript:alert('XSS');">), + %(<IMG SRC=javascript:alert('XSS')>), + %(<IMG SRC=JaVaScRiPt:alert('XSS')>), + %(<IMG """><SCRIPT>alert("XSS")</SCRIPT>">), + %(<IMG SRC=javascript:alert(&quot;XSS&quot;)>), + %(<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>), + %(<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>), + %(<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>), + %(<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>), + %(<IMG SRC="jav\tascript:alert('XSS');">), + %(<IMG SRC="jav&#x09;ascript:alert('XSS');">), + %(<IMG SRC="jav&#x0A;ascript:alert('XSS');">), + %(<IMG SRC="jav&#x0D;ascript:alert('XSS');">), + %(<IMG SRC=" &#14; javascript:alert('XSS');">), + %(<IMG SRC="javascript&#x3a;alert('XSS');">), + %(<IMG SRC=`javascript:alert("RSnake says, 'XSS'")`>)].each_with_index do |img_hack, i| + define_method "test_should_not_fall_for_xss_image_hack_#{i+1}" do + assert_sanitized img_hack, "<img>" + end + end + + def test_should_sanitize_tag_broken_up_by_null + assert_sanitized %(<SCR\0IPT>alert(\"XSS\")</SCR\0IPT>), "alert(\"XSS\")" + end + + def test_should_sanitize_invalid_script_tag + assert_sanitized %(<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>), "" + end + + def test_should_sanitize_script_tag_with_multiple_open_brackets + assert_sanitized %(<<SCRIPT>alert("XSS");//<</SCRIPT>), "&lt;" + assert_sanitized %(<iframe src=http://ha.ckers.org/scriptlet.html\n<a), %(&lt;a) + end + + def test_should_sanitize_unclosed_script + assert_sanitized %(<SCRIPT SRC=http://ha.ckers.org/xss.js?<B>), "<b>" + end + + def test_should_sanitize_half_open_scripts + assert_sanitized %(<IMG SRC="javascript:alert('XSS')"), "<img>" + end + + def test_should_not_fall_for_ridiculous_hack + img_hack = %(<IMG\nSRC\n=\n"\nj\na\nv\na\ns\nc\nr\ni\np\nt\n:\na\nl\ne\nr\nt\n(\n'\nX\nS\nS\n'\n)\n"\n>) + assert_sanitized img_hack, "<img>" + end + + def test_should_sanitize_attributes + assert_sanitized %(<SPAN title="'><script>alert()</script>">blah</SPAN>), %(<span title="#{CGI.escapeHTML "'><script>alert()</script>"}">blah</span>) + end + + def test_should_sanitize_illegal_style_properties + raw = %(display:block; position:absolute; left:0; top:0; width:100%; height:100%; z-index:1; background-color:black; background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg); background-x:center; background-y:center; background-repeat:repeat;) + expected = %(display: block; width: 100%; height: 100%; background-color: black; background-image: ; background-x: center; background-y: center;) + assert_equal expected, sanitize_css(raw) + end + + def test_should_sanitize_with_trailing_space + raw = "display:block; " + expected = "display: block;" + assert_equal expected, sanitize_css(raw) + end + + def test_should_sanitize_xul_style_attributes + raw = %(-moz-binding:url('http://ha.ckers.org/xssmoz.xml#xss')) + assert_equal '', sanitize_css(raw) + end + + def test_should_sanitize_invalid_tag_names + assert_sanitized(%(a b c<script/XSS src="http://ha.ckers.org/xss.js"></script>d e f), "a b cd e f") + end + + def test_should_sanitize_non_alpha_and_non_digit_characters_in_tags + assert_sanitized('<a onclick!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>foo</a>', "<a>foo</a>") + end + + def test_should_sanitize_invalid_tag_names_in_single_tags + assert_sanitized('<img/src="http://ha.ckers.org/xss.js"/>', "<img />") + end + + def test_should_sanitize_img_dynsrc_lowsrc + assert_sanitized(%(<img lowsrc="javascript:alert('XSS')" />), "<img />") + end + + def test_should_sanitize_div_background_image_unicode_encoded + raw = %(background-image:\0075\0072\006C\0028'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029'\0029) + assert_equal '', sanitize_css(raw) + end + + def test_should_sanitize_div_style_expression + raw = %(width: expression(alert('XSS'));) + assert_equal '', sanitize_css(raw) + end + + def test_should_sanitize_across_newlines + raw = %(\nwidth:\nexpression(alert('XSS'));\n) + assert_equal '', sanitize_css(raw) + end + + def test_should_sanitize_img_vbscript + assert_sanitized %(<img src='vbscript:msgbox("XSS")' />), '<img />' + end + + def test_should_sanitize_cdata_section + assert_sanitized "<![CDATA[<span>section</span>]]>", "&lt;![CDATA[&lt;span>section&lt;/span>]]>" + end + + def test_should_sanitize_unterminated_cdata_section + assert_sanitized "<![CDATA[<span>neverending...", "&lt;![CDATA[&lt;span>neverending...]]>" + end + + def test_should_not_mangle_urls_with_ampersand + assert_sanitized %{<a href=\"http://www.domain.com?var1=1&amp;var2=2\">my link</a>} + end + + def test_should_sanitize_neverending_attribute + assert_sanitized "<span class=\"\\", "<span class=\"\\\">" + end + + def test_x03a + assert_sanitized %(<a href="javascript&#x3a;alert('XSS');">), "<a>" + assert_sanitized %(<a href="javascript&#x003a;alert('XSS');">), "<a>" + assert_sanitized %(<a href="http&#x3a;//legit">), %(<a href="http://legit">) + assert_sanitized %(<a href="javascript&#x3A;alert('XSS');">), "<a>" + assert_sanitized %(<a href="javascript&#x003A;alert('XSS');">), "<a>" + assert_sanitized %(<a href="http&#x3A;//legit">), %(<a href="http://legit">) + end + +protected + def assert_sanitized(input, expected = nil) + @sanitizer ||= HTML::WhiteListSanitizer.new + if input + assert_dom_equal expected || input, @sanitizer.sanitize(input) + else + assert_nil @sanitizer.sanitize(input) + end + end + + def sanitize_css(input) + (@sanitizer ||= HTML::WhiteListSanitizer.new).sanitize_css(input) + end +end diff --git a/actionview/test/template/html-scanner/tag_node_test.rb b/actionview/test/template/html-scanner/tag_node_test.rb new file mode 100644 index 0000000000..a29d2d43d7 --- /dev/null +++ b/actionview/test/template/html-scanner/tag_node_test.rb @@ -0,0 +1,243 @@ +require 'abstract_unit' + +class TagNodeTest < ActiveSupport::TestCase + def test_open_without_attributes + node = tag("<tag>") + assert_equal "tag", node.name + assert_equal Hash.new, node.attributes + assert_nil node.closing + end + + def test_open_with_attributes + node = tag("<TAG1 foo=hey_ho x:bar=\"blah blah\" BAZ='blah blah blah' >") + assert_equal "tag1", node.name + assert_equal "hey_ho", node["foo"] + assert_equal "blah blah", node["x:bar"] + assert_equal "blah blah blah", node["baz"] + end + + def test_self_closing_without_attributes + node = tag("<tag/>") + assert_equal "tag", node.name + assert_equal Hash.new, node.attributes + assert_equal :self, node.closing + end + + def test_self_closing_with_attributes + node = tag("<tag a=b/>") + assert_equal "tag", node.name + assert_equal( { "a" => "b" }, node.attributes ) + assert_equal :self, node.closing + end + + def test_closing_without_attributes + node = tag("</tag>") + assert_equal "tag", node.name + assert_nil node.attributes + assert_equal :close, node.closing + end + + def test_bracket_op_when_no_attributes + node = tag("</tag>") + assert_nil node["foo"] + end + + def test_bracket_op_when_attributes + node = tag("<tag a=b/>") + assert_equal "b", node["a"] + end + + def test_attributes_with_escaped_quotes + node = tag("<tag a='b\\'c' b=\"bob \\\"float\\\"\">") + assert_equal "b\\'c", node["a"] + assert_equal "bob \\\"float\\\"", node["b"] + end + + def test_to_s + node = tag("<a b=c d='f' g=\"h 'i'\" />") + node = node.to_s + assert node.include?('a') + assert node.include?('b="c"') + assert node.include?('d="f"') + assert node.include?('g="h') + assert node.include?('i') + end + + def test_tag + assert tag("<tag>").tag? + end + + def test_match_tag_as_string + assert tag("<tag>").match(:tag => "tag") + assert !tag("<tag>").match(:tag => "b") + end + + def test_match_tag_as_regexp + assert tag("<tag>").match(:tag => /t.g/) + assert !tag("<tag>").match(:tag => /t[bqs]g/) + end + + def test_match_attributes_as_string + t = tag("<tag a=something b=else />") + assert t.match(:attributes => {"a" => "something"}) + assert t.match(:attributes => {"b" => "else"}) + end + + def test_match_attributes_as_regexp + t = tag("<tag a=something b=else />") + assert t.match(:attributes => {"a" => /^something$/}) + assert t.match(:attributes => {"b" => /e.*e/}) + assert t.match(:attributes => {"a" => /me..i/, "b" => /.ls.$/}) + end + + def test_match_attributes_as_number + t = tag("<tag a=15 b=3.1415 />") + assert t.match(:attributes => {"a" => 15}) + assert t.match(:attributes => {"b" => 3.1415}) + assert t.match(:attributes => {"a" => 15, "b" => 3.1415}) + end + + def test_match_attributes_exist + t = tag("<tag a=15 b=3.1415 />") + assert t.match(:attributes => {"a" => true}) + assert t.match(:attributes => {"b" => true}) + assert t.match(:attributes => {"a" => true, "b" => true}) + end + + def test_match_attributes_not_exist + t = tag("<tag a=15 b=3.1415 />") + assert t.match(:attributes => {"c" => false}) + assert t.match(:attributes => {"c" => nil}) + assert t.match(:attributes => {"a" => true, "c" => false}) + end + + def test_match_parent_success + t = tag("<tag a=15 b='hello'>", tag("<foo k='value'>")) + assert t.match(:parent => {:tag => "foo", :attributes => {"k" => /v.l/, "j" => false}}) + end + + def test_match_parent_fail + t = tag("<tag a=15 b='hello'>", tag("<foo k='value'>")) + assert !t.match(:parent => {:tag => /kafka/}) + end + + def test_match_child_success + t = tag("<tag x:k='something'>") + tag("<child v=john a=kelly>", t) + tag("<sib m=vaughn v=james>", t) + assert t.match(:child => { :tag => "sib", :attributes => {"v" => /j/}}) + assert t.match(:child => { :attributes => {"a" => "kelly"}}) + end + + def test_match_child_fail + t = tag("<tag x:k='something'>") + tag("<child v=john a=kelly>", t) + tag("<sib m=vaughn v=james>", t) + assert !t.match(:child => { :tag => "sib", :attributes => {"v" => /r/}}) + assert !t.match(:child => { :attributes => {"v" => false}}) + end + + def test_match_ancestor_success + t = tag("<tag x:k='something'>", tag("<parent v=john a=kelly>", tag("<grandparent m=vaughn v=james>"))) + assert t.match(:ancestor => {:tag => "parent", :attributes => {"a" => /ll/}}) + assert t.match(:ancestor => {:attributes => {"m" => "vaughn"}}) + end + + def test_match_ancestor_fail + t = tag("<tag x:k='something'>", tag("<parent v=john a=kelly>", tag("<grandparent m=vaughn v=james>"))) + assert !t.match(:ancestor => {:tag => /^parent/, :attributes => {"v" => /m/}}) + assert !t.match(:ancestor => {:attributes => {"v" => false}}) + end + + def test_match_descendant_success + tag("<grandchild m=vaughn v=james>", tag("<child v=john a=kelly>", t = tag("<tag x:k='something'>"))) + assert t.match(:descendant => {:tag => "child", :attributes => {"a" => /ll/}}) + assert t.match(:descendant => {:attributes => {"m" => "vaughn"}}) + end + + def test_match_descendant_fail + tag("<grandchild m=vaughn v=james>", tag("<child v=john a=kelly>", t = tag("<tag x:k='something'>"))) + assert !t.match(:descendant => {:tag => /^child/, :attributes => {"v" => /m/}}) + assert !t.match(:descendant => {:attributes => {"v" => false}}) + end + + def test_match_child_count + t = tag("<tag x:k='something'>") + tag("hello", t) + tag("<child v=john a=kelly>", t) + tag("<sib m=vaughn v=james>", t) + assert t.match(:children => { :count => 2 }) + assert t.match(:children => { :count => 2..4 }) + assert t.match(:children => { :less_than => 4 }) + assert t.match(:children => { :greater_than => 1 }) + assert !t.match(:children => { :count => 3 }) + end + + def test_conditions_as_strings + t = tag("<tag x:k='something'>") + assert t.match("tag" => "tag") + assert t.match("attributes" => { "x:k" => "something" }) + assert !t.match("tag" => "gat") + assert !t.match("attributes" => { "x:j" => "something" }) + end + + def test_attributes_as_symbols + t = tag("<child v=john a=kelly>") + assert t.match(:attributes => { :v => /oh/ }) + assert t.match(:attributes => { :a => /ll/ }) + end + + def test_match_sibling + t = tag("<tag x:k='something'>") + tag("hello", t) + tag("<span a=b>", t) + tag("world", t) + m = tag("<span k=r>", t) + tag("<span m=l>", t) + + assert m.match(:sibling => {:tag => "span", :attributes => {:a => true}}) + assert m.match(:sibling => {:tag => "span", :attributes => {:m => true}}) + assert !m.match(:sibling => {:tag => "span", :attributes => {:k => true}}) + end + + def test_match_sibling_before + t = tag("<tag x:k='something'>") + tag("hello", t) + tag("<span a=b>", t) + tag("world", t) + m = tag("<span k=r>", t) + tag("<span m=l>", t) + + assert m.match(:before => {:tag => "span", :attributes => {:m => true}}) + assert !m.match(:before => {:tag => "span", :attributes => {:a => true}}) + assert !m.match(:before => {:tag => "span", :attributes => {:k => true}}) + end + + def test_match_sibling_after + t = tag("<tag x:k='something'>") + tag("hello", t) + tag("<span a=b>", t) + tag("world", t) + m = tag("<span k=r>", t) + tag("<span m=l>", t) + + assert m.match(:after => {:tag => "span", :attributes => {:a => true}}) + assert !m.match(:after => {:tag => "span", :attributes => {:m => true}}) + assert !m.match(:after => {:tag => "span", :attributes => {:k => true}}) + end + + def test_tag_to_s + t = tag("<b x='foo'>") + tag("hello", t) + tag("<hr />", t) + assert_equal %(<b x="foo">hello<hr /></b>), t.to_s + end + + private + + def tag(content, parent=nil) + node = HTML::Node.parse(parent,0,0,content) + parent.children << node if parent + node + end +end diff --git a/actionview/test/template/html-scanner/text_node_test.rb b/actionview/test/template/html-scanner/text_node_test.rb new file mode 100644 index 0000000000..cbcb9e78f0 --- /dev/null +++ b/actionview/test/template/html-scanner/text_node_test.rb @@ -0,0 +1,50 @@ +require 'abstract_unit' + +class TextNodeTest < ActiveSupport::TestCase + def setup + @node = HTML::Text.new(nil, 0, 0, "hello, howdy, aloha, annyeong") + end + + def test_to_s + assert_equal "hello, howdy, aloha, annyeong", @node.to_s + end + + def test_find_string + assert_equal @node, @node.find("hello, howdy, aloha, annyeong") + assert_equal false, @node.find("bogus") + end + + def test_find_regexp + assert_equal @node, @node.find(/an+y/) + assert_nil @node.find(/b/) + end + + def test_find_hash + assert_equal @node, @node.find(:content => /howdy/) + assert_nil @node.find(:content => /^howdy$/) + assert_equal false, @node.find(:content => "howdy") + end + + def test_find_other + assert_nil @node.find(:hello) + end + + def test_match_string + assert @node.match("hello, howdy, aloha, annyeong") + assert_equal false, @node.match("bogus") + end + + def test_match_regexp + assert_not_nil @node, @node.match(/an+y/) + assert_nil @node.match(/b/) + end + + def test_match_hash + assert_not_nil @node, @node.match(:content => "howdy") + assert_nil @node.match(:content => /^howdy$/) + end + + def test_match_other + assert_nil @node.match(:hello) + end +end diff --git a/actionview/test/template/html-scanner/tokenizer_test.rb b/actionview/test/template/html-scanner/tokenizer_test.rb new file mode 100644 index 0000000000..1d59de23b6 --- /dev/null +++ b/actionview/test/template/html-scanner/tokenizer_test.rb @@ -0,0 +1,131 @@ +require 'abstract_unit' + +class TokenizerTest < ActiveSupport::TestCase + + def test_blank + tokenize "" + assert_end + end + + def test_space + tokenize " " + assert_next " " + assert_end + end + + def test_tag_simple_open + tokenize "<tag>" + assert_next "<tag>" + assert_end + end + + def test_tag_simple_self_closing + tokenize "<tag />" + assert_next "<tag />" + assert_end + end + + def test_tag_simple_closing + tokenize "</tag>" + assert_next "</tag>" + end + + def test_tag_with_single_quoted_attribute + tokenize %{<tag a='hello'>x} + assert_next %{<tag a='hello'>} + end + + def test_tag_with_single_quoted_attribute_with_escape + tokenize %{<tag a='hello\\''>x} + assert_next %{<tag a='hello\\''>} + end + + def test_tag_with_double_quoted_attribute + tokenize %{<tag a="hello">x} + assert_next %{<tag a="hello">} + end + + def test_tag_with_double_quoted_attribute_with_escape + tokenize %{<tag a="hello\\"">x} + assert_next %{<tag a="hello\\"">} + end + + def test_tag_with_unquoted_attribute + tokenize %{<tag a=hello>x} + assert_next %{<tag a=hello>} + end + + def test_tag_with_lt_char_in_attribute + tokenize %{<tag a="x < y">x} + assert_next %{<tag a="x < y">} + end + + def test_tag_with_gt_char_in_attribute + tokenize %{<tag a="x > y">x} + assert_next %{<tag a="x > y">} + end + + def test_doctype_tag + tokenize %{<!DOCTYPE "blah" "blah" "blah">\n <html>} + assert_next %{<!DOCTYPE "blah" "blah" "blah">} + assert_next %{\n } + assert_next %{<html>} + end + + def test_cdata_tag + tokenize %{<![CDATA[<br>]]>} + assert_next %{<![CDATA[<br>]]>} + assert_end + end + + def test_unterminated_cdata_tag + tokenize %{<content:encoded><![CDATA[ neverending...} + assert_next %{<content:encoded>} + assert_next %{<![CDATA[ neverending...} + assert_end + end + + def test_less_than_with_space + tokenize %{original < hello > world} + assert_next %{original } + assert_next %{< hello > world} + end + + def test_less_than_without_matching_greater_than + tokenize %{hello <span onmouseover="gotcha"\n<b>foo</b>\nbar</span>} + assert_next %{hello } + assert_next %{<span onmouseover="gotcha"\n} + assert_next %{<b>} + assert_next %{foo} + assert_next %{</b>} + assert_next %{\nbar} + assert_next %{</span>} + assert_end + end + + def test_unterminated_comment + tokenize %{hello <!-- neverending...} + assert_next %{hello } + assert_next %{<!-- neverending...} + assert_end + end + + private + + def tokenize(text) + @tokenizer = HTML::Tokenizer.new(text) + end + + def assert_next(expected, message=nil) + token = @tokenizer.next + assert_equal expected, token, message + end + + def assert_sequence(*expected) + assert_next expected.shift until expected.empty? + end + + def assert_end(message=nil) + assert_nil @tokenizer.next, message + end +end diff --git a/actionview/test/template/javascript_helper_test.rb b/actionview/test/template/javascript_helper_test.rb new file mode 100644 index 0000000000..de6a6eaab3 --- /dev/null +++ b/actionview/test/template/javascript_helper_test.rb @@ -0,0 +1,62 @@ +require 'abstract_unit' + +class JavaScriptHelperTest < ActionView::TestCase + tests ActionView::Helpers::JavaScriptHelper + + def _evaluate_assigns_and_ivars() end + + attr_accessor :formats, :output_buffer + + def update_details(details) + @details = details + yield if block_given? + end + + def setup + super + ActiveSupport.escape_html_entities_in_json = true + @template = self + end + + def teardown + ActiveSupport.escape_html_entities_in_json = false + end + + def test_escape_javascript + assert_equal '', escape_javascript(nil) + assert_equal %(This \\"thing\\" is really\\n netos\\'), escape_javascript(%(This "thing" is really\n netos')) + assert_equal %(backslash\\\\test), escape_javascript( %(backslash\\test) ) + assert_equal %(dont <\\/close> tags), escape_javascript(%(dont </close> tags)) + assert_equal %(unicode &#x2028; newline), escape_javascript(%(unicode \342\200\250 newline).force_encoding(Encoding::UTF_8).encode!) + assert_equal %(unicode &#x2029; newline), escape_javascript(%(unicode \342\200\251 newline).force_encoding(Encoding::UTF_8).encode!) + + assert_equal %(dont <\\/close> tags), j(%(dont </close> tags)) + end + + def test_escape_javascript_with_safebuffer + given = %('quoted' "double-quoted" new-line:\n </closed>) + expect = %(\\'quoted\\' \\"double-quoted\\" new-line:\\n <\\/closed>) + assert_equal expect, escape_javascript(given) + assert_equal expect, escape_javascript(ActiveSupport::SafeBuffer.new(given)) + assert_instance_of String, escape_javascript(given) + assert_instance_of ActiveSupport::SafeBuffer, escape_javascript(ActiveSupport::SafeBuffer.new(given)) + end + + def test_javascript_tag + self.output_buffer = 'foo' + + assert_dom_equal "<script>\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", + javascript_tag("alert('hello')") + + assert_equal 'foo', output_buffer, 'javascript_tag without a block should not concat to output_buffer' + end + + def test_javascript_tag_with_options + assert_dom_equal "<script id=\"the_js_tag\">\n//<![CDATA[\nalert('hello')\n//]]>\n</script>", + javascript_tag("alert('hello')", :id => "the_js_tag") + end + + def test_javascript_cdata_section + assert_dom_equal "\n//<![CDATA[\nalert('hello')\n//]]>\n", javascript_cdata_section("alert('hello')") + end +end diff --git a/actionview/test/template/log_subscriber_test.rb b/actionview/test/template/log_subscriber_test.rb new file mode 100644 index 0000000000..7f4c84929f --- /dev/null +++ b/actionview/test/template/log_subscriber_test.rb @@ -0,0 +1,91 @@ +require "abstract_unit" +require "active_support/log_subscriber/test_helper" +require "action_view/log_subscriber" +require "controller/fake_models" + +class AVLogSubscriberTest < ActiveSupport::TestCase + include ActiveSupport::LogSubscriber::TestHelper + + def setup + super + view_paths = ActionController::Base.view_paths + lookup_context = ActionView::LookupContext.new(view_paths, {}, ["test"]) + renderer = ActionView::Renderer.new(lookup_context) + @view = ActionView::Base.new(renderer, {}) + Rails.stubs(:root).returns(File.expand_path(FIXTURE_LOAD_PATH)) + ActionView::LogSubscriber.attach_to :action_view + end + + def teardown + super + ActiveSupport::LogSubscriber.log_subscribers.clear + end + + def set_logger(logger) + ActionView::Base.logger = logger + end + + def test_render_file_template + @view.render(:file => "test/hello_world") + wait + + assert_equal 1, @logger.logged(:info).size + assert_match(/Rendered test\/hello_world\.erb/, @logger.logged(:info).last) + end + + def test_render_text_template + @view.render(:text => "TEXT") + wait + + assert_equal 1, @logger.logged(:info).size + assert_match(/Rendered text template/, @logger.logged(:info).last) + end + + def test_render_inline_template + @view.render(:inline => "<%= 'TEXT' %>") + wait + + assert_equal 1, @logger.logged(:info).size + assert_match(/Rendered inline template/, @logger.logged(:info).last) + end + + def test_render_partial_template + @view.render(:partial => "test/customer") + wait + + assert_equal 1, @logger.logged(:info).size + assert_match(/Rendered test\/_customer.erb/, @logger.logged(:info).last) + end + + def test_render_partial_with_implicit_path + @view.render(Customer.new("david"), :greeting => "hi") + wait + + assert_equal 1, @logger.logged(:info).size + assert_match(/Rendered customers\/_customer\.html\.erb/, @logger.logged(:info).last) + end + + def test_render_collection_template + @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ]) + wait + + assert_equal 1, @logger.logged(:info).size + assert_match(/Rendered test\/_customer.erb/, @logger.logged(:info).last) + end + + def test_render_collection_with_implicit_path + @view.render([ Customer.new("david"), Customer.new("mary") ], :greeting => "hi") + wait + + assert_equal 1, @logger.logged(:info).size + assert_match(/Rendered customers\/_customer\.html\.erb/, @logger.logged(:info).last) + end + + def test_render_collection_template_without_path + @view.render([ GoodCustomer.new("david"), Customer.new("mary") ], :greeting => "hi") + wait + + assert_equal 1, @logger.logged(:info).size + assert_match(/Rendered collection/, @logger.logged(:info).last) + end +end diff --git a/actionview/test/template/lookup_context_test.rb b/actionview/test/template/lookup_context_test.rb new file mode 100644 index 0000000000..073bd14783 --- /dev/null +++ b/actionview/test/template/lookup_context_test.rb @@ -0,0 +1,263 @@ +require "abstract_unit" +require "abstract_controller/rendering" + +class LookupContextTest < ActiveSupport::TestCase + def setup + @lookup_context = ActionView::LookupContext.new(FIXTURE_LOAD_PATH, {}) + ActionView::LookupContext::DetailsKey.clear + end + + def teardown + I18n.locale = :en + end + + test "allows to override default_formats with ActionView::Base.default_formats" do + begin + formats = ActionView::Base.default_formats + ActionView::Base.default_formats = [:foo, :bar] + + assert_equal [:foo, :bar], ActionView::LookupContext.new([]).default_formats + ensure + ActionView::Base.default_formats = formats + end + end + + test "process view paths on initialization" do + assert_kind_of ActionView::PathSet, @lookup_context.view_paths + end + + test "normalizes details on initialization" do + assert_equal Mime::SET, @lookup_context.formats + assert_equal :en, @lookup_context.locale + end + + test "allows me to freeze and retrieve frozen formats" do + @lookup_context.formats.freeze + assert @lookup_context.formats.frozen? + end + + test "provides getters and setters for formats" do + @lookup_context.formats = [:html] + assert_equal [:html], @lookup_context.formats + end + + test "handles */* formats" do + @lookup_context.formats = ["*/*"] + assert_equal Mime::SET, @lookup_context.formats + end + + test "handles explicitly defined */* formats fallback to :js" do + @lookup_context.formats = [:js, Mime::ALL] + assert_equal [:js, *Mime::SET.symbols], @lookup_context.formats + end + + test "adds :html fallback to :js formats" do + @lookup_context.formats = [:js] + assert_equal [:js, :html], @lookup_context.formats + end + + test "provides getters and setters for locale" do + @lookup_context.locale = :pt + assert_equal :pt, @lookup_context.locale + end + + test "changing lookup_context locale, changes I18n.locale" do + @lookup_context.locale = :pt + assert_equal :pt, I18n.locale + end + + test "delegates changing the locale to the I18n configuration object if it contains a lookup_context object" do + begin + I18n.config = AbstractController::I18nProxy.new(I18n.config, @lookup_context) + @lookup_context.locale = :pt + assert_equal :pt, I18n.locale + assert_equal :pt, @lookup_context.locale + ensure + I18n.config = I18n.config.original_config + end + + assert_equal :pt, I18n.locale + end + + test "find templates using the given view paths and configured details" do + template = @lookup_context.find("hello_world", %w(test)) + assert_equal "Hello world!", template.source + + @lookup_context.locale = :da + template = @lookup_context.find("hello_world", %w(test)) + assert_equal "Hey verden", template.source + end + + test "found templates respects given formats if one cannot be found from template or handler" do + ActionView::Template::Handlers::Builder.expects(:default_format).returns(nil) + @lookup_context.formats = [:text] + template = @lookup_context.find("hello", %w(test)) + assert_equal [:text], template.formats + end + + test "adds fallbacks to view paths when required" do + assert_equal 1, @lookup_context.view_paths.size + + @lookup_context.with_fallbacks do + assert_equal 3, @lookup_context.view_paths.size + assert @lookup_context.view_paths.include?(ActionView::FallbackFileSystemResolver.new("")) + assert @lookup_context.view_paths.include?(ActionView::FallbackFileSystemResolver.new("/")) + end + end + + test "add fallbacks just once in nested fallbacks calls" do + @lookup_context.with_fallbacks do + @lookup_context.with_fallbacks do + assert_equal 3, @lookup_context.view_paths.size + end + end + end + + test "generates a new details key for each details hash" do + keys = [] + keys << @lookup_context.details_key + assert_equal 1, keys.uniq.size + + @lookup_context.locale = :da + keys << @lookup_context.details_key + assert_equal 2, keys.uniq.size + + @lookup_context.locale = :en + keys << @lookup_context.details_key + assert_equal 2, keys.uniq.size + + @lookup_context.formats = [:html] + keys << @lookup_context.details_key + assert_equal 3, keys.uniq.size + + @lookup_context.formats = nil + keys << @lookup_context.details_key + assert_equal 3, keys.uniq.size + end + + test "gives the key forward to the resolver, so it can be used as cache key" do + @lookup_context.view_paths = ActionView::FixtureResolver.new("test/_foo.erb" => "Foo") + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Foo", template.source + + # Now we are going to change the template, but it won't change the returned template + # since we will hit the cache. + @lookup_context.view_paths.first.hash["test/_foo.erb"] = "Bar" + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Foo", template.source + + # This time we will change the locale. The updated template should be picked since + # lookup_context generated a new key after we changed the locale. + @lookup_context.locale = :da + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Bar", template.source + + # Now we will change back the locale and it will still pick the old template. + # This is expected because lookup_context will reuse the previous key for :en locale. + @lookup_context.locale = :en + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Foo", template.source + + # Finally, we can expire the cache. And the expected template will be used. + @lookup_context.view_paths.first.clear_cache + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Bar", template.source + end + + test "can disable the cache on demand" do + @lookup_context.view_paths = ActionView::FixtureResolver.new("test/_foo.erb" => "Foo") + old_template = @lookup_context.find("foo", %w(test), true) + + template = @lookup_context.find("foo", %w(test), true) + assert_equal template, old_template + + assert @lookup_context.cache + template = @lookup_context.disable_cache do + assert !@lookup_context.cache + @lookup_context.find("foo", %w(test), true) + end + assert @lookup_context.cache + + assert_not_equal template, old_template + end + + test "responds to #prefixes" do + assert_equal [], @lookup_context.prefixes + @lookup_context.prefixes = ["foo"] + assert_equal ["foo"], @lookup_context.prefixes + end +end + +class LookupContextWithFalseCaching < ActiveSupport::TestCase + def setup + @resolver = ActionView::FixtureResolver.new("test/_foo.erb" => ["Foo", Time.utc(2000)]) + ActionView::Resolver.stubs(:caching?).returns(false) + @lookup_context = ActionView::LookupContext.new(@resolver, {}) + end + + test "templates are always found in the resolver but timestamp is checked before being compiled" do + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Foo", template.source + + # Now we are going to change the template, but it won't change the returned template + # since the timestamp is the same. + @resolver.hash["test/_foo.erb"][0] = "Bar" + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Foo", template.source + + # Now update the timestamp. + @resolver.hash["test/_foo.erb"][1] = Time.now.utc + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Bar", template.source + end + + test "if no template was found in the second lookup, with no cache, raise error" do + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Foo", template.source + + @resolver.hash.clear + assert_raise ActionView::MissingTemplate do + @lookup_context.find("foo", %w(test), true) + end + end + + test "if no template was cached in the first lookup, retrieval should work in the second call" do + @resolver.hash.clear + assert_raise ActionView::MissingTemplate do + @lookup_context.find("foo", %w(test), true) + end + + @resolver.hash["test/_foo.erb"] = ["Foo", Time.utc(2000)] + template = @lookup_context.find("foo", %w(test), true) + assert_equal "Foo", template.source + end +end + +class TestMissingTemplate < ActiveSupport::TestCase + def setup + @lookup_context = ActionView::LookupContext.new("/Path/to/views", {}) + end + + test "if no template was found we get a helpful error message including the inheritance chain" do + e = assert_raise ActionView::MissingTemplate do + @lookup_context.find("foo", %w(parent child)) + end + assert_match %r{Missing template parent/foo, child/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message + end + + test "if no partial was found we get a helpful error message including the inheritance chain" do + e = assert_raise ActionView::MissingTemplate do + @lookup_context.find("foo", %w(parent child), true) + end + assert_match %r{Missing partial parent/foo, child/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message + end + + test "if a single prefix is passed as a string and the lookup fails, MissingTemplate accepts it" do + e = assert_raise ActionView::MissingTemplate do + details = {:handlers=>[], :formats=>[], :locale=>[]} + @lookup_context.view_paths.find("foo", "parent", true, details) + end + assert_match %r{Missing partial parent/foo with .* Searched in:\n \* "/Path/to/views"\n}, e.message + end + +end diff --git a/actionview/test/template/number_helper_test.rb b/actionview/test/template/number_helper_test.rb new file mode 100644 index 0000000000..6e640889d2 --- /dev/null +++ b/actionview/test/template/number_helper_test.rb @@ -0,0 +1,151 @@ +require "abstract_unit" + +class NumberHelperTest < ActionView::TestCase + tests ActionView::Helpers::NumberHelper + + def test_number_to_phone + assert_equal nil, number_to_phone(nil) + assert_equal "555-1234", number_to_phone(5551234) + assert_equal "(800) 555-1212 x 123", number_to_phone(8005551212, area_code: true, extension: 123) + assert_equal "+18005551212", number_to_phone(8005551212, country_code: 1, delimiter: "") + end + + def test_number_to_currency + assert_equal nil, number_to_currency(nil) + assert_equal "$1,234,567,890.50", number_to_currency(1234567890.50) + assert_equal "$1,234,567,892", number_to_currency(1234567891.50, precision: 0) + assert_equal "1,234,567,890.50 - K&#269;", number_to_currency("-1234567890.50", unit: "K&#269;", format: "%n %u", negative_format: "%n - %u") + end + + def test_number_to_percentage + assert_equal nil, number_to_percentage(nil) + assert_equal "100.000%", number_to_percentage(100) + assert_equal "100%", number_to_percentage(100, precision: 0) + assert_equal "123.4%", number_to_percentage(123.400, precision: 3, strip_insignificant_zeros: true) + assert_equal "1.000,000%", number_to_percentage(1000, delimiter: ".", separator: ",") + end + + def test_number_with_delimiter + assert_equal nil, number_with_delimiter(nil) + assert_equal "12,345,678", number_with_delimiter(12345678) + assert_equal "0", number_with_delimiter(0) + end + + def test_number_with_precision + assert_equal nil, number_with_precision(nil) + assert_equal "-111.235", number_with_precision(-111.2346) + assert_equal "111.00", number_with_precision(111, precision: 2) + assert_equal "0.00100", number_with_precision(0.001, precision: 5) + end + + def test_number_to_human_size + assert_equal nil, number_to_human_size(nil) + assert_equal "3 Bytes", number_to_human_size(3.14159265) + assert_equal "1.2 MB", number_to_human_size(1234567, precision: 2) + end + + def test_number_to_human + assert_equal nil, number_to_human(nil) + assert_equal "0", number_to_human(0) + assert_equal "1.23 Thousand", number_to_human(1234) + assert_equal "489.0 Thousand", number_to_human(489000, precision: 4, strip_insignificant_zeros: false) + end + + def test_number_helpers_escape_delimiter_and_separator + assert_equal "111&lt;script&gt;&lt;/script&gt;111&lt;script&gt;&lt;/script&gt;1111", number_to_phone(1111111111, delimiter: "<script></script>") + + assert_equal "$1&lt;script&gt;&lt;/script&gt;01", number_to_currency(1.01, separator: "<script></script>") + assert_equal "$1&lt;script&gt;&lt;/script&gt;000.00", number_to_currency(1000, delimiter: "<script></script>") + + assert_equal "1&lt;script&gt;&lt;/script&gt;010%", number_to_percentage(1.01, separator: "<script></script>") + assert_equal "1&lt;script&gt;&lt;/script&gt;000.000%", number_to_percentage(1000, delimiter: "<script></script>") + + assert_equal "1&lt;script&gt;&lt;/script&gt;01", number_with_delimiter(1.01, separator: "<script></script>") + assert_equal "1&lt;script&gt;&lt;/script&gt;000", number_with_delimiter(1000, delimiter: "<script></script>") + + assert_equal "1&lt;script&gt;&lt;/script&gt;010", number_with_precision(1.01, separator: "<script></script>") + assert_equal "1&lt;script&gt;&lt;/script&gt;000.000", number_with_precision(1000, delimiter: "<script></script>") + + assert_equal "9&lt;script&gt;&lt;/script&gt;86 KB", number_to_human_size(10100, separator: "<script></script>") + + assert_equal "1&lt;script&gt;&lt;/script&gt;01", number_to_human(1.01, separator: "<script></script>") + assert_equal "100&lt;script&gt;&lt;/script&gt;000 Quadrillion", number_to_human(10**20, delimiter: "<script></script>") + end + + def test_number_helpers_outputs_are_html_safe + assert number_to_human(1).html_safe? + assert !number_to_human("<script></script>").html_safe? + assert number_to_human("asdf".html_safe).html_safe? + assert number_to_human("1".html_safe).html_safe? + + assert number_to_human_size(1).html_safe? + assert number_to_human_size(1000000).html_safe? + assert !number_to_human_size("<script></script>").html_safe? + assert number_to_human_size("asdf".html_safe).html_safe? + assert number_to_human_size("1".html_safe).html_safe? + + assert number_with_precision(1, strip_insignificant_zeros: false).html_safe? + assert number_with_precision(1, strip_insignificant_zeros: true).html_safe? + assert !number_with_precision("<script></script>").html_safe? + assert number_with_precision("asdf".html_safe).html_safe? + assert number_with_precision("1".html_safe).html_safe? + + assert number_to_currency(1).html_safe? + assert !number_to_currency("<script></script>").html_safe? + assert number_to_currency("asdf".html_safe).html_safe? + assert number_to_currency("1".html_safe).html_safe? + + assert number_to_percentage(1).html_safe? + assert !number_to_percentage("<script></script>").html_safe? + assert number_to_percentage("asdf".html_safe).html_safe? + assert number_to_percentage("1".html_safe).html_safe? + + assert number_to_phone(1).html_safe? + assert_equal "&lt;script&gt;&lt;/script&gt;", number_to_phone("<script></script>") + assert number_to_phone("<script></script>").html_safe? + assert number_to_phone("asdf".html_safe).html_safe? + assert number_to_phone("1".html_safe).html_safe? + + assert number_with_delimiter(1).html_safe? + assert !number_with_delimiter("<script></script>").html_safe? + assert number_with_delimiter("asdf".html_safe).html_safe? + assert number_with_delimiter("1".html_safe).html_safe? + end + + def test_number_helpers_should_raise_error_if_invalid_when_specified + exception = assert_raise InvalidNumberError do + number_to_human("x", raise: true) + end + assert_equal "x", exception.number + + exception = assert_raise InvalidNumberError do + number_to_human_size("x", raise: true) + end + assert_equal "x", exception.number + + exception = assert_raise InvalidNumberError do + number_with_precision("x", raise: true) + end + assert_equal "x", exception.number + + exception = assert_raise InvalidNumberError do + number_to_currency("x", raise: true) + end + assert_equal "x", exception.number + + exception = assert_raise InvalidNumberError do + number_to_percentage("x", raise: true) + end + assert_equal "x", exception.number + + exception = assert_raise InvalidNumberError do + number_with_delimiter("x", raise: true) + end + assert_equal "x", exception.number + + exception = assert_raise InvalidNumberError do + number_to_phone("x", raise: true) + end + assert_equal "x", exception.number + end +end diff --git a/actionview/test/template/output_buffer_test.rb b/actionview/test/template/output_buffer_test.rb new file mode 100644 index 0000000000..eb0df3d1ab --- /dev/null +++ b/actionview/test/template/output_buffer_test.rb @@ -0,0 +1,59 @@ +require 'abstract_unit' + +class OutputBufferTest < ActionController::TestCase + class TestController < ActionController::Base + def index + render :text => 'foo' + end + end + + tests TestController + + def setup + @vc = @controller.view_context + get :index + assert_equal ['foo'], body_parts + end + + test 'output buffer is nil after rendering' do + assert_nil output_buffer + end + + test 'flushing ignores nil output buffer' do + @controller.view_context.flush_output_buffer + assert_nil output_buffer + assert_equal ['foo'], body_parts + end + + test 'flushing ignores empty output buffer' do + @vc.output_buffer = '' + @vc.flush_output_buffer + assert_equal '', output_buffer + assert_equal ['foo'], body_parts + end + + test 'flushing appends the output buffer to the body parts' do + @vc.output_buffer = 'bar' + @vc.flush_output_buffer + assert_equal '', output_buffer + assert_equal ['foo', 'bar'], body_parts + end + + test 'flushing preserves output buffer encoding' do + original_buffer = ' '.force_encoding(Encoding::EUC_JP) + @vc.output_buffer = original_buffer + @vc.flush_output_buffer + assert_equal ['foo', original_buffer], body_parts + assert_not_equal original_buffer, output_buffer + assert_equal Encoding::EUC_JP, output_buffer.encoding + end + + protected + def output_buffer + @vc.output_buffer + end + + def body_parts + @controller.response.body_parts + end +end diff --git a/actionview/test/template/output_safety_helper_test.rb b/actionview/test/template/output_safety_helper_test.rb new file mode 100644 index 0000000000..76c71c9e6d --- /dev/null +++ b/actionview/test/template/output_safety_helper_test.rb @@ -0,0 +1,28 @@ +require 'abstract_unit' + +class OutputSafetyHelperTest < ActionView::TestCase + tests ActionView::Helpers::OutputSafetyHelper + + def setup + @string = "hello" + end + + test "raw returns the safe string" do + result = raw(@string) + assert_equal @string, result + assert result.html_safe? + end + + test "raw handles nil values correctly" do + assert_equal "", raw(nil) + end + + test "safe_join should html_escape any items, including the separator, if they are not html_safe" do + joined = safe_join(["<p>foo</p>".html_safe, "<p>bar</p>"], "<br />") + assert_equal "<p>foo</p>&lt;br /&gt;&lt;p&gt;bar&lt;/p&gt;", joined + + joined = safe_join(["<p>foo</p>".html_safe, "<p>bar</p>".html_safe], "<br />".html_safe) + assert_equal "<p>foo</p><br /><p>bar</p>", joined + end + +end \ No newline at end of file diff --git a/actionview/test/template/record_identifier_test.rb b/actionview/test/template/record_identifier_test.rb new file mode 100644 index 0000000000..22038110a5 --- /dev/null +++ b/actionview/test/template/record_identifier_test.rb @@ -0,0 +1,49 @@ +require 'abstract_unit' +require 'controller/fake_models' + +class RecordIdentifierTest < ActiveSupport::TestCase + include ActionView::RecordIdentifier + + def setup + @klass = Comment + @record = @klass.new + @singular = 'comment' + @plural = 'comments' + @uncountable = Sheep + end + + def test_dom_id_with_new_record + assert_equal "new_#{@singular}", dom_id(@record) + end + + def test_dom_id_with_new_record_and_prefix + assert_equal "custom_prefix_#{@singular}", dom_id(@record, :custom_prefix) + end + + def test_dom_id_with_saved_record + @record.save + assert_equal "#{@singular}_1", dom_id(@record) + end + + def test_dom_id_with_prefix + @record.save + assert_equal "edit_#{@singular}_1", dom_id(@record, :edit) + end + + def test_dom_class + assert_equal @singular, dom_class(@record) + end + + def test_dom_class_with_prefix + assert_equal "custom_prefix_#{@singular}", dom_class(@record, :custom_prefix) + end + + def test_dom_id_as_singleton_method + @record.save + assert_equal "#{@singular}_1", ActionView::RecordIdentifier.dom_id(@record) + end + + def test_dom_class_as_singleton_method + assert_equal @singular, ActionView::RecordIdentifier.dom_class(@record) + end +end diff --git a/actionview/test/template/record_tag_helper_test.rb b/actionview/test/template/record_tag_helper_test.rb new file mode 100644 index 0000000000..ab84bccb56 --- /dev/null +++ b/actionview/test/template/record_tag_helper_test.rb @@ -0,0 +1,117 @@ +require 'abstract_unit' + +class RecordTagPost + extend ActiveModel::Naming + include ActiveModel::Conversion + attr_accessor :id, :body + + def initialize + @id = 45 + @body = "What a wonderful world!" + + yield self if block_given? + end +end + +class RecordTagHelperTest < ActionView::TestCase + include RenderERBUtils + + tests ActionView::Helpers::RecordTagHelper + + def setup + super + @post = RecordTagPost.new + end + + def test_content_tag_for + expected = %(<li class="record_tag_post" id="record_tag_post_45"></li>) + actual = content_tag_for(:li, @post) + assert_dom_equal expected, actual + end + + def test_content_tag_for_prefix + expected = %(<ul class="archived_record_tag_post" id="archived_record_tag_post_45"></ul>) + actual = content_tag_for(:ul, @post, :archived) + assert_dom_equal expected, actual + end + + def test_content_tag_for_with_extra_html_options + expected = %(<tr class="record_tag_post special" id="record_tag_post_45" style='background-color: #f0f0f0'></tr>) + actual = content_tag_for(:tr, @post, class: "special", style: "background-color: #f0f0f0") + assert_dom_equal expected, actual + end + + def test_content_tag_for_with_array_css_class + expected = %(<tr class="record_tag_post special odd" id="record_tag_post_45"></tr>) + actual = content_tag_for(:tr, @post, class: ["special", "odd"]) + assert_dom_equal expected, actual + end + + def test_content_tag_for_with_prefix_and_extra_html_options + expected = %(<tr class="archived_record_tag_post special" id="archived_record_tag_post_45" style='background-color: #f0f0f0'></tr>) + actual = content_tag_for(:tr, @post, :archived, class: "special", style: "background-color: #f0f0f0") + assert_dom_equal expected, actual + end + + def test_block_not_in_erb_multiple_calls + expected = %(<div class="record_tag_post special" id="record_tag_post_45">What a wonderful world!</div>) + actual = div_for(@post, class: "special") { @post.body } + assert_dom_equal expected, actual + actual = div_for(@post, class: "special") { @post.body } + assert_dom_equal expected, actual + end + + def test_block_works_with_content_tag_for_in_erb + expected = %(<tr class="record_tag_post" id="record_tag_post_45">What a wonderful world!</tr>) + actual = render_erb("<%= content_tag_for(:tr, @post) do %><%= @post.body %><% end %>") + assert_dom_equal expected, actual + end + + def test_div_for_in_erb + expected = %(<div class="record_tag_post special" id="record_tag_post_45">What a wonderful world!</div>) + actual = render_erb("<%= div_for(@post, class: 'special') do %><%= @post.body %><% end %>") + assert_dom_equal expected, actual + end + + def test_content_tag_for_collection + post_1 = RecordTagPost.new { |post| post.id = 101; post.body = "Hello!" } + post_2 = RecordTagPost.new { |post| post.id = 102; post.body = "World!" } + expected = %(<li class="record_tag_post" id="record_tag_post_101">Hello!</li>\n<li class="record_tag_post" id="record_tag_post_102">World!</li>) + actual = content_tag_for(:li, [post_1, post_2]) { |post| post.body } + assert_dom_equal expected, actual + end + + def test_content_tag_for_collection_without_given_block + post_1 = RecordTagPost.new.tap { |post| post.id = 101; post.body = "Hello!" } + post_2 = RecordTagPost.new.tap { |post| post.id = 102; post.body = "World!" } + expected = %(<li class="record_tag_post" id="record_tag_post_101"></li>\n<li class="record_tag_post" id="record_tag_post_102"></li>) + actual = content_tag_for(:li, [post_1, post_2]) + assert_dom_equal expected, actual + end + + def test_div_for_collection + post_1 = RecordTagPost.new { |post| post.id = 101; post.body = "Hello!" } + post_2 = RecordTagPost.new { |post| post.id = 102; post.body = "World!" } + expected = %(<div class="record_tag_post" id="record_tag_post_101">Hello!</div>\n<div class="record_tag_post" id="record_tag_post_102">World!</div>) + actual = div_for([post_1, post_2]) { |post| post.body } + assert_dom_equal expected, actual + end + + def test_content_tag_for_single_record_is_html_safe + result = div_for(@post, class: "special") { @post.body } + assert result.html_safe? + end + + def test_content_tag_for_collection_is_html_safe + post_1 = RecordTagPost.new { |post| post.id = 101; post.body = "Hello!" } + post_2 = RecordTagPost.new { |post| post.id = 102; post.body = "World!" } + result = content_tag_for(:li, [post_1, post_2]) { |post| post.body } + assert result.html_safe? + end + + def test_content_tag_for_does_not_change_options_hash + options = { class: "important" } + content_tag_for(:li, @post, options) + assert_equal({ class: "important" }, options) + end +end diff --git a/actionview/test/template/render_test.rb b/actionview/test/template/render_test.rb new file mode 100644 index 0000000000..81f3391fcd --- /dev/null +++ b/actionview/test/template/render_test.rb @@ -0,0 +1,537 @@ +# encoding: utf-8 +require 'abstract_unit' +require 'controller/fake_models' + +class TestController < ActionController::Base +end + +module RenderTestCases + def setup_view(paths) + @assigns = { :secret => 'in the sauce' } + @view = ActionView::Base.new(paths, @assigns) + @controller_view = TestController.new.view_context + + # Reload and register danish language for testing + I18n.reload! + I18n.backend.store_translations 'da', {} + I18n.backend.store_translations 'pt-BR', {} + + # Ensure original are still the same since we are reindexing view paths + assert_equal ORIGINAL_LOCALES, I18n.available_locales.map {|l| l.to_s }.sort + end + + def test_render_without_options + e = assert_raises(ArgumentError) { @view.render() } + assert_match "You invoked render but did not give any of :partial, :template, :inline, :file or :text option.", e.message + end + + def test_render_file + assert_equal "Hello world!", @view.render(:file => "test/hello_world") + end + + # Test if :formats, :locale etc. options are passed correctly to the resolvers. + def test_render_file_with_format + assert_match "<h1>No Comment</h1>", @view.render(:file => "comments/empty", :formats => [:html]) + assert_match "<error>No Comment</error>", @view.render(:file => "comments/empty", :formats => [:xml]) + assert_match "<error>No Comment</error>", @view.render(:file => "comments/empty", :formats => :xml) + end + + def test_render_template_with_format + assert_match "<h1>No Comment</h1>", @view.render(:template => "comments/empty", :formats => [:html]) + assert_match "<error>No Comment</error>", @view.render(:template => "comments/empty", :formats => [:xml]) + end + + def test_render_partial_implicitly_use_format_of_the_rendered_template + @view.lookup_context.formats = [:json] + assert_equal "Hello world", @view.render(:template => "test/one", :formats => [:html]) + end + + def test_render_partial_implicitly_use_format_of_the_rendered_partial + @view.lookup_context.formats = [:html] + assert_equal "Third level", @view.render(:template => "test/html_template") + end + + def test_render_partial_use_last_prepended_format_for_partials_with_the_same_names + @view.lookup_context.formats = [:html] + assert_equal "\nHTML Template, but JSON partial", @view.render(:template => "test/change_priority") + end + + def test_render_template_with_a_missing_partial_of_another_format + @view.lookup_context.formats = [:html] + assert_raise ActionView::Template::Error, "Missing partial /missing with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder]}" do + @view.render(:template => "with_format", :formats => [:json]) + end + end + + def test_render_file_with_locale + assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => [:de]) + assert_equal "<h1>Kein Kommentar</h1>", @view.render(:file => "comments/empty", :locale => :de) + end + + def test_render_template_with_locale + assert_equal "<h1>Kein Kommentar</h1>", @view.render(:template => "comments/empty", :locale => [:de]) + end + + def test_render_file_with_handlers + assert_equal "<h1>No Comment</h1>\n", @view.render(:file => "comments/empty", :handlers => [:builder]) + assert_equal "<h1>No Comment</h1>\n", @view.render(:file => "comments/empty", :handlers => :builder) + end + + def test_render_template_with_handlers + assert_equal "<h1>No Comment</h1>\n", @view.render(:template => "comments/empty", :handlers => [:builder]) + end + + def test_render_raw_template_with_handlers + assert_equal "<%= hello_world %>\n", @view.render(:template => "plain_text") + end + + def test_render_raw_template_with_quotes + assert_equal %q;Here are some characters: !@#$%^&*()-="'}{`; + "\n", @view.render(:template => "plain_text_with_characters") + end + + def test_render_ruby_template_with_handlers + assert_equal "Hello from Ruby code", @view.render(:template => "ruby_template") + end + + def test_render_ruby_template_inline + assert_equal '4', @view.render(:inline => "(2**2).to_s", :type => :ruby) + end + + def test_render_file_with_localization_on_context_level + old_locale, @view.locale = @view.locale, :da + assert_equal "Hey verden", @view.render(:file => "test/hello_world") + ensure + @view.locale = old_locale + end + + def test_render_file_with_dashed_locale + old_locale, @view.locale = @view.locale, :"pt-BR" + assert_equal "Ola mundo", @view.render(:file => "test/hello_world") + ensure + @view.locale = old_locale + end + + def test_render_file_at_top_level + assert_equal 'Elastica', @view.render(:file => '/shared') + end + + def test_render_file_with_full_path + template_path = File.join(File.dirname(__FILE__), '../fixtures/test/hello_world') + assert_equal "Hello world!", @view.render(:file => template_path) + end + + def test_render_file_with_instance_variables + assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_ivar") + end + + def test_render_file_with_locals + locals = { :secret => 'in the sauce' } + assert_equal "The secret is in the sauce\n", @view.render(:file => "test/render_file_with_locals", :locals => locals) + end + + def test_render_file_not_using_full_path_with_dot_in_path + assert_equal "The secret is in the sauce\n", @view.render(:file => "test/dot.directory/render_file_with_ivar") + end + + def test_render_partial_from_default + assert_equal "only partial", @view.render("test/partial_only") + end + + def test_render_partial + assert_equal "only partial", @view.render(:partial => "test/partial_only") + end + + def test_render_partial_with_format + assert_equal 'partial html', @view.render(:partial => 'test/partial') + end + + def test_render_partial_with_selected_format + assert_equal 'partial html', @view.render(:partial => 'test/partial', :formats => :html) + assert_equal 'partial js', @view.render(:partial => 'test/partial', :formats => [:js]) + end + + def test_render_partial_at_top_level + # file fixtures/_top_level_partial_only (not fixtures/test) + assert_equal 'top level partial', @view.render(:partial => '/top_level_partial_only') + end + + def test_render_partial_with_format_at_top_level + # file fixtures/_top_level_partial.html (not fixtures/test, with format extension) + assert_equal 'top level partial html', @view.render(:partial => '/top_level_partial') + end + + def test_render_partial_with_locals + assert_equal "5", @view.render(:partial => "test/counter", :locals => { :counter_counter => 5 }) + end + + def test_render_partial_with_locals_from_default + assert_equal "only partial", @view.render("test/partial_only", :counter_counter => 5) + end + + def test_render_partial_with_invalid_name + e = assert_raises(ArgumentError) { @view.render(:partial => "test/200") } + assert_equal "The partial name (test/200) is not a valid Ruby identifier; " + + "make sure your partial name starts with a lowercase letter or underscore, " + + "and is followed by any combination of letters, numbers and underscores.", e.message + end + + def test_render_partial_with_missing_filename + e = assert_raises(ArgumentError) { @view.render(:partial => "test/") } + assert_equal "The partial name (test/) is not a valid Ruby identifier; " + + "make sure your partial name starts with a lowercase letter or underscore, " + + "and is followed by any combination of letters, numbers and underscores.", e.message + end + + def test_render_partial_with_incompatible_object + e = assert_raises(ArgumentError) { @view.render(:partial => nil) } + assert_equal "'#{nil.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.", e.message + end + + def test_render_partial_with_hyphen + e = assert_raises(ArgumentError) { @view.render(:partial => "test/a-in") } + assert_equal "The partial name (test/a-in) is not a valid Ruby identifier; " + + "make sure your partial name starts with a lowercase letter or underscore, " + + "and is followed by any combination of letters, numbers and underscores.", e.message + end + + def test_render_partial_with_errors + e = assert_raises(ActionView::Template::Error) { @view.render(:partial => "test/raise") } + assert_match %r!method.*doesnt_exist!, e.message + assert_equal "", e.sub_template_message + assert_equal "1", e.line_number + assert_equal "1: <%= doesnt_exist %>", e.annoted_source_code.strip + assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name + end + + def test_render_error_indentation + e = assert_raises(ActionView::Template::Error) { @view.render(:partial => "test/raise_indentation") } + error_lines = e.annoted_source_code.split("\n") + assert_match %r!error\shere!, e.message + assert_equal "11", e.line_number + assert_equal " 9: <p>Ninth paragraph</p>", error_lines.second + assert_equal " 10: <p>Tenth paragraph</p>", error_lines.third + end + + def test_render_sub_template_with_errors + e = assert_raises(ActionView::Template::Error) { @view.render(:template => "test/sub_template_raise") } + assert_match %r!method.*doesnt_exist!, e.message + assert_equal "Trace of template inclusion: #{File.expand_path("#{FIXTURE_LOAD_PATH}/test/sub_template_raise.html.erb")}", e.sub_template_message + assert_equal "1", e.line_number + assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name + end + + def test_render_file_with_errors + e = assert_raises(ActionView::Template::Error) { @view.render(:file => File.expand_path("test/_raise", FIXTURE_LOAD_PATH)) } + assert_match %r!method.*doesnt_exist!, e.message + assert_equal "", e.sub_template_message + assert_equal "1", e.line_number + assert_equal "1: <%= doesnt_exist %>", e.annoted_source_code.strip + assert_equal File.expand_path("#{FIXTURE_LOAD_PATH}/test/_raise.html.erb"), e.file_name + end + + def test_render_object + assert_equal "Hello: david", @view.render(:partial => "test/customer", :object => Customer.new("david")) + end + + def test_render_object_with_array + assert_equal "[1, 2, 3]", @view.render(:partial => "test/object_inspector", :object => [1, 2, 3]) + end + + def test_render_partial_collection + assert_equal "Hello: davidHello: mary", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), Customer.new("mary") ]) + end + + def test_render_partial_collection_as_by_string + assert_equal "david david davidmary mary mary", + @view.render(:partial => "test/customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => 'customer') + end + + def test_render_partial_collection_as_by_symbol + assert_equal "david david davidmary mary mary", + @view.render(:partial => "test/customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer) + end + + def test_render_partial_collection_without_as + assert_equal "local_inspector,local_inspector_counter", + @view.render(:partial => "test/local_inspector", :collection => [ Customer.new("mary") ]) + end + + def test_render_partial_with_empty_collection_should_return_nil + assert_nil @view.render(:partial => "test/customer", :collection => []) + end + + def test_render_partial_with_nil_collection_should_return_nil + assert_nil @view.render(:partial => "test/customer", :collection => nil) + end + + def test_render_partial_with_nil_values_in_collection + assert_equal "Hello: davidHello: Anonymous", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), nil ]) + end + + def test_render_partial_with_layout_using_collection_and_template + assert_equal "<b>Hello: Amazon</b><b>Hello: Yahoo</b>", @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + end + + def test_render_partial_with_layout_using_collection_and_template_makes_current_item_available_in_layout + assert_equal '<b class="amazon">Hello: Amazon</b><b class="yahoo">Hello: Yahoo</b>', + @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + end + + def test_render_partial_with_layout_using_collection_and_template_makes_current_item_counter_available_in_layout + assert_equal '<b data-counter="0">Hello: Amazon</b><b data-counter="1">Hello: Yahoo</b>', + @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object_counter', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + end + + def test_render_partial_with_layout_using_object_and_template_makes_object_available_in_layout + assert_equal '<b class="amazon">Hello: Amazon</b>', + @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :object => Customer.new("Amazon")) + end + + def test_render_partial_with_empty_array_should_return_nil + assert_nil @view.render(:partial => []) + end + + def test_render_partial_using_string + assert_equal "Hello: Anonymous", @controller_view.render('customer') + end + + def test_render_partial_with_locals_using_string + assert_equal "Hola: david", @controller_view.render('customer_greeting', :greeting => 'Hola', :customer_greeting => Customer.new("david")) + end + + def test_render_partial_using_object + assert_equal "Hello: lifo", + @controller_view.render(Customer.new("lifo"), :greeting => "Hello") + end + + def test_render_partial_using_collection + customers = [ Customer.new("Amazon"), Customer.new("Yahoo") ] + assert_equal "Hello: AmazonHello: Yahoo", + @controller_view.render(customers, :greeting => "Hello") + end + + def test_render_partial_without_object_or_collection_does_not_generate_partial_name_local_variable + exception = assert_raises ActionView::Template::Error do + @controller_view.render("partial_name_local_variable") + end + assert_match "undefined local variable or method `partial_name_local_variable'", exception.message + end + + # TODO: The reason for this test is unclear, improve documentation + def test_render_partial_and_fallback_to_layout + assert_equal "Before (Josh)\n\nAfter", @view.render(:partial => "test/layout_for_partial", :locals => { :name => "Josh" }) + end + + # TODO: The reason for this test is unclear, improve documentation + def test_render_missing_xml_partial_and_raise_missing_template + @view.formats = [:xml] + assert_raises(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") } + ensure + @view.formats = nil + end + + def test_render_layout_with_block_and_other_partial_inside + render = @view.render(:layout => "test/layout_with_partial_and_yield") { "Yield!" } + assert_equal "Before\npartial html\nYield!\nAfter\n", render + end + + def test_render_inline + assert_equal "Hello, World!", @view.render(:inline => "Hello, World!") + end + + def test_render_inline_with_locals + assert_equal "Hello, Josh!", @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }) + end + + def test_render_fallbacks_to_erb_for_unknown_types + assert_equal "Hello, World!", @view.render(:inline => "Hello, World!", :type => :bar) + end + + CustomHandler = lambda do |template| + "@output_buffer = ''\n" + + "@output_buffer << 'source: #{template.source.inspect}'\n" + end + + def test_render_inline_with_render_from_to_proc + ActionView::Template.register_template_handler :ruby_handler, :source.to_proc + assert_equal '3', @view.render(:inline => "(1 + 2).to_s", :type => :ruby_handler) + end + + def test_render_inline_with_compilable_custom_type + ActionView::Template.register_template_handler :foo, CustomHandler + assert_equal 'source: "Hello, World!"', @view.render(:inline => "Hello, World!", :type => :foo) + end + + def test_render_inline_with_locals_and_compilable_custom_type + ActionView::Template.register_template_handler :foo, CustomHandler + assert_equal 'source: "Hello, <%= name %>!"', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo) + end + + def test_render_knows_about_types_registered_when_extensions_are_checked_earlier_in_initialization + ActionView::Template::Handlers.extensions + ActionView::Template.register_template_handler :foo, CustomHandler + assert ActionView::Template::Handlers.extensions.include?(:foo) + end + + def test_render_ignores_templates_with_malformed_template_handlers + ActiveSupport::Deprecation.silence do + %w(malformed malformed.erb malformed.html.erb malformed.en.html.erb).each do |name| + assert_raises(ActionView::MissingTemplate) { @view.render(:file => "test/malformed/#{name}") } + end + end + end + + def test_render_with_layout + assert_equal %(<title></title>\nHello world!\n), + @view.render(:file => "test/hello_world", :layout => "layouts/yield") + end + + def test_render_with_layout_which_has_render_inline + assert_equal %(welcome\nHello world!\n), + @view.render(:file => "test/hello_world", :layout => "layouts/yield_with_render_inline_inside") + end + + def test_render_with_layout_which_renders_another_partial + assert_equal %(partial html\nHello world!\n), + @view.render(:file => "test/hello_world", :layout => "layouts/yield_with_render_partial_inside") + end + + def test_render_layout_with_block_and_yield + assert_equal %(Content from block!\n), + @view.render(:layout => "layouts/yield_only") { "Content from block!" } + end + + def test_render_layout_with_block_and_yield_with_params + assert_equal %(Yield! Content from block!\n), + @view.render(:layout => "layouts/yield_with_params") { |param| "#{param} Content from block!" } + end + + def test_render_layout_with_block_which_renders_another_partial_and_yields + assert_equal %(partial html\nContent from block!\n), + @view.render(:layout => "layouts/partial_and_yield") { "Content from block!" } + end + + def test_render_partial_and_layout_without_block_with_locals + assert_equal %(Before (Foo!)\npartial html\nAfter), + @view.render(:partial => 'test/partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_partial_and_layout_without_block_with_locals_and_rendering_another_partial + assert_equal %(Before (Foo!)\npartial html\npartial with partial\n\nAfter), + @view.render(:partial => 'test/partial_with_partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_layout_with_a_nested_render_layout_call + assert_equal %(Before (Foo!)\nBefore (Bar!)\npartial html\nAfter\npartial with layout\n\nAfter), + @view.render(:partial => 'test/partial_with_layout', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_layout_with_a_nested_render_layout_call_using_block_with_render_partial + assert_equal %(Before (Foo!)\nBefore (Bar!)\n\n partial html\n\nAfterpartial with layout\n\nAfter), + @view.render(:partial => 'test/partial_with_layout_block_partial', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_layout_with_a_nested_render_layout_call_using_block_with_render_content + assert_equal %(Before (Foo!)\nBefore (Bar!)\n\n Content from inside layout!\n\nAfterpartial with layout\n\nAfter), + @view.render(:partial => 'test/partial_with_layout_block_content', :layout => 'test/layout_for_partial', :locals => { :name => 'Foo!'}) + end + + def test_render_partial_with_layout_raises_descriptive_error + e = assert_raises(ActionView::MissingTemplate) { @view.render(partial: 'test/partial', layout: true) } + assert_match "Missing partial /true with", e.message + end + + def test_render_with_nested_layout + assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n), + @view.render(:file => "test/nested_layout", :layout => "layouts/yield") + end + + def test_render_with_file_in_layout + assert_equal %(\n<title>title</title>\n\n), + @view.render(:file => "test/layout_render_file") + end + + def test_render_layout_with_object + assert_equal %(<title>David</title>), + @view.render(:file => "test/layout_render_object") + end + + def test_render_with_passing_couple_extensions_to_one_register_template_handler_function_call + ActionView::Template.register_template_handler :foo1, :foo2, CustomHandler + assert_equal @view.render(:inline => "Hello, World!", :type => :foo1), @view.render(:inline => "Hello, World!", :type => :foo2) + end + + def test_render_throws_exception_when_no_extensions_passed_to_register_template_handler_function_call + assert_raises(ArgumentError) { ActionView::Template.register_template_handler CustomHandler } + end +end + +class CachedViewRenderTest < ActiveSupport::TestCase + include RenderTestCases + + # Ensure view path cache is primed + def setup + view_paths = ActionController::Base.view_paths + assert_equal ActionView::OptimizedFileSystemResolver, view_paths.first.class + setup_view(view_paths) + end + + def teardown + GC.start + end +end + +class LazyViewRenderTest < ActiveSupport::TestCase + include RenderTestCases + + # Test the same thing as above, but make sure the view path + # is not eager loaded + def setup + path = ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH) + view_paths = ActionView::PathSet.new([path]) + assert_equal ActionView::FileSystemResolver.new(FIXTURE_LOAD_PATH), view_paths.first + setup_view(view_paths) + end + + def teardown + GC.start + end + + def test_render_utf8_template_with_magic_comment + with_external_encoding Encoding::ASCII_8BIT do + result = @view.render(:file => "test/utf8_magic", :formats => [:html], :layouts => "layouts/yield") + assert_equal Encoding::UTF_8, result.encoding + assert_equal "\nРусский \nтекст\n\nUTF-8\nUTF-8\nUTF-8\n", result + end + end + + def test_render_utf8_template_with_default_external_encoding + with_external_encoding Encoding::UTF_8 do + result = @view.render(:file => "test/utf8", :formats => [:html], :layouts => "layouts/yield") + assert_equal Encoding::UTF_8, result.encoding + assert_equal "Русский текст\n\nUTF-8\nUTF-8\nUTF-8\n", result + end + end + + def test_render_utf8_template_with_incompatible_external_encoding + with_external_encoding Encoding::SHIFT_JIS do + e = assert_raises(ActionView::Template::Error) { @view.render(:file => "test/utf8", :formats => [:html], :layouts => "layouts/yield") } + assert_match 'Your template was not saved as valid Shift_JIS', e.original_exception.message + end + end + + def test_render_utf8_template_with_partial_with_incompatible_encoding + with_external_encoding Encoding::SHIFT_JIS do + e = assert_raises(ActionView::Template::Error) { @view.render(:file => "test/utf8_magic_with_bare_partial", :formats => [:html], :layouts => "layouts/yield") } + assert_match 'Your template was not saved as valid Shift_JIS', e.original_exception.message + end + end + + def with_external_encoding(encoding) + old = Encoding.default_external + silence_warnings { Encoding.default_external = encoding } + yield + ensure + silence_warnings { Encoding.default_external = old } + end +end diff --git a/actionview/test/template/resolver_patterns_test.rb b/actionview/test/template/resolver_patterns_test.rb new file mode 100644 index 0000000000..97b1bad055 --- /dev/null +++ b/actionview/test/template/resolver_patterns_test.rb @@ -0,0 +1,31 @@ +require 'abstract_unit' + +class ResolverPatternsTest < ActiveSupport::TestCase + def setup + path = File.expand_path("../../fixtures/", __FILE__) + pattern = ":prefix/{:formats/,}:action{.:formats,}{.:handlers,}" + @resolver = ActionView::FileSystemResolver.new(path, pattern) + end + + def test_should_return_empty_list_for_unknown_path + templates = @resolver.find_all("unknown", "custom_pattern", false, {:locale => [], :formats => [:html], :handlers => [:erb]}) + assert_equal [], templates, "expected an empty list of templates" + end + + def test_should_return_template_for_declared_path + templates = @resolver.find_all("path", "custom_pattern", false, {:locale => [], :formats => [:html], :handlers => [:erb]}) + assert_equal 1, templates.size, "expected one template" + assert_equal "Hello custom patterns!", templates.first.source + assert_equal "custom_pattern/path", templates.first.virtual_path + assert_equal [:html], templates.first.formats + end + + def test_should_return_all_templates_when_ambigous_pattern + templates = @resolver.find_all("another", "custom_pattern", false, {:locale => [], :formats => [:html], :handlers => [:erb]}) + assert_equal 2, templates.size, "expected two templates" + assert_equal "Another template!", templates[0].source + assert_equal "custom_pattern/another", templates[0].virtual_path + assert_equal "Hello custom patterns!", templates[1].source + assert_equal "custom_pattern/another", templates[1].virtual_path + end +end diff --git a/actionview/test/template/sanitize_helper_test.rb b/actionview/test/template/sanitize_helper_test.rb new file mode 100644 index 0000000000..12d5260a9d --- /dev/null +++ b/actionview/test/template/sanitize_helper_test.rb @@ -0,0 +1,51 @@ +require 'abstract_unit' + +# The exhaustive tests are in test/controller/html/sanitizer_test.rb. +# This tests the that the helpers hook up correctly to the sanitizer classes. +class SanitizeHelperTest < ActionView::TestCase + tests ActionView::Helpers::SanitizeHelper + + def test_strip_links + assert_equal "Dont touch me", strip_links("Dont touch me") + assert_equal "<a<a", strip_links("<a<a") + assert_equal "on my mind\nall day long", strip_links("<a href='almost'>on my mind</a>\n<A href='almost'>all day long</A>") + assert_equal "0wn3d", strip_links("<a href='http://www.rubyonrails.com/'><a href='http://www.rubyonrails.com/' onlclick='steal()'>0wn3d</a></a>") + assert_equal "Magic", strip_links("<a href='http://www.rubyonrails.com/'>Mag<a href='http://www.ruby-lang.org/'>ic") + assert_equal "FrrFox", strip_links("<href onlclick='steal()'>FrrFox</a></href>") + assert_equal "My mind\nall <b>day</b> long", strip_links("<a href='almost'>My mind</a>\n<A href='almost'>all <b>day</b> long</A>") + assert_equal "all <b>day</b> long", strip_links("<<a>a href='hello'>all <b>day</b> long<</A>/a>") + end + + def test_sanitize_form + assert_equal '', sanitize("<form action=\"/foo/bar\" method=\"post\"><input></form>") + end + + def test_should_sanitize_illegal_style_properties + raw = %(display:block; position:absolute; left:0; top:0; width:100%; height:100%; z-index:1; background-color:black; background-image:url(http://www.ragingplatypus.com/i/cam-full.jpg); background-x:center; background-y:center; background-repeat:repeat;) + expected = %(display: block; width: 100%; height: 100%; background-color: black; background-image: ; background-x: center; background-y: center;) + assert_equal expected, sanitize_css(raw) + end + + def test_strip_tags + assert_equal("<<<bad html", strip_tags("<<<bad html")) + assert_equal("<<", strip_tags("<<<bad html>")) + assert_equal("Dont touch me", strip_tags("Dont touch me")) + assert_equal("This is a test.", strip_tags("<p>This <u>is<u> a <a href='test.html'><strong>test</strong></a>.</p>")) + assert_equal("Weirdos", strip_tags("Wei<<a>a onclick='alert(document.cookie);'</a>/>rdos")) + assert_equal("This is a test.", strip_tags("This is a test.")) + assert_equal( + %{This is a test.\n\n\nIt no longer contains any HTML.\n}, strip_tags( + %{<title>This is <b>a <a href="" target="_blank">test</a></b>.</title>\n\n<!-- it has a comment -->\n\n<p>It no <b>longer <strong>contains <em>any <strike>HTML</strike></em>.</strong></b></p>\n})) + assert_equal "This has a here.", strip_tags("This has a <!-- comment --> here.") + [nil, '', ' '].each do |blank| + stripped = strip_tags(blank) + assert_equal blank, stripped + end + assert_equal "", strip_tags("<script>") + assert_equal "something &lt;img onerror=alert(1337)", ERB::Util.html_escape(strip_tags("something <img onerror=alert(1337)")) + end + + def test_sanitize_is_marked_safe + assert sanitize("<html><script></script></html>").html_safe? + end +end diff --git a/actionview/test/template/streaming_render_test.rb b/actionview/test/template/streaming_render_test.rb new file mode 100644 index 0000000000..520bf3a824 --- /dev/null +++ b/actionview/test/template/streaming_render_test.rb @@ -0,0 +1,109 @@ +# encoding: utf-8 +require 'abstract_unit' +require 'controller/fake_models' + +class TestController < ActionController::Base +end + +class FiberedTest < ActiveSupport::TestCase + def setup + view_paths = ActionController::Base.view_paths + @assigns = { :secret => 'in the sauce', :name => nil } + @view = ActionView::Base.new(view_paths, @assigns) + @controller_view = TestController.new.view_context + end + + def render_body(options) + @view.view_renderer.render_body(@view, options) + end + + def buffered_render(options) + body = render_body(options) + string = "" + body.each do |piece| + string << piece + end + string + end + + def test_streaming_works + content = [] + body = render_body(:template => "test/hello_world", :layout => "layouts/yield") + + body.each do |piece| + content << piece + end + + assert_equal "<title>", content[0] + assert_equal "", content[1] + assert_equal "</title>\n", content[2] + assert_equal "Hello world!", content[3] + assert_equal "\n", content[4] + end + + def test_render_file + assert_equal "Hello world!", buffered_render(:file => "test/hello_world") + end + + def test_render_file_with_locals + locals = { :secret => 'in the sauce' } + assert_equal "The secret is in the sauce\n", buffered_render(:file => "test/render_file_with_locals", :locals => locals) + end + + def test_render_partial + assert_equal "only partial", buffered_render(:partial => "test/partial_only") + end + + def test_render_inline + assert_equal "Hello, World!", buffered_render(:inline => "Hello, World!") + end + + def test_render_without_layout + assert_equal "Hello world!", buffered_render(:template => "test/hello_world") + end + + def test_render_with_layout + assert_equal %(<title></title>\nHello world!\n), + buffered_render(:template => "test/hello_world", :layout => "layouts/yield") + end + + def test_render_with_layout_which_has_render_inline + assert_equal %(welcome\nHello world!\n), + buffered_render(:template => "test/hello_world", :layout => "layouts/yield_with_render_inline_inside") + end + + def test_render_with_layout_which_renders_another_partial + assert_equal %(partial html\nHello world!\n), + buffered_render(:template => "test/hello_world", :layout => "layouts/yield_with_render_partial_inside") + end + + def test_render_with_nested_layout + assert_equal %(<title>title</title>\n\n<div id="column">column</div>\n<div id="content">content</div>\n), + buffered_render(:template => "test/nested_layout", :layout => "layouts/yield") + end + + def test_render_with_file_in_layout + assert_equal %(\n<title>title</title>\n\n), + buffered_render(:template => "test/layout_render_file") + end + + def test_render_with_handler_without_streaming_support + assert_match "<p>This is grand!</p>", buffered_render(:template => "test/hello") + end + + def test_render_with_streaming_multiple_yields_provide_and_content_for + assert_equal "Yes, \nthis works\n like a charm.", + buffered_render(:template => "test/streaming", :layout => "layouts/streaming") + end + + def test_render_with_streaming_with_fake_yields_and_streaming_buster + assert_equal "This won't look\n good.", + buffered_render(:template => "test/streaming_buster", :layout => "layouts/streaming") + end + + def test_render_with_nested_streaming_multiple_yields_provide_and_content_for + assert_equal "?Yes, \n\nthis works\n\n? like a charm.", + buffered_render(:template => "test/nested_streaming", :layout => "layouts/streaming") + end + +end diff --git a/actionview/test/template/tag_helper_test.rb b/actionview/test/template/tag_helper_test.rb new file mode 100644 index 0000000000..802da5d566 --- /dev/null +++ b/actionview/test/template/tag_helper_test.rb @@ -0,0 +1,130 @@ +require 'abstract_unit' + +class TagHelperTest < ActionView::TestCase + include RenderERBUtils + + tests ActionView::Helpers::TagHelper + + def test_tag + assert_equal "<br />", tag("br") + assert_equal "<br clear=\"left\" />", tag(:br, :clear => "left") + assert_equal "<br>", tag("br", nil, true) + end + + def test_tag_options + str = tag("p", "class" => "show", :class => "elsewhere") + assert_match(/class="show"/, str) + assert_match(/class="elsewhere"/, str) + end + + def test_tag_options_rejects_nil_option + assert_equal "<p />", tag("p", :ignored => nil) + end + + def test_tag_options_accepts_false_option + assert_equal "<p value=\"false\" />", tag("p", :value => false) + end + + def test_tag_options_accepts_blank_option + assert_equal "<p included=\"\" />", tag("p", :included => '') + end + + def test_tag_options_converts_boolean_option + assert_dom_equal '<p disabled="disabled" itemscope="itemscope" multiple="multiple" readonly="readonly" allowfullscreen="allowfullscreen" seamless="seamless" typemustmatch="typemustmatch" sortable="sortable" default="default" inert="inert" truespeed="truespeed" />', + tag("p", :disabled => true, :itemscope => true, :multiple => true, :readonly => true, :allowfullscreen => true, :seamless => true, :typemustmatch => true, :sortable => true, :default => true, :inert => true, :truespeed => true) + end + + def test_content_tag + assert_equal "<a href=\"create\">Create</a>", content_tag("a", "Create", "href" => "create") + assert content_tag("a", "Create", "href" => "create").html_safe? + assert_equal content_tag("a", "Create", "href" => "create"), + content_tag("a", "Create", :href => "create") + assert_equal "<p>&lt;script&gt;evil_js&lt;/script&gt;</p>", + content_tag(:p, '<script>evil_js</script>') + assert_equal "<p><script>evil_js</script></p>", + content_tag(:p, '<script>evil_js</script>', nil, false) + end + + def test_content_tag_with_block_in_erb + buffer = render_erb("<%= content_tag(:div) do %>Hello world!<% end %>") + assert_dom_equal "<div>Hello world!</div>", buffer + end + + def test_content_tag_with_block_and_options_in_erb + buffer = render_erb("<%= content_tag(:div, :class => 'green') do %>Hello world!<% end %>") + assert_dom_equal %(<div class="green">Hello world!</div>), buffer + end + + def test_content_tag_with_block_and_options_out_of_erb + assert_dom_equal %(<div class="green">Hello world!</div>), content_tag(:div, :class => "green") { "Hello world!" } + end + + def test_content_tag_with_block_and_options_outside_out_of_erb + assert_equal content_tag("a", "Create", :href => "create"), + content_tag("a", "href" => "create") { "Create" } + end + + def test_content_tag_nested_in_content_tag_out_of_erb + assert_equal content_tag("p", content_tag("b", "Hello")), + content_tag("p") { content_tag("b", "Hello") }, + output_buffer + end + + def test_content_tag_nested_in_content_tag_in_erb + assert_equal "<p>\n <b>Hello</b>\n</p>", view.render("test/content_tag_nested_in_content_tag") + end + + def test_content_tag_with_escaped_array_class + str = content_tag('p', "limelight", :class => ["song", "play>"]) + assert_equal "<p class=\"song play&gt;\">limelight</p>", str + + str = content_tag('p', "limelight", :class => ["song", "play"]) + assert_equal "<p class=\"song play\">limelight</p>", str + end + + def test_content_tag_with_unescaped_array_class + str = content_tag('p', "limelight", {:class => ["song", "play>"]}, false) + assert_equal "<p class=\"song play>\">limelight</p>", str + end + + def test_content_tag_with_data_attributes + assert_dom_equal '<p data-number="1" data-string="hello" data-string-with-quotes="double&quot;quote&quot;party&quot;">limelight</p>', + content_tag('p', "limelight", data: { number: 1, string: 'hello', string_with_quotes: 'double"quote"party"' }) + end + + def test_cdata_section + assert_equal "<![CDATA[<hello world>]]>", cdata_section("<hello world>") + end + + def test_cdata_section_splitted + assert_equal "<![CDATA[hello]]]]><![CDATA[>world]]>", cdata_section("hello]]>world") + assert_equal "<![CDATA[hello]]]]><![CDATA[>world]]]]><![CDATA[>again]]>", cdata_section("hello]]>world]]>again") + end + + def test_escape_once + assert_equal '1 &lt; 2 &amp; 3', escape_once('1 < 2 &amp; 3') + end + + def test_tag_honors_html_safe_for_param_values + ['1&amp;2', '1 &lt; 2', '&#8220;test&#8220;'].each do |escaped| + assert_equal %(<a href="#{escaped}" />), tag('a', :href => escaped.html_safe) + end + end + + def test_skip_invalid_escaped_attributes + ['&1;', '&#1dfa3;', '& #123;'].each do |escaped| + assert_equal %(<a href="#{escaped.gsub(/&/, '&amp;')}" />), tag('a', :href => escaped) + end + end + + def test_disable_escaping + assert_equal '<a href="&amp;" />', tag('a', { :href => '&amp;' }, false, false) + end + + def test_data_attributes + ['data', :data].each { |data| + assert_dom_equal '<a data-a-float="3.14" data-a-big-decimal="-123.456" data-a-number="1" data-array="[1,2,3]" data-hash="{&quot;key&quot;:&quot;value&quot;}" data-string-with-quotes="double&quot;quote&quot;party&quot;" data-string="hello" data-symbol="foo" />', + tag('a', { data => { a_float: 3.14, a_big_decimal: BigDecimal.new("-123.456"), a_number: 1, string: 'hello', symbol: :foo, array: [1, 2, 3], hash: { key: 'value'}, string_with_quotes: 'double"quote"party"' } }) + } + end +end diff --git a/actionview/test/template/template_error_test.rb b/actionview/test/template/template_error_test.rb new file mode 100644 index 0000000000..91424daeed --- /dev/null +++ b/actionview/test/template/template_error_test.rb @@ -0,0 +1,13 @@ +require "abstract_unit" + +class TemplateErrorTest < ActiveSupport::TestCase + def test_provides_original_message + error = ActionView::Template::Error.new("test", Exception.new("original")) + assert_equal "original", error.message + end + + def test_provides_useful_inspect + error = ActionView::Template::Error.new("test", Exception.new("original")) + assert_equal "#<ActionView::Template::Error: original>", error.inspect + end +end diff --git a/actionview/test/template/template_test.rb b/actionview/test/template/template_test.rb new file mode 100644 index 0000000000..c94508d678 --- /dev/null +++ b/actionview/test/template/template_test.rb @@ -0,0 +1,200 @@ +# encoding: US-ASCII +require "abstract_unit" +require "logger" + +class TestERBTemplate < ActiveSupport::TestCase + ERBHandler = ActionView::Template::Handlers::ERB.new + + class LookupContext + def disable_cache + yield + end + + def find_template(*args) + end + + attr_accessor :formats + end + + class Context + def initialize + @output_buffer = "original" + @virtual_path = nil + end + + def hello + "Hello" + end + + def apostrophe + "l'apostrophe" + end + + def partial + ActionView::Template.new( + "<%= @virtual_path %>", + "partial", + ERBHandler, + :virtual_path => "partial" + ) + end + + def lookup_context + @lookup_context ||= LookupContext.new + end + + def logger + ActiveSupport::Logger.new(STDERR) + end + + def my_buffer + @output_buffer + end + end + + def new_template(body = "<%= hello %>", details = { format: :html }) + ActionView::Template.new(body, "hello template", details.fetch(:handler) { ERBHandler }, {:virtual_path => "hello"}.merge!(details)) + end + + def render(locals = {}) + @template.render(@context, locals) + end + + def setup + @context = Context.new + end + + def test_basic_template + @template = new_template + assert_equal "Hello", render + end + + def test_basic_template_does_html_escape + @template = new_template("<%= apostrophe %>") + assert_equal "l&#39;apostrophe", render + end + + def test_text_template_does_not_html_escape + @template = new_template("<%= apostrophe %> <%== apostrophe %>", format: :text) + assert_equal "l'apostrophe l'apostrophe", render + end + + def test_raw_template + @template = new_template("<%= hello %>", :handler => ActionView::Template::Handlers::Raw.new) + assert_equal "<%= hello %>", render + end + + def test_template_loses_its_source_after_rendering + @template = new_template + render + assert_nil @template.source + end + + def test_template_does_not_lose_its_source_after_rendering_if_it_does_not_have_a_virtual_path + @template = new_template("Hello", :virtual_path => nil) + render + assert_equal "Hello", @template.source + end + + def test_locals + @template = new_template("<%= my_local %>") + @template.locals = [:my_local] + assert_equal "I am a local", render(:my_local => "I am a local") + end + + def test_restores_buffer + @template = new_template + assert_equal "Hello", render + assert_equal "original", @context.my_buffer + end + + def test_virtual_path + @template = new_template("<%= @virtual_path %>" \ + "<%= partial.render(self, {}) %>" \ + "<%= @virtual_path %>") + assert_equal "hellopartialhello", render + end + + def test_refresh_with_templates + @template = new_template("Hello", :virtual_path => "test/foo/bar") + @template.locals = [:key] + @context.lookup_context.expects(:find_template).with("bar", %w(test/foo), false, [:key]).returns("template") + assert_equal "template", @template.refresh(@context) + end + + def test_refresh_with_partials + @template = new_template("Hello", :virtual_path => "test/_foo") + @template.locals = [:key] + @context.lookup_context.expects(:find_template).with("foo", %w(test), true, [:key]).returns("partial") + assert_equal "partial", @template.refresh(@context) + end + + def test_refresh_raises_an_error_without_virtual_path + @template = new_template("Hello", :virtual_path => nil) + assert_raise RuntimeError do + @template.refresh(@context) + end + end + + def test_resulting_string_is_utf8 + @template = new_template + assert_equal Encoding::UTF_8, render.encoding + end + + def test_no_magic_comment_word_with_utf_8 + @template = new_template("hello \u{fc}mlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + end + + # This test ensures that if the default_external + # is set to something other than UTF-8, we don't + # get any errors and get back a UTF-8 String. + def test_default_external_works + with_external_encoding "ISO-8859-1" do + @template = new_template("hello \xFCmlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + end + end + + def test_encoding_can_be_specified_with_magic_comment + @template = new_template("# encoding: ISO-8859-1\nhello \xFCmlat") + assert_equal Encoding::UTF_8, render.encoding + assert_equal "\nhello \u{fc}mlat", render + end + + # TODO: This is currently handled inside ERB. The case of explicitly + # lying about encodings via the normal Rails API should be handled + # inside Rails. + def test_lying_with_magic_comment + assert_raises(ActionView::Template::Error) do + @template = new_template("# encoding: UTF-8\nhello \xFCmlat", :virtual_path => nil) + render + end + end + + def test_encoding_can_be_specified_with_magic_comment_in_erb + with_external_encoding Encoding::UTF_8 do + @template = new_template("<%# encoding: ISO-8859-1 %>hello \xFCmlat", :virtual_path => nil) + assert_equal Encoding::UTF_8, render.encoding + assert_equal "hello \u{fc}mlat", render + end + end + + def test_error_when_template_isnt_valid_utf8 + assert_raises(ActionView::Template::Error, /\xFC/) do + @template = new_template("hello \xFCmlat", :virtual_path => nil) + render + end + end + + def with_external_encoding(encoding) + old = Encoding.default_external + Encoding::Converter.new old, encoding if old != encoding + silence_warnings { Encoding.default_external = encoding } + yield + ensure + silence_warnings { Encoding.default_external = old } + end +end diff --git a/actionview/test/template/test_case_test.rb b/actionview/test/template/test_case_test.rb new file mode 100644 index 0000000000..acd002ce73 --- /dev/null +++ b/actionview/test/template/test_case_test.rb @@ -0,0 +1,367 @@ +require 'abstract_unit' +require 'controller/fake_controllers' + +module ActionView + + module ATestHelper + end + + module AnotherTestHelper + def from_another_helper + 'Howdy!' + end + end + + module ASharedTestHelper + def from_shared_helper + 'Holla!' + end + end + + class TestCase + helper ASharedTestHelper + + module SharedTests + def self.included(test_case) + test_case.class_eval do + test "helpers defined on ActionView::TestCase are available" do + assert test_case.ancestors.include?(ASharedTestHelper) + assert_equal 'Holla!', from_shared_helper + end + end + end + end + end + + class GeneralViewTest < ActionView::TestCase + include SharedTests + test_case = self + + test "memoizes the view" do + assert_same view, view + end + + test "exposes view as _view for backwards compatibility" do + assert_same _view, view + end + + test "retrieve non existing config values" do + assert_equal nil, ActionView::Base.new.config.something_odd + end + + test "works without testing a helper module" do + assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy')) + end + + test "can render a layout with block" do + assert_equal "Before (ChrisCruft)\n!\nAfter", + render(:layout => "test/layout_for_partial", :locals => {:name => "ChrisCruft"}) {"!"} + end + + helper AnotherTestHelper + test "additional helper classes can be specified as in a controller" do + assert test_case.ancestors.include?(AnotherTestHelper) + assert_equal 'Howdy!', from_another_helper + end + + test "determine_default_helper_class returns nil if the test name constant resolves to a class" do + assert_nil self.class.determine_default_helper_class("String") + end + + test "delegates notice to request.flash[:notice]" do + view.request.flash.expects(:[]).with(:notice) + view.notice + end + + test "delegates alert to request.flash[:alert]" do + view.request.flash.expects(:[]).with(:alert) + view.alert + end + + test "uses controller lookup context" do + assert_equal self.lookup_context, @controller.lookup_context + end + end + + class ClassMethodsTest < ActionView::TestCase + include SharedTests + test_case = self + + tests ATestHelper + test "tests the specified helper module" do + assert_equal ATestHelper, test_case.helper_class + assert test_case.ancestors.include?(ATestHelper) + end + + helper AnotherTestHelper + test "additional helper classes can be specified as in a controller" do + assert test_case.ancestors.include?(AnotherTestHelper) + assert_equal 'Howdy!', from_another_helper + + test_case.helper_class.module_eval do + def render_from_helper + from_another_helper + end + end + assert_equal 'Howdy!', render(:partial => 'test/from_helper') + end + end + + class HelperInclusionTest < ActionView::TestCase + module RenderHelper + def render_from_helper + render :partial => 'customer', :collection => @customers + end + end + + helper RenderHelper + + test "helper class that is being tested is always included in view instance" do + @controller.controller_path = 'test' + + @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')] + assert_match(/Hello: EloyHello: Manfred/, render(:partial => 'test/from_helper')) + end + end + + class ControllerHelperMethod < ActionView::TestCase + module SomeHelper + def some_method + render :partial => 'test/from_helper' + end + end + + helper SomeHelper + + test "can call a helper method defined on the current controller from a helper" do + @controller.singleton_class.class_eval <<-EOF, __FILE__, __LINE__ + 1 + def render_from_helper + 'controller_helper_method' + end + EOF + @controller.class.helper_method :render_from_helper + + assert_equal 'controller_helper_method', some_method + end + end + + class ViewAssignsTest < ActionView::TestCase + test "view_assigns returns a Hash of user defined ivars" do + @a = 'b' + @c = 'd' + assert_equal({:a => 'b', :c => 'd'}, view_assigns) + end + + test "view_assigns excludes internal ivars" do + INTERNAL_IVARS.each do |ivar| + assert defined?(ivar), "expected #{ivar} to be defined" + assert !view_assigns.keys.include?(ivar.to_s.sub('@', '').to_sym), "expected #{ivar} to be excluded from view_assigns" + end + end + end + + class HelperExposureTest < ActionView::TestCase + helper(Module.new do + def render_from_helper + from_test_case + end + end) + test "is able to make methods available to the view" do + assert_equal 'Word!', render(:partial => 'test/from_helper') + end + + def from_test_case; 'Word!'; end + helper_method :from_test_case + end + + class IgnoreProtectAgainstForgeryTest < ActionView::TestCase + module HelperThatInvokesProtectAgainstForgery + def help_me + protect_against_forgery? + end + end + + helper HelperThatInvokesProtectAgainstForgery + + test "protect_from_forgery? in any helpers returns false" do + assert !view.help_me + end + + end + + class ATestHelperTest < ActionView::TestCase + include SharedTests + test_case = self + + test "inflects the name of the helper module to test from the test case class" do + assert_equal ATestHelper, test_case.helper_class + assert test_case.ancestors.include?(ATestHelper) + end + + test "a configured test controller is available" do + assert_kind_of ActionController::Base, controller + assert_equal '', controller.controller_path + end + + test "no additional helpers should shared across test cases" do + assert !test_case.ancestors.include?(AnotherTestHelper) + assert_raise(NoMethodError) { send :from_another_helper } + end + + test "is able to use routes" do + controller.request.assign_parameters(@routes, 'foo', 'index') + assert_equal '/foo', url_for + assert_equal '/bar', url_for(:controller => 'bar') + end + + test "is able to use named routes" do + with_routing do |set| + set.draw { resources :contents } + assert_equal 'http://test.host/contents/new', new_content_url + assert_equal 'http://test.host/contents/1', content_url(:id => 1) + end + end + + test "is able to use mounted routes" do + with_routing do |set| + app = Class.new do + def self.routes + @routes ||= ActionDispatch::Routing::RouteSet.new + end + + routes.draw { get "bar", :to => lambda {} } + + def self.call(*) + end + end + + set.draw { mount app => "/foo", :as => "foo_app" } + + assert_equal '/foo/bar', foo_app.bar_path + end + end + + test "named routes can be used from helper included in view" do + with_routing do |set| + set.draw { resources :contents } + _helpers.module_eval do + def render_from_helper + new_content_url + end + end + + assert_equal 'http://test.host/contents/new', render(:partial => 'test/from_helper') + end + end + + test "is able to render partials with local variables" do + assert_equal 'Eloy', render('developers/developer', :developer => stub(:name => 'Eloy')) + assert_equal 'Eloy', render(:partial => 'developers/developer', + :locals => { :developer => stub(:name => 'Eloy') }) + end + + test "is able to render partials from templates and also use instance variables" do + @controller.controller_path = "test" + + @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')] + assert_match(/Hello: EloyHello: Manfred/, render(:file => 'test/list')) + end + + test "is able to render partials from templates and also use instance variables after view has been referenced" do + @controller.controller_path = "test" + + view + + @customers = [stub(:name => 'Eloy'), stub(:name => 'Manfred')] + assert_match(/Hello: EloyHello: Manfred/, render(:file => 'test/list')) + end + + end + + class AssertionsTest < ActionView::TestCase + def render_from_helper + form_tag('/foo') do + safe_concat render(:text => '<ul><li>foo</li></ul>') + end + end + helper_method :render_from_helper + + test "uses the output_buffer for assert_select" do + render(:partial => 'test/from_helper') + + assert_select 'form' do + assert_select 'li', :text => 'foo' + end + end + end + + class RenderTemplateTest < ActionView::TestCase + test "supports specifying templates with a Regexp" do + controller.controller_path = "fun" + render(:template => "fun/games/hello_world") + assert_template %r{\Afun/games/hello_world\Z} + end + + test "supports specifying partials" do + controller.controller_path = "test" + render(:template => "test/calling_partial_with_layout") + assert_template :partial => "_partial_for_use_in_layout" + end + + test "supports specifying locals (passing)" do + controller.controller_path = "test" + render(:template => "test/calling_partial_with_layout") + assert_template :partial => "_partial_for_use_in_layout", :locals => { :name => "David" } + end + + test "supports specifying locals (failing)" do + controller.controller_path = "test" + render(:template => "test/calling_partial_with_layout") + assert_raise ActiveSupport::TestCase::Assertion, /Somebody else.*David/m do + assert_template :partial => "_partial_for_use_in_layout", :locals => { :name => "Somebody Else" } + end + end + + test 'supports different locals on the same partial' do + controller.controller_path = "test" + render(:template => "test/render_two_partials") + assert_template partial: '_partial', locals: { 'first' => '1' } + assert_template partial: '_partial', locals: { 'second' => '2' } + end + + test 'raises descriptive error message when template was not rendered' do + controller.controller_path = "test" + render(template: "test/hello_world_with_partial") + e = assert_raise ActiveSupport::TestCase::Assertion do + assert_template partial: 'i_was_never_rendered', locals: { 'did_not' => 'happen' } + end + assert_match "i_was_never_rendered to be rendered but it was not.", e.message + assert_match 'Expected ["/test/partial"] to include "i_was_never_rendered"', e.message + end + + test 'specifying locals works when the partial is inside a directory with underline prefix' do + controller.controller_path = "test" + render(template: 'test/render_partial_inside_directory') + assert_template partial: 'test/_directory/_partial_with_locales', locals: { 'name' => 'Jane' } + end + + test 'specifying locals works when the partial is inside a directory without underline prefix' do + controller.controller_path = "test" + render(template: 'test/render_partial_inside_directory') + assert_template partial: 'test/_directory/partial_with_locales', locals: { 'name' => 'Jane' } + end + end + + module AHelperWithInitialize + def initialize(*) + super + @called_initialize = true + end + end + + class AHelperWithInitializeTest < ActionView::TestCase + test "the helper's initialize was actually called" do + assert @called_initialize + end + end +end diff --git a/actionview/test/template/test_test.rb b/actionview/test/template/test_test.rb new file mode 100644 index 0000000000..108a674d95 --- /dev/null +++ b/actionview/test/template/test_test.rb @@ -0,0 +1,80 @@ +require 'abstract_unit' + +module PeopleHelper + def title(text) + content_tag(:h1, text) + end + + def homepage_path + people_path + end + + def homepage_url + people_url + end + + def link_to_person(person) + link_to person.name, person + end +end + +class PeopleHelperTest < ActionView::TestCase + def test_title + assert_equal "<h1>Ruby on Rails</h1>", title("Ruby on Rails") + end + + def test_homepage_path + with_test_route_set do + assert_equal "/people", homepage_path + end + end + + def test_homepage_url + with_test_route_set do + assert_equal "http://test.host/people", homepage_url + end + end + + def test_link_to_person + with_test_route_set do + person = mock(:name => "David") + person.class.extend ActiveModel::Naming + expects(:mocha_mock_path).with(person).returns("/people/1") + assert_equal '<a href="/people/1">David</a>', link_to_person(person) + end + end + + private + def with_test_route_set + with_routing do |set| + set.draw do + get 'people', :to => 'people#index', :as => :people + end + yield + end + end +end + +class CrazyHelperTest < ActionView::TestCase + tests PeopleHelper + + def test_helper_class_can_be_set_manually_not_just_inferred + assert_equal PeopleHelper, self.class.helper_class + end +end + +class CrazySymbolHelperTest < ActionView::TestCase + tests :people + + def test_set_helper_class_using_symbol + assert_equal PeopleHelper, self.class.helper_class + end +end + +class CrazyStringHelperTest < ActionView::TestCase + tests 'people' + + def test_set_helper_class_using_string + assert_equal PeopleHelper, self.class.helper_class + end +end diff --git a/actionview/test/template/testing/fixture_resolver_test.rb b/actionview/test/template/testing/fixture_resolver_test.rb new file mode 100644 index 0000000000..9649f349cb --- /dev/null +++ b/actionview/test/template/testing/fixture_resolver_test.rb @@ -0,0 +1,18 @@ +require 'abstract_unit' + +class FixtureResolverTest < ActiveSupport::TestCase + def test_should_return_empty_list_for_unknown_path + resolver = ActionView::FixtureResolver.new() + templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []}) + assert_equal [], templates, "expected an empty list of templates" + end + + def test_should_return_template_for_declared_path + resolver = ActionView::FixtureResolver.new("arbitrary/path.erb" => "this text") + templates = resolver.find_all("path", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => [:erb]}) + assert_equal 1, templates.size, "expected one template" + assert_equal "this text", templates.first.source + assert_equal "arbitrary/path", templates.first.virtual_path + assert_equal [:html], templates.first.formats + end +end diff --git a/actionview/test/template/testing/null_resolver_test.rb b/actionview/test/template/testing/null_resolver_test.rb new file mode 100644 index 0000000000..55ec36e753 --- /dev/null +++ b/actionview/test/template/testing/null_resolver_test.rb @@ -0,0 +1,12 @@ +require 'abstract_unit' + +class NullResolverTest < ActiveSupport::TestCase + def test_should_return_template_for_any_path + resolver = ActionView::NullResolver.new() + templates = resolver.find_all("path.erb", "arbitrary", false, {:locale => [], :formats => [:html], :handlers => []}) + assert_equal 1, templates.size, "expected one template" + assert_equal "Template generated by Null Resolver", templates.first.source + assert_equal "arbitrary/path.erb", templates.first.virtual_path.to_s + assert_equal [:html], templates.first.formats + end +end diff --git a/actionview/test/template/text_helper_test.rb b/actionview/test/template/text_helper_test.rb new file mode 100644 index 0000000000..1b2234f4e2 --- /dev/null +++ b/actionview/test/template/text_helper_test.rb @@ -0,0 +1,467 @@ +# encoding: utf-8 +require 'abstract_unit' + +class TextHelperTest < ActionView::TestCase + tests ActionView::Helpers::TextHelper + + def setup + super + # This simulates the fact that instance variables are reset every time + # a view is rendered. The cycle helper depends on this behavior. + @_cycles = nil if (defined? @_cycles) + end + + def test_concat + self.output_buffer = 'foo' + assert_equal 'foobar', concat('bar') + assert_equal 'foobar', output_buffer + end + + def test_simple_format_should_be_html_safe + assert simple_format("<b> test with html tags </b>").html_safe? + end + + def test_simple_format + assert_equal "<p></p>", simple_format(nil) + + assert_equal "<p>crazy\n<br /> cross\n<br /> platform linebreaks</p>", simple_format("crazy\r\n cross\r platform linebreaks") + assert_equal "<p>A paragraph</p>\n\n<p>and another one!</p>", simple_format("A paragraph\n\nand another one!") + assert_equal "<p>A paragraph\n<br /> With a newline</p>", simple_format("A paragraph\n With a newline") + + text = "A\nB\nC\nD".freeze + assert_equal "<p>A\n<br />B\n<br />C\n<br />D</p>", simple_format(text) + + text = "A\r\n \nB\n\n\r\n\t\nC\nD".freeze + assert_equal "<p>A\n<br /> \n<br />B</p>\n\n<p>\t\n<br />C\n<br />D</p>", simple_format(text) + + assert_equal %q(<p class="test">This is a classy test</p>), simple_format("This is a classy test", :class => 'test') + assert_equal %Q(<p class="test">para 1</p>\n\n<p class="test">para 2</p>), simple_format("para 1\n\npara 2", :class => 'test') + end + + def test_simple_format_should_sanitize_input_when_sanitize_option_is_not_false + assert_equal "<p><b> test with unsafe string </b></p>", simple_format("<b> test with unsafe string </b><script>code!</script>") + end + + def test_simple_format_should_not_sanitize_input_when_sanitize_option_is_false + assert_equal "<p><b> test with unsafe string </b><script>code!</script></p>", simple_format("<b> test with unsafe string </b><script>code!</script>", {}, :sanitize => false) + end + + def test_simple_format_with_custom_wrapper + assert_equal "<div></div>", simple_format(nil, {}, :wrapper_tag => "div") + end + + def test_simple_format_with_custom_wrapper_and_multi_line_breaks + assert_equal "<div>We want to put a wrapper...</div>\n\n<div>...right there.</div>", simple_format("We want to put a wrapper...\n\n...right there.", {}, :wrapper_tag => "div") + end + + def test_simple_format_should_not_change_the_text_passed + text = "<b>Ok</b><script>code!</script>" + text_clone = text.dup + simple_format(text) + assert_equal text_clone, text + end + + def test_simple_format_does_not_modify_the_html_options_hash + options = { :class => "foobar"} + passed_options = options.dup + simple_format("some text", passed_options) + assert_equal options, passed_options + end + + def test_simple_format_does_not_modify_the_options_hash + options = { :wrapper_tag => :div, :sanitize => false } + passed_options = options.dup + simple_format("some text", {}, passed_options) + assert_equal options, passed_options + end + + def test_truncate + assert_equal "Hello World!", truncate("Hello World!", :length => 12) + assert_equal "Hello Wor...", truncate("Hello World!!", :length => 12) + end + + def test_truncate_should_use_default_length_of_30 + str = "This is a string that will go longer then the default truncate length of 30" + assert_equal str[0...27] + "...", truncate(str) + end + + def test_truncate_with_options_hash + assert_equal "This is a string that wil[...]", truncate("This is a string that will go longer then the default truncate length of 30", :omission => "[...]") + assert_equal "Hello W...", truncate("Hello World!", :length => 10) + assert_equal "Hello[...]", truncate("Hello World!", :omission => "[...]", :length => 10) + assert_equal "Hello[...]", truncate("Hello Big World!", :omission => "[...]", :length => 13, :separator => ' ') + assert_equal "Hello Big[...]", truncate("Hello Big World!", :omission => "[...]", :length => 14, :separator => ' ') + assert_equal "Hello Big[...]", truncate("Hello Big World!", :omission => "[...]", :length => 15, :separator => ' ') + end + + def test_truncate_multibyte + assert_equal "\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 ...".force_encoding(Encoding::UTF_8), + truncate("\354\225\204\353\246\254\353\236\221 \354\225\204\353\246\254 \354\225\204\353\235\274\353\246\254\354\230\244".force_encoding(Encoding::UTF_8), :length => 10) + end + + def test_truncate_does_not_modify_the_options_hash + options = { :length => 10 } + passed_options = options.dup + truncate("some text", passed_options) + assert_equal options, passed_options + end + + def test_truncate_with_link_options + assert_equal "Here is a long test and ...<a href=\"#\">Continue</a>", + truncate("Here is a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + end + + def test_truncate_should_be_html_safe + assert truncate("Hello World!", :length => 12).html_safe? + end + + def test_truncate_should_escape_the_input + assert_equal "Hello &lt;sc...", truncate("Hello <script>code!</script>World!!", :length => 12) + end + + def test_truncate_should_not_escape_the_input_with_escape_false + assert_equal "Hello <sc...", truncate("Hello <script>code!</script>World!!", :length => 12, :escape => false) + end + + def test_truncate_with_escape_false_should_be_html_safe + truncated = truncate("Hello <script>code!</script>World!!", :length => 12, :escape => false) + assert truncated.html_safe? + end + + def test_truncate_with_block_should_be_html_safe + truncated = truncate("Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + assert truncated.html_safe? + end + + def test_truncate_with_block_should_escape_the_input + assert_equal "&lt;script&gt;code!&lt;/script&gt;He...<a href=\"#\">Continue</a>", + truncate("<script>code!</script>Here's a long test and I need a continue to read link", :length => 27) { link_to 'Continue', '#' } + end + + def test_truncate_with_block_should_not_escape_the_input_with_escape_false + assert_equal "<script>code!</script>He...<a href=\"#\">Continue</a>", + truncate("<script>code!</script>Here's a long test and I need a continue to read link", :length => 27, :escape => false) { link_to 'Continue', '#' } + end + + def test_truncate_with_block_with_escape_false_should_be_html_safe + truncated = truncate("<script>code!</script>Here's a long test and I need a continue to read link", :length => 27, :escape => false) { link_to 'Continue', '#' } + assert truncated.html_safe? + end + + def test_truncate_with_block_should_escape_the_block + assert_equal "Here is a long test and ...&lt;script&gt;alert(&#39;foo&#39;);&lt;/script&gt;", + truncate("Here is a long test and I need a continue to read link", :length => 27) { "<script>alert('foo');</script>" } + end + + def test_highlight_should_be_html_safe + assert highlight("This is a beautiful morning", "beautiful").html_safe? + end + + def test_highlight + assert_equal( + "This is a <mark>beautiful</mark> morning", + highlight("This is a beautiful morning", "beautiful") + ) + + assert_equal( + "This is a <mark>beautiful</mark> morning, but also a <mark>beautiful</mark> day", + highlight("This is a beautiful morning, but also a beautiful day", "beautiful") + ) + + assert_equal( + "This is a <b>beautiful</b> morning, but also a <b>beautiful</b> day", + highlight("This is a beautiful morning, but also a beautiful day", "beautiful", :highlighter => '<b>\1</b>') + ) + + assert_equal( + "This text is not changed because we supplied an empty phrase", + highlight("This text is not changed because we supplied an empty phrase", nil) + ) + + assert_equal ' ', highlight(' ', 'blank text is returned verbatim') + end + + def test_highlight_should_sanitize_input + assert_equal( + "This is a <mark>beautiful</mark> morning", + highlight("This is a beautiful morning<script>code!</script>", "beautiful") + ) + end + + def test_highlight_should_not_sanitize_if_sanitize_option_if_false + assert_equal( + "This is a <mark>beautiful</mark> morning<script>code!</script>", + highlight("This is a beautiful morning<script>code!</script>", "beautiful", :sanitize => false) + ) + end + + def test_highlight_with_regexp + assert_equal( + "This is a <mark>beautiful!</mark> morning", + highlight("This is a beautiful! morning", "beautiful!") + ) + + assert_equal( + "This is a <mark>beautiful! morning</mark>", + highlight("This is a beautiful! morning", "beautiful! morning") + ) + + assert_equal( + "This is a <mark>beautiful? morning</mark>", + highlight("This is a beautiful? morning", "beautiful? morning") + ) + end + + def test_highlight_with_multiple_phrases_in_one_pass + assert_equal %(<em>wow</em> <em>em</em>), highlight('wow em', %w(wow em), :highlighter => '<em>\1</em>') + end + + def test_highlight_with_html + assert_equal( + "<p>This is a <mark>beautiful</mark> morning, but also a <mark>beautiful</mark> day</p>", + highlight("<p>This is a beautiful morning, but also a beautiful day</p>", "beautiful") + ) + assert_equal( + "<p>This is a <em><mark>beautiful</mark></em> morning, but also a <mark>beautiful</mark> day</p>", + highlight("<p>This is a <em>beautiful</em> morning, but also a beautiful day</p>", "beautiful") + ) + assert_equal( + "<p>This is a <em class=\"error\"><mark>beautiful</mark></em> morning, but also a <mark>beautiful</mark> <span class=\"last\">day</span></p>", + highlight("<p>This is a <em class=\"error\">beautiful</em> morning, but also a beautiful <span class=\"last\">day</span></p>", "beautiful") + ) + assert_equal( + "<p class=\"beautiful\">This is a <mark>beautiful</mark> morning, but also a <mark>beautiful</mark> day</p>", + highlight("<p class=\"beautiful\">This is a beautiful morning, but also a beautiful day</p>", "beautiful") + ) + assert_equal( + "<p>This is a <mark>beautiful</mark> <a href=\"http://example.com/beautiful#top?what=beautiful%20morning&amp;when=now+then\">morning</a>, but also a <mark>beautiful</mark> day</p>", + highlight("<p>This is a beautiful <a href=\"http://example.com/beautiful\#top?what=beautiful%20morning&when=now+then\">morning</a>, but also a beautiful day</p>", "beautiful") + ) + assert_equal( + "<div>abc <b>div</b></div>", + highlight("<div>abc div</div>", "div", :highlighter => '<b>\1</b>') + ) + end + + def test_highlight_does_not_modify_the_options_hash + options = { :highlighter => '<b>\1</b>', :sanitize => false } + passed_options = options.dup + highlight("<div>abc div</div>", "div", passed_options) + assert_equal options, passed_options + end + + def test_excerpt + assert_equal("...is a beautiful morn...", excerpt("This is a beautiful morning", "beautiful", :radius => 5)) + assert_equal("This is a...", excerpt("This is a beautiful morning", "this", :radius => 5)) + assert_equal("...iful morning", excerpt("This is a beautiful morning", "morning", :radius => 5)) + assert_nil excerpt("This is a beautiful morning", "day") + end + + def test_excerpt_should_not_be_html_safe + assert !excerpt('This is a beautiful! morning', 'beautiful', :radius => 5).html_safe? + end + + def test_excerpt_in_borderline_cases + assert_equal("", excerpt("", "", :radius => 0)) + assert_equal("a", excerpt("a", "a", :radius => 0)) + assert_equal("...b...", excerpt("abc", "b", :radius => 0)) + assert_equal("abc", excerpt("abc", "b", :radius => 1)) + assert_equal("abc...", excerpt("abcd", "b", :radius => 1)) + assert_equal("...abc", excerpt("zabc", "b", :radius => 1)) + assert_equal("...abc...", excerpt("zabcd", "b", :radius => 1)) + assert_equal("zabcd", excerpt("zabcd", "b", :radius => 2)) + + # excerpt strips the resulting string before ap-/prepending excerpt_string. + # whether this behavior is meaningful when excerpt_string is not to be + # appended is questionable. + assert_equal("zabcd", excerpt(" zabcd ", "b", :radius => 4)) + assert_equal("...abc...", excerpt("z abc d", "b", :radius => 1)) + end + + def test_excerpt_with_regex + assert_equal('...is a beautiful! mor...', excerpt('This is a beautiful! morning', 'beautiful', :radius => 5)) + assert_equal('...is a beautiful? mor...', excerpt('This is a beautiful? morning', 'beautiful', :radius => 5)) + end + + def test_excerpt_with_omission + assert_equal("[...]is a beautiful morn[...]", excerpt("This is a beautiful morning", "beautiful", :omission => "[...]",:radius => 5)) + assert_equal( + "This is the ultimate supercalifragilisticexpialidoceous very looooooooooooooooooong looooooooooooong beautiful morning with amazing sunshine and awesome tempera[...]", + excerpt("This is the ultimate supercalifragilisticexpialidoceous very looooooooooooooooooong looooooooooooong beautiful morning with amazing sunshine and awesome temperatures. So what are you gonna do about it?", "very", + :omission => "[...]") + ) + end + + def test_excerpt_with_utf8 + assert_equal("...\357\254\203ciency could not be...".force_encoding(Encoding::UTF_8), excerpt("That's why e\357\254\203ciency could not be helped".force_encoding(Encoding::UTF_8), 'could', :radius => 8)) + end + + def test_excerpt_does_not_modify_the_options_hash + options = { :omission => "[...]",:radius => 5 } + passed_options = options.dup + excerpt("This is a beautiful morning", "beautiful", passed_options) + assert_equal options, passed_options + end + + def test_excerpt_with_separator + options = { :separator => ' ', :radius => 1 } + assert_equal('...a very beautiful...', excerpt('This is a very beautiful morning', 'very', options)) + assert_equal('This is...', excerpt('This is a very beautiful morning', 'this', options)) + assert_equal('...beautiful morning', excerpt('This is a very beautiful morning', 'morning', options)) + + options = { :separator => "\n", :radius => 0 } + assert_equal("...very long...", excerpt("my very\nvery\nvery long\nstring", 'long', options)) + + options = { :separator => "\n", :radius => 1 } + assert_equal("...very\nvery long\nstring", excerpt("my very\nvery\nvery long\nstring", 'long', options)) + end + + def test_word_wrap + assert_equal("my very very\nvery long\nstring", word_wrap("my very very very long string", :line_width => 15)) + end + + def test_word_wrap_with_extra_newlines + assert_equal("my very very\nvery long\nstring\n\nwith another\nline", word_wrap("my very very very long string\n\nwith another line", :line_width => 15)) + end + + def test_word_wrap_does_not_modify_the_options_hash + options = { :line_width => 15 } + passed_options = options.dup + word_wrap("some text", passed_options) + assert_equal options, passed_options + end + + def test_pluralization + assert_equal("1 count", pluralize(1, "count")) + assert_equal("2 counts", pluralize(2, "count")) + assert_equal("1 count", pluralize('1', "count")) + assert_equal("2 counts", pluralize('2', "count")) + assert_equal("1,066 counts", pluralize('1,066', "count")) + assert_equal("1.25 counts", pluralize('1.25', "count")) + assert_equal("1.0 count", pluralize('1.0', "count")) + assert_equal("1.00 count", pluralize('1.00', "count")) + assert_equal("2 counters", pluralize(2, "count", "counters")) + assert_equal("0 counters", pluralize(nil, "count", "counters")) + assert_equal("2 people", pluralize(2, "person")) + assert_equal("10 buffaloes", pluralize(10, "buffalo")) + assert_equal("1 berry", pluralize(1, "berry")) + assert_equal("12 berries", pluralize(12, "berry")) + end + + def test_cycle_class + value = Cycle.new("one", 2, "3") + assert_equal("one", value.to_s) + assert_equal("2", value.to_s) + assert_equal("3", value.to_s) + assert_equal("one", value.to_s) + value.reset + assert_equal("one", value.to_s) + assert_equal("2", value.to_s) + assert_equal("3", value.to_s) + end + + def test_cycle_class_with_no_arguments + assert_raise(ArgumentError) { Cycle.new } + end + + def test_cycle + assert_equal("one", cycle("one", 2, "3")) + assert_equal("2", cycle("one", 2, "3")) + assert_equal("3", cycle("one", 2, "3")) + assert_equal("one", cycle("one", 2, "3")) + assert_equal("2", cycle("one", 2, "3")) + assert_equal("3", cycle("one", 2, "3")) + end + + def test_cycle_with_no_arguments + assert_raise(ArgumentError) { cycle } + end + + def test_cycle_resets_with_new_values + assert_equal("even", cycle("even", "odd")) + assert_equal("odd", cycle("even", "odd")) + assert_equal("even", cycle("even", "odd")) + assert_equal("1", cycle(1, 2, 3)) + assert_equal("2", cycle(1, 2, 3)) + assert_equal("3", cycle(1, 2, 3)) + assert_equal("1", cycle(1, 2, 3)) + end + + def test_named_cycles + assert_equal("1", cycle(1, 2, 3, :name => "numbers")) + assert_equal("red", cycle("red", "blue", :name => "colors")) + assert_equal("2", cycle(1, 2, 3, :name => "numbers")) + assert_equal("blue", cycle("red", "blue", :name => "colors")) + assert_equal("3", cycle(1, 2, 3, :name => "numbers")) + assert_equal("red", cycle("red", "blue", :name => "colors")) + end + + def test_current_cycle_with_default_name + cycle("even","odd") + assert_equal "even", current_cycle + cycle("even","odd") + assert_equal "odd", current_cycle + cycle("even","odd") + assert_equal "even", current_cycle + end + + def test_current_cycle_with_named_cycles + cycle("red", "blue", :name => "colors") + assert_equal "red", current_cycle("colors") + cycle("red", "blue", :name => "colors") + assert_equal "blue", current_cycle("colors") + cycle("red", "blue", :name => "colors") + assert_equal "red", current_cycle("colors") + end + + def test_current_cycle_safe_call + assert_nothing_raised { current_cycle } + assert_nothing_raised { current_cycle("colors") } + end + + def test_current_cycle_with_more_than_two_names + cycle(1,2,3) + assert_equal "1", current_cycle + cycle(1,2,3) + assert_equal "2", current_cycle + cycle(1,2,3) + assert_equal "3", current_cycle + cycle(1,2,3) + assert_equal "1", current_cycle + end + + def test_default_named_cycle + assert_equal("1", cycle(1, 2, 3)) + assert_equal("2", cycle(1, 2, 3, :name => "default")) + assert_equal("3", cycle(1, 2, 3)) + end + + def test_reset_cycle + assert_equal("1", cycle(1, 2, 3)) + assert_equal("2", cycle(1, 2, 3)) + reset_cycle + assert_equal("1", cycle(1, 2, 3)) + end + + def test_reset_unknown_cycle + reset_cycle("colors") + end + + def test_recet_named_cycle + assert_equal("1", cycle(1, 2, 3, :name => "numbers")) + assert_equal("red", cycle("red", "blue", :name => "colors")) + reset_cycle("numbers") + assert_equal("1", cycle(1, 2, 3, :name => "numbers")) + assert_equal("blue", cycle("red", "blue", :name => "colors")) + assert_equal("2", cycle(1, 2, 3, :name => "numbers")) + assert_equal("red", cycle("red", "blue", :name => "colors")) + end + + def test_cycle_no_instance_variable_clashes + @cycles = %w{Specialized Fuji Giant} + assert_equal("red", cycle("red", "blue")) + assert_equal("blue", cycle("red", "blue")) + assert_equal("red", cycle("red", "blue")) + assert_equal(%w{Specialized Fuji Giant}, @cycles) + end +end diff --git a/actionview/test/template/translation_helper_test.rb b/actionview/test/template/translation_helper_test.rb new file mode 100644 index 0000000000..d496dbb35e --- /dev/null +++ b/actionview/test/template/translation_helper_test.rb @@ -0,0 +1,138 @@ +require 'abstract_unit' + +class TranslationHelperTest < ActiveSupport::TestCase + include ActionView::Helpers::TagHelper + include ActionView::Helpers::TranslationHelper + + attr_reader :request, :view + + def setup + I18n.backend.store_translations(:en, + :translations => { + :templates => { + :found => { :foo => 'Foo' }, + :array => { :foo => { :bar => 'Foo Bar' } }, + :default => { :foo => 'Foo' } + }, + :foo => 'Foo', + :hello => '<a>Hello World</a>', + :html => '<a>Hello World</a>', + :hello_html => '<a>Hello World</a>', + :interpolated_html => '<a>Hello %{word}</a>', + :array_html => %w(foo bar), + :array => %w(foo bar), + :count_html => { + :one => '<a>One %{count}</a>', + :other => '<a>Other %{count}</a>' + } + } + ) + @view = ::ActionView::Base.new(ActionController::Base.view_paths, {}) + end + + def test_delegates_to_i18n_setting_the_rescue_format_option_to_html + I18n.expects(:translate).with(:foo, :locale => 'en', :rescue_format => :html).returns("") + translate :foo, :locale => 'en' + end + + def test_delegates_localize_to_i18n + @time = Time.utc(2008, 7, 8, 12, 18, 38) + I18n.expects(:localize).with(@time) + localize @time + end + + def test_returns_missing_translation_message_wrapped_into_span + expected = '<span class="translation_missing" title="translation missing: en.translations.missing">Missing</span>' + assert_equal expected, translate(:"translations.missing") + assert_equal true, translate(:"translations.missing").html_safe? + end + + def test_returns_missing_translation_message_using_nil_as_rescue_format + expected = 'translation missing: en.translations.missing' + assert_equal expected, translate(:"translations.missing", :rescue_format => nil) + assert_equal false, translate(:"translations.missing", :rescue_format => nil).html_safe? + end + + def test_i18n_translate_defaults_to_nil_rescue_format + expected = 'translation missing: en.translations.missing' + assert_equal expected, I18n.translate(:"translations.missing") + assert_equal false, I18n.translate(:"translations.missing").html_safe? + end + + def test_translation_returning_an_array + expected = %w(foo bar) + assert_equal expected, translate(:"translations.array") + end + + def test_finds_translation_scoped_by_partial + assert_equal 'Foo', view.render(:file => 'translations/templates/found').strip + end + + def test_finds_array_of_translations_scoped_by_partial + assert_equal 'Foo Bar', @view.render(:file => 'translations/templates/array').strip + end + + def test_default_lookup_scoped_by_partial + assert_equal 'Foo', view.render(:file => 'translations/templates/default').strip + end + + def test_missing_translation_scoped_by_partial + expected = '<span class="translation_missing" title="translation missing: en.translations.templates.missing.missing">Missing</span>' + assert_equal expected, view.render(:file => 'translations/templates/missing').strip + end + + def test_translate_does_not_mark_plain_text_as_safe_html + assert_equal false, translate(:'translations.hello').html_safe? + end + + def test_translate_marks_translations_named_html_as_safe_html + assert translate(:'translations.html').html_safe? + end + + def test_translate_marks_translations_with_a_html_suffix_as_safe_html + assert translate(:'translations.hello_html').html_safe? + end + + def test_translate_escapes_interpolations_in_translations_with_a_html_suffix + assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => '<World>') + assert_equal '<a>Hello &lt;World&gt;</a>', translate(:'translations.interpolated_html', :word => stub(:to_s => "<World>")) + end + + def test_translate_with_html_count + assert_equal '<a>One 1</a>', translate(:'translations.count_html', :count => 1) + assert_equal '<a>Other 2</a>', translate(:'translations.count_html', :count => 2) + assert_equal '<a>Other &lt;One&gt;</a>', translate(:'translations.count_html', :count => '<One>') + end + + def test_translation_returning_an_array_ignores_html_suffix + assert_equal ["foo", "bar"], translate(:'translations.array_html') + end + + def test_translate_with_default_named_html + translation = translate(:'translations.missing', :default => :'translations.hello_html') + assert_equal '<a>Hello World</a>', translation + assert_equal true, translation.html_safe? + end + + def test_translate_with_two_defaults_named_html + translation = translate(:'translations.missing', :default => [:'translations.missing_html', :'translations.hello_html']) + assert_equal '<a>Hello World</a>', translation + assert_equal true, translation.html_safe? + end + + def test_translate_with_last_default_named_html + translation = translate(:'translations.missing', :default => [:'translations.missing', :'translations.hello_html']) + assert_equal '<a>Hello World</a>', translation + assert_equal true, translation.html_safe? + end + + def test_translate_with_string_default + translation = translate(:'translations.missing', default: 'A Generic String') + assert_equal 'A Generic String', translation + end + + def test_translate_with_array_of_string_defaults + translation = translate(:'translations.missing', default: ['A Generic String', 'Second generic string']) + assert_equal 'A Generic String', translation + end +end diff --git a/actionview/test/template/url_helper_test.rb b/actionview/test/template/url_helper_test.rb new file mode 100644 index 0000000000..eb4349015a --- /dev/null +++ b/actionview/test/template/url_helper_test.rb @@ -0,0 +1,759 @@ +# encoding: utf-8 +require 'abstract_unit' +require 'controller/fake_controllers' + +class UrlHelperTest < ActiveSupport::TestCase + + # In a few cases, the helper proxies to 'controller' + # or request. + # + # In those cases, we'll set up a simple mock + attr_accessor :controller, :request + + cattr_accessor :request_forgery + self.request_forgery = false + + routes = ActionDispatch::Routing::RouteSet.new + routes.draw do + get "/" => "foo#bar" + get "/other" => "foo#other" + get "/article/:id" => "foo#article", :as => :article + end + + include ActionView::Helpers::UrlHelper + include routes.url_helpers + + include ActionView::Helpers::JavaScriptHelper + include ActionDispatch::Assertions::DomAssertions + include ActionView::Context + include RenderERBUtils + + setup :_prepare_context + + def hash_for(options = {}) + { controller: "foo", action: "bar" }.merge!(options) + end + alias url_hash hash_for + + def test_url_for_does_not_escape_urls + assert_equal "/?a=b&c=d", url_for(hash_for(a: :b, c: :d)) + end + + def test_url_for_with_back + referer = 'http://www.example.com/referer' + @controller = Struct.new(:request).new(Struct.new(:env).new("HTTP_REFERER" => referer)) + + assert_equal 'http://www.example.com/referer', url_for(:back) + end + + def test_url_for_with_back_and_no_referer + @controller = Struct.new(:request).new(Struct.new(:env).new({})) + assert_equal 'javascript:history.back()', url_for(:back) + end + + def test_button_to_with_straight_url + assert_dom_equal %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /></div></form>}, button_to("Hello", "http://www.example.com") + end + + def test_button_to_with_straight_url_and_request_forgery + self.request_forgery = true + + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /><input name="form_token" type="hidden" value="secret" /></div></form>}, + button_to("Hello", "http://www.example.com") + ) + ensure + self.request_forgery = false + end + + def test_button_to_with_form_class + assert_dom_equal %{<form method="post" action="http://www.example.com" class="custom-class"><div><input type="submit" value="Hello" /></div></form>}, button_to("Hello", "http://www.example.com", form_class: 'custom-class') + end + + def test_button_to_with_form_class_escapes + assert_dom_equal %{<form method="post" action="http://www.example.com" class="&lt;script&gt;evil_js&lt;/script&gt;"><div><input type="submit" value="Hello" /></div></form>}, button_to("Hello", "http://www.example.com", form_class: '<script>evil_js</script>') + end + + def test_button_to_with_query + assert_dom_equal %{<form method="post" action="http://www.example.com/q1=v1&amp;q2=v2" class="button_to"><div><input type="submit" value="Hello" /></div></form>}, button_to("Hello", "http://www.example.com/q1=v1&q2=v2") + end + + def test_button_to_with_html_safe_URL + assert_dom_equal %{<form method="post" action="http://www.example.com/q1=v1&amp;q2=v2" class="button_to"><div><input type="submit" value="Hello" /></div></form>}, button_to("Hello", "http://www.example.com/q1=v1&amp;q2=v2".html_safe) + end + + def test_button_to_with_query_and_no_name + assert_dom_equal %{<form method="post" action="http://www.example.com?q1=v1&amp;q2=v2" class="button_to"><div><input type="submit" value="http://www.example.com?q1=v1&amp;q2=v2" /></div></form>}, button_to(nil, "http://www.example.com?q1=v1&q2=v2") + end + + def test_button_to_with_javascript_confirm + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><input data-confirm="Are you sure?" type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", data: { confirm: "Are you sure?" }) + ) + end + + def test_button_to_with_javascript_disable_with + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><input data-disable-with="Greeting..." type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", data: { disable_with: "Greeting..." }) + ) + end + + def test_button_to_with_remote_and_form_options + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="custom-class" data-remote="true" data-type="json"><div><input type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", remote: true, form: { class: "custom-class", "data-type" => "json" }) + ) + end + + def test_button_to_with_remote_and_javascript_confirm + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to" data-remote="true"><div><input data-confirm="Are you sure?" type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", remote: true, data: { confirm: "Are you sure?" }) + ) + end + + def test_button_to_with_remote_and_javascript_disable_with + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to" data-remote="true"><div><input data-disable-with="Greeting..." type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", remote: true, data: { disable_with: "Greeting..." }) + ) + end + + def test_button_to_with_remote_false + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", remote: false) + ) + end + + def test_button_to_enabled_disabled + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", disabled: false) + ) + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><input disabled="disabled" type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", disabled: true) + ) + end + + def test_button_to_with_method_delete + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><input type="hidden" name="_method" value="delete" /><input type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", method: :delete) + ) + end + + def test_button_to_with_method_get + assert_dom_equal( + %{<form method="get" action="http://www.example.com" class="button_to"><div><input type="submit" value="Hello" /></div></form>}, + button_to("Hello", "http://www.example.com", method: :get) + ) + end + + def test_button_to_with_block + assert_dom_equal( + %{<form method="post" action="http://www.example.com" class="button_to"><div><button type="submit"><span>Hello</span></button></div></form>}, + button_to("http://www.example.com") { content_tag(:span, 'Hello') } + ) + end + + def test_link_tag_with_straight_url + assert_dom_equal %{<a href="http://www.example.com">Hello</a>}, link_to("Hello", "http://www.example.com") + end + + def test_link_tag_without_host_option + assert_dom_equal(%{<a href="/">Test Link</a>}, link_to('Test Link', url_hash)) + end + + def test_link_tag_with_host_option + hash = hash_for(host: "www.example.com") + expected = %{<a href="http://www.example.com/">Test Link</a>} + assert_dom_equal(expected, link_to('Test Link', hash)) + end + + def test_link_tag_with_query + expected = %{<a href="http://www.example.com?q1=v1&amp;q2=v2">Hello</a>} + assert_dom_equal expected, link_to("Hello", "http://www.example.com?q1=v1&q2=v2") + end + + def test_link_tag_with_query_and_no_name + expected = %{<a href="http://www.example.com?q1=v1&amp;q2=v2">http://www.example.com?q1=v1&amp;q2=v2</a>} + assert_dom_equal expected, link_to(nil, "http://www.example.com?q1=v1&q2=v2") + end + + def test_link_tag_with_back + env = {"HTTP_REFERER" => "http://www.example.com/referer"} + @controller = Struct.new(:request).new(Struct.new(:env).new(env)) + expected = %{<a href="#{env["HTTP_REFERER"]}">go back</a>} + assert_dom_equal expected, link_to('go back', :back) + end + + def test_link_tag_with_back_and_no_referer + @controller = Struct.new(:request).new(Struct.new(:env).new({})) + link = link_to('go back', :back) + assert_dom_equal %{<a href="javascript:history.back()">go back</a>}, link + end + + def test_link_tag_with_img + link = link_to("<img src='/favicon.jpg' />".html_safe, "/") + expected = %{<a href="/"><img src='/favicon.jpg' /></a>} + assert_dom_equal expected, link + end + + def test_link_with_nil_html_options + link = link_to("Hello", url_hash, nil) + assert_dom_equal %{<a href="/">Hello</a>}, link + end + + def test_link_tag_with_custom_onclick + link = link_to("Hello", "http://www.example.com", onclick: "alert('yay!')") + expected = %{<a href="http://www.example.com" onclick="alert(&#39;yay!&#39;)">Hello</a>} + assert_dom_equal expected, link + end + + def test_link_tag_with_javascript_confirm + assert_dom_equal( + %{<a href="http://www.example.com" data-confirm="Are you sure?">Hello</a>}, + link_to("Hello", "http://www.example.com", data: { confirm: "Are you sure?" }) + ) + assert_dom_equal( + %{<a href="http://www.example.com" data-confirm="You cant possibly be sure, can you?">Hello</a>}, + link_to("Hello", "http://www.example.com", data: { confirm: "You cant possibly be sure, can you?" }) + ) + assert_dom_equal( + %{<a href="http://www.example.com" data-confirm="You cant possibly be sure,\n can you?">Hello</a>}, + link_to("Hello", "http://www.example.com", data: { confirm: "You cant possibly be sure,\n can you?" }) + ) + end + + def test_link_to_with_remote + assert_dom_equal( + %{<a href="http://www.example.com" data-remote="true">Hello</a>}, + link_to("Hello", "http://www.example.com", remote: true) + ) + end + + def test_link_to_with_remote_false + assert_dom_equal( + %{<a href="http://www.example.com">Hello</a>}, + link_to("Hello", "http://www.example.com", remote: false) + ) + end + + def test_link_to_with_symbolic_remote_in_non_html_options + assert_dom_equal( + %{<a href="/" data-remote="true">Hello</a>}, + link_to("Hello", hash_for(remote: true), {}) + ) + end + + def test_link_to_with_string_remote_in_non_html_options + assert_dom_equal( + %{<a href="/" data-remote="true">Hello</a>}, + link_to("Hello", hash_for('remote' => true), {}) + ) + end + + def test_link_tag_using_post_javascript + assert_dom_equal( + %{<a href="http://www.example.com" data-method="post" rel="nofollow">Hello</a>}, + link_to("Hello", "http://www.example.com", method: :post) + ) + end + + def test_link_tag_using_delete_javascript + assert_dom_equal( + %{<a href="http://www.example.com" rel="nofollow" data-method="delete">Destroy</a>}, + link_to("Destroy", "http://www.example.com", method: :delete) + ) + end + + def test_link_tag_using_delete_javascript_and_href + assert_dom_equal( + %{<a href="\#" rel="nofollow" data-method="delete">Destroy</a>}, + link_to("Destroy", "http://www.example.com", method: :delete, href: '#') + ) + end + + def test_link_tag_using_post_javascript_and_rel + assert_dom_equal( + %{<a href="http://www.example.com" data-method="post" rel="example nofollow">Hello</a>}, + link_to("Hello", "http://www.example.com", method: :post, rel: 'example') + ) + end + + def test_link_tag_using_post_javascript_and_confirm + assert_dom_equal( + %{<a href="http://www.example.com" data-method="post" rel="nofollow" data-confirm="Are you serious?">Hello</a>}, + link_to("Hello", "http://www.example.com", method: :post, data: { confirm: "Are you serious?" }) + ) + end + + def test_link_tag_using_delete_javascript_and_href_and_confirm + assert_dom_equal( + %{<a href="\#" rel="nofollow" data-confirm="Are you serious?" data-method="delete">Destroy</a>}, + link_to("Destroy", "http://www.example.com", method: :delete, href: '#', data: { confirm: "Are you serious?" }) + ) + end + + def test_link_tag_with_block + assert_dom_equal %{<a href="/"><span>Example site</span></a>}, + link_to('/') { content_tag(:span, 'Example site') } + end + + def test_link_tag_with_block_and_html_options + assert_dom_equal %{<a class="special" href="/"><span>Example site</span></a>}, + link_to('/', class: "special") { content_tag(:span, 'Example site') } + end + + def test_link_tag_using_block_in_erb + out = render_erb %{<%= link_to('/') do %>Example site<% end %>} + assert_equal '<a href="/">Example site</a>', out + end + + def test_link_tag_with_html_safe_string + assert_dom_equal( + %{<a href="/article/Gerd_M%C3%BCller">Gerd Müller</a>}, + link_to("Gerd Müller", article_path("Gerd_Müller".html_safe)) + ) + end + + def test_link_tag_escapes_content + assert_dom_equal %{<a href="/">Malicious &lt;script&gt;content&lt;/script&gt;</a>}, + link_to("Malicious <script>content</script>", "/") + end + + def test_link_tag_does_not_escape_html_safe_content + assert_dom_equal %{<a href="/">Malicious <script>content</script></a>}, + link_to("Malicious <script>content</script>".html_safe, "/") + end + + def test_link_to_unless + assert_equal "Showing", link_to_unless(true, "Showing", url_hash) + + assert_dom_equal %{<a href="/">Listing</a>}, + link_to_unless(false, "Listing", url_hash) + + assert_equal "Showing", link_to_unless(true, "Showing", url_hash) + + assert_equal "<strong>Showing</strong>", + link_to_unless(true, "Showing", url_hash) { |name| + "<strong>#{name}</strong>".html_safe + } + + assert_equal "test", + link_to_unless(true, "Showing", url_hash) { + "test" + } + + assert_equal %{&lt;b&gt;Showing&lt;/b&gt;}, link_to_unless(true, "<b>Showing</b>", url_hash) + assert_equal %{<a href="/">&lt;b&gt;Showing&lt;/b&gt;</a>}, link_to_unless(false, "<b>Showing</b>", url_hash) + assert_equal %{<b>Showing</b>}, link_to_unless(true, "<b>Showing</b>".html_safe, url_hash) + assert_equal %{<a href="/"><b>Showing</b></a>}, link_to_unless(false, "<b>Showing</b>".html_safe, url_hash) + end + + def test_link_to_if + assert_equal "Showing", link_to_if(false, "Showing", url_hash) + assert_dom_equal %{<a href="/">Listing</a>}, link_to_if(true, "Listing", url_hash) + assert_equal "Showing", link_to_if(false, "Showing", url_hash) + end + + def request_for_url(url, opts = {}) + env = Rack::MockRequest.env_for("http://www.example.com#{url}", opts) + ActionDispatch::Request.new(env) + end + + def test_current_page_with_http_head_method + @request = request_for_url("/", :method => :head) + assert current_page?(url_hash) + assert current_page?("http://www.example.com/") + end + + def test_current_page_with_simple_url + @request = request_for_url("/") + assert current_page?(url_hash) + assert current_page?("http://www.example.com/") + end + + def test_current_page_ignoring_params + @request = request_for_url("/?order=desc&page=1") + + assert current_page?(url_hash) + assert current_page?("http://www.example.com/") + end + + def test_current_page_with_params_that_match + @request = request_for_url("/?order=desc&page=1") + + assert current_page?(hash_for(order: "desc", page: "1")) + assert current_page?("http://www.example.com/?order=desc&page=1") + end + + def test_current_page_with_not_get_verb + @request = request_for_url("/events", method: :post) + + assert !current_page?('/events') + end + + def test_link_unless_current + @request = request_for_url("/") + + assert_equal "Showing", + link_to_unless_current("Showing", url_hash) + assert_equal "Showing", + link_to_unless_current("Showing", "http://www.example.com/") + + @request = request_for_url("/?order=desc") + + assert_equal "Showing", + link_to_unless_current("Showing", url_hash) + assert_equal "Showing", + link_to_unless_current("Showing", "http://www.example.com/") + + @request = request_for_url("/?order=desc&page=1") + + assert_equal "Showing", + link_to_unless_current("Showing", hash_for(order: 'desc', page: '1')) + assert_equal "Showing", + link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=1") + + @request = request_for_url("/?order=desc") + + assert_equal %{<a href="/?order=asc">Showing</a>}, + link_to_unless_current("Showing", hash_for(order: :asc)) + assert_equal %{<a href="http://www.example.com/?order=asc">Showing</a>}, + link_to_unless_current("Showing", "http://www.example.com/?order=asc") + + @request = request_for_url("/?order=desc") + assert_equal %{<a href="/?order=desc&amp;page=2\">Showing</a>}, + link_to_unless_current("Showing", hash_for(order: "desc", page: 2)) + assert_equal %{<a href="http://www.example.com/?order=desc&amp;page=2">Showing</a>}, + link_to_unless_current("Showing", "http://www.example.com/?order=desc&page=2") + + @request = request_for_url("/show") + + assert_equal %{<a href="/">Listing</a>}, + link_to_unless_current("Listing", url_hash) + assert_equal %{<a href="http://www.example.com/">Listing</a>}, + link_to_unless_current("Listing", "http://www.example.com/") + end + + def test_mail_to + assert_dom_equal %{<a href="mailto:david@loudthinking.com">david@loudthinking.com</a>}, mail_to("david@loudthinking.com") + assert_dom_equal %{<a href="mailto:david@loudthinking.com">David Heinemeier Hansson</a>}, mail_to("david@loudthinking.com", "David Heinemeier Hansson") + assert_dom_equal( + %{<a class="admin" href="mailto:david@loudthinking.com">David Heinemeier Hansson</a>}, + mail_to("david@loudthinking.com", "David Heinemeier Hansson", "class" => "admin") + ) + assert_equal mail_to("david@loudthinking.com", "David Heinemeier Hansson", "class" => "admin"), + mail_to("david@loudthinking.com", "David Heinemeier Hansson", class: "admin") + end + + def test_mail_with_options + assert_dom_equal( + %{<a href="mailto:me@example.com?cc=ccaddress%40example.com&amp;bcc=bccaddress%40example.com&amp;body=This%20is%20the%20body%20of%20the%20message.&amp;subject=This%20is%20an%20example%20email">My email</a>}, + mail_to("me@example.com", "My email", cc: "ccaddress@example.com", bcc: "bccaddress@example.com", subject: "This is an example email", body: "This is the body of the message.") + ) + end + + def test_mail_to_with_img + assert_dom_equal %{<a href="mailto:feedback@example.com"><img src="/feedback.png" /></a>}, + mail_to('feedback@example.com', '<img src="/feedback.png" />'.html_safe) + end + + def test_mail_to_returns_html_safe_string + assert mail_to("david@loudthinking.com").html_safe? + end + + def test_mail_to_with_block + assert_dom_equal %{<a href="mailto:me@example.com"><span>Email me</span></a>}, + mail_to('me@example.com') { content_tag(:span, 'Email me') } + end + + def test_mail_to_with_block_and_options + assert_dom_equal %{<a class="special" href="mailto:me@example.com?cc=ccaddress%40example.com"><span>Email me</span></a>}, + mail_to('me@example.com', cc: "ccaddress@example.com", class: "special") { content_tag(:span, 'Email me') } + end + + def test_mail_to_does_not_modify_html_options_hash + options = { class: 'special' } + mail_to 'me@example.com', 'ME!', options + assert_equal({ class: 'special' }, options) + end + + def protect_against_forgery? + self.request_forgery + end + + def form_authenticity_token + "secret" + end + + def request_forgery_protection_token + "form_token" + end + + private + def sort_query_string_params(uri) + path, qs = uri.split('?') + qs = qs.split('&amp;').sort.join('&amp;') if qs + qs ? "#{path}?#{qs}" : path + end +end + +class UrlHelperControllerTest < ActionController::TestCase + class UrlHelperController < ActionController::Base + test_routes do + get 'url_helper_controller_test/url_helper/show/:id', + to: 'url_helper_controller_test/url_helper#show', + as: :show + + get 'url_helper_controller_test/url_helper/profile/:name', + to: 'url_helper_controller_test/url_helper#show', + as: :profile + + get 'url_helper_controller_test/url_helper/show_named_route', + to: 'url_helper_controller_test/url_helper#show_named_route', + as: :show_named_route + + get "/:controller(/:action(/:id))" + + get 'url_helper_controller_test/url_helper/normalize_recall_params', + to: UrlHelperController.action(:normalize_recall), + as: :normalize_recall_params + + get '/url_helper_controller_test/url_helper/override_url_helper/default', + to: 'url_helper_controller_test/url_helper#override_url_helper', + as: :override_url_helper + end + + def show + if params[:name] + render inline: 'ok' + else + redirect_to profile_path(params[:id]) + end + end + + def show_url_for + render inline: "<%= url_for controller: 'url_helper_controller_test/url_helper', action: 'show_url_for' %>" + end + + def show_overridden_url_for + render inline: "<%= url_for params.merge(controller: 'url_helper_controller_test/url_helper', action: 'show_url_for') %>" + end + + def show_named_route + render inline: "<%= show_named_route_#{params[:kind]} %>" + end + + def nil_url_for + render inline: '<%= url_for(nil) %>' + end + + def normalize_recall_params + render inline: '<%= normalize_recall_params_path %>' + end + + def recall_params_not_changed + render inline: '<%= url_for(action: :show_url_for) %>' + end + + def override_url_helper + render inline: '<%= override_url_helper_path %>' + end + + def override_url_helper_path + '/url_helper_controller_test/url_helper/override_url_helper/override' + end + helper_method :override_url_helper_path + end + + tests UrlHelperController + + def test_url_for_shows_only_path + get :show_url_for + assert_equal '/url_helper_controller_test/url_helper/show_url_for', @response.body + end + + def test_overridden_url_for_shows_only_path + get :show_overridden_url_for + assert_equal '/url_helper_controller_test/url_helper/show_url_for', @response.body + end + + def test_named_route_url_shows_host_and_path + get :show_named_route, kind: 'url' + assert_equal 'http://test.host/url_helper_controller_test/url_helper/show_named_route', + @response.body + end + + def test_named_route_path_shows_only_path + get :show_named_route, kind: 'path' + assert_equal '/url_helper_controller_test/url_helper/show_named_route', @response.body + end + + def test_url_for_nil_returns_current_path + get :nil_url_for + assert_equal '/url_helper_controller_test/url_helper/nil_url_for', @response.body + end + + def test_named_route_should_show_host_and_path_using_controller_default_url_options + class << @controller + def default_url_options + { host: 'testtwo.host' } + end + end + + get :show_named_route, kind: 'url' + assert_equal 'http://testtwo.host/url_helper_controller_test/url_helper/show_named_route', @response.body + end + + def test_recall_params_should_be_normalized + get :normalize_recall_params + assert_equal '/url_helper_controller_test/url_helper/normalize_recall_params', @response.body + end + + def test_recall_params_should_not_be_changed + get :recall_params_not_changed + assert_equal '/url_helper_controller_test/url_helper/show_url_for', @response.body + end + + def test_recall_params_should_normalize_id + get :show, id: '123' + assert_equal 302, @response.status + assert_equal 'http://test.host/url_helper_controller_test/url_helper/profile/123', @response.location + + get :show, name: '123' + assert_equal 'ok', @response.body + end + + def test_url_helper_can_be_overridden + get :override_url_helper + assert_equal '/url_helper_controller_test/url_helper/override_url_helper/override', @response.body + end +end + +class TasksController < ActionController::Base + test_routes do + resources :tasks + end + + def index + render_default + end + + def show + render_default + end + + protected + def render_default + render inline: "<%= link_to_unless_current('tasks', tasks_path) %>\n" + + "<%= link_to_unless_current('tasks', tasks_url) %>" + end +end + +class LinkToUnlessCurrentWithControllerTest < ActionController::TestCase + tests TasksController + + def test_link_to_unless_current_to_current + get :index + assert_equal "tasks\ntasks", @response.body + end + + def test_link_to_unless_current_shows_link + get :show, id: 1 + assert_equal %{<a href="/tasks">tasks</a>\n} + + %{<a href="#{@request.protocol}#{@request.host_with_port}/tasks">tasks</a>}, + @response.body + end +end + +class Session + extend ActiveModel::Naming + include ActiveModel::Conversion + attr_accessor :id, :workshop_id + + def initialize(id) + @id = id + end + + def persisted? + id.present? + end + + def to_s + id.to_s + end +end + +class WorkshopsController < ActionController::Base + test_routes do + resources :workshops do + resources :sessions + end + end + + def index + @workshop = Workshop.new(nil) + render inline: "<%= url_for(@workshop) %>\n<%= link_to('Workshop', @workshop) %>" + end + + def show + @workshop = Workshop.new(params[:id]) + render inline: "<%= url_for(@workshop) %>\n<%= link_to('Workshop', @workshop) %>" + end +end + +class SessionsController < ActionController::Base + test_routes do + resources :workshops do + resources :sessions + end + end + + def index + @workshop = Workshop.new(params[:workshop_id]) + @session = Session.new(nil) + render inline: "<%= url_for([@workshop, @session]) %>\n<%= link_to('Session', [@workshop, @session]) %>" + end + + def show + @workshop = Workshop.new(params[:workshop_id]) + @session = Session.new(params[:id]) + render inline: "<%= url_for([@workshop, @session]) %>\n<%= link_to('Session', [@workshop, @session]) %>" + end +end + +class PolymorphicControllerTest < ActionController::TestCase + def test_new_resource + @controller = WorkshopsController.new + + get :index + assert_equal %{/workshops\n<a href="/workshops">Workshop</a>}, @response.body + end + + def test_existing_resource + @controller = WorkshopsController.new + + get :show, id: 1 + assert_equal %{/workshops/1\n<a href="/workshops/1">Workshop</a>}, @response.body + end + + def test_new_nested_resource + @controller = SessionsController.new + + get :index, workshop_id: 1 + assert_equal %{/workshops/1/sessions\n<a href="/workshops/1/sessions">Session</a>}, @response.body + end + + def test_existing_nested_resource + @controller = SessionsController.new + + get :show, workshop_id: 1, id: 1 + assert_equal %{/workshops/1/sessions/1\n<a href="/workshops/1/sessions/1">Session</a>}, @response.body + end +end -- cgit v1.2.3