scriptorium 0.0.3 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.lt3 +324 -0
- data/README.md +3155 -1
- data/assets/.DS_Store +0 -0
- data/assets/README.md +44 -0
- data/assets/icons/social/reddit.png +0 -0
- data/assets/icons/social/x-logo.png +0 -0
- data/assets/icons/ui/.DS_Store +0 -0
- data/assets/icons/ui/back.png +0 -0
- data/assets/icons/ui/copy.png +0 -0
- data/assets/icons/ui/down.png +0 -0
- data/assets/icons/ui/end.png +0 -0
- data/assets/icons/ui/exit.png +0 -0
- data/assets/icons/ui/foo +10 -0
- data/assets/icons/ui/home.png +0 -0
- data/assets/icons/ui/left.png +0 -0
- data/assets/icons/ui/next.png +0 -0
- data/assets/icons/ui/right.png +0 -0
- data/assets/icons/ui/start.png +0 -0
- data/assets/icons/ui/up.png +0 -0
- data/assets/imagenotfound.jpg +0 -0
- data/assets/samples/placeholder.svg +9 -0
- data/assets/themes/standard/favicon.svg +6 -0
- data/bin/sblog +84 -5
- data/bin/scriptorium +1 -0
- data/doc/README.txt +6 -0
- data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +94 -0
- data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +2 -0
- data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +45 -0
- data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
- data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
- data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
- data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +35 -0
- data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +27 -0
- data/doc/anti-amnesia/20250807-213025.md +116 -0
- data/doc/anti-amnesia/20250901-211714-codemirror-integration-and-web-tests.md +172 -0
- data/doc/anti-amnesia/20250902-002402-backup-restore-system.md +126 -0
- data/doc/anti-amnesia/20250907-203339-backup-metadata-implementation.md +66 -0
- data/doc/banner_svg_config.md +114 -0
- data/doc/contrib.lt3 +8 -0
- data/doc/dependencies.md +281 -0
- data/doc/hacker.lt3 +5 -0
- data/doc/imported/0001-elixir-conf-2014/metadata.txt +7 -0
- data/doc/imported/0001-elixir-conf-2014/post.html +37 -0
- data/doc/imported/0001-elixir-conf-2014/source.lt3 +22 -0
- data/doc/imported/0002-programmers-and-word-processing/metadata.txt +7 -0
- data/doc/imported/0002-programmers-and-word-processing/post.html +192 -0
- data/doc/imported/0002-programmers-and-word-processing/source.lt3 +146 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/metadata.txt +7 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/post.html +60 -0
- data/doc/imported/0003-how-to-turn-your-brain-sideways/source.lt3 +40 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/metadata.txt +7 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/post.html +42 -0
- data/doc/imported/0004-upcoming-lone-star-ruby-conference/source.lt3 +24 -0
- data/doc/imported/0005-elixir-conf-2015-announced/metadata.txt +7 -0
- data/doc/imported/0005-elixir-conf-2015-announced/post.html +30 -0
- data/doc/imported/0005-elixir-conf-2015-announced/source.lt3 +16 -0
- data/doc/imported/0006-ruby-for-dinosaurs/metadata.txt +7 -0
- data/doc/imported/0006-ruby-for-dinosaurs/post.html +43 -0
- data/doc/imported/0006-ruby-for-dinosaurs/source.lt3 +27 -0
- data/doc/imported/0007-phoenix-isnt-rails/metadata.txt +7 -0
- data/doc/imported/0007-phoenix-isnt-rails/post.html +116 -0
- data/doc/imported/0007-phoenix-isnt-rails/source.lt3 +87 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/metadata.txt +7 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/post.html +129 -0
- data/doc/imported/0008-concerning-the-term-monkeypatching/source.lt3 +92 -0
- data/doc/imported/0009-announcement-coming-soon/metadata.txt +7 -0
- data/doc/imported/0009-announcement-coming-soon/post.html +33 -0
- data/doc/imported/0009-announcement-coming-soon/source.lt3 +19 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/metadata.txt +7 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/post.html +175 -0
- data/doc/imported/0010-immutable-data-ditching-the-wax-tablet/source.lt3 +139 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/metadata.txt +7 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/post.html +139 -0
- data/doc/imported/0011-computer-science-as-a-lost-art/source.lt3 +104 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/metadata.txt +7 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/post.html +42 -0
- data/doc/imported/0012-ruby-day-in-turin-italy/source.lt3 +24 -0
- data/doc/imported/0013-rubyday-was-a-success/metadata.txt +7 -0
- data/doc/imported/0013-rubyday-was-a-success/post.html +44 -0
- data/doc/imported/0013-rubyday-was-a-success/source.lt3 +27 -0
- data/doc/imported/0014-working-on-the-blogging-software/metadata.txt +7 -0
- data/doc/imported/0014-working-on-the-blogging-software/post.html +63 -0
- data/doc/imported/0014-working-on-the-blogging-software/source.lt3 +41 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/metadata.txt +7 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/post.html +172 -0
- data/doc/imported/0015-ok-its-not-really-a-lost-art/source.lt3 +134 -0
- data/doc/imported/0016-an-in-operator-for-ruby/metadata.txt +7 -0
- data/doc/imported/0016-an-in-operator-for-ruby/post.html +155 -0
- data/doc/imported/0016-an-in-operator-for-ruby/source.lt3 +106 -0
- data/doc/imported/0017-the-forgotten-mathematician/metadata.txt +7 -0
- data/doc/imported/0017-the-forgotten-mathematician/post.html +161 -0
- data/doc/imported/0017-the-forgotten-mathematician/source.lt3 +119 -0
- data/doc/imported/0018-ruby-puns/metadata.txt +7 -0
- data/doc/imported/0018-ruby-puns/post.html +46 -0
- data/doc/imported/0018-ruby-puns/source.lt3 +28 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/metadata.txt +7 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/post.html +138 -0
- data/doc/imported/0019-custom-exceptions-via-metaprogramming/source.lt3 +101 -0
- data/doc/imported/0020-fffff/metadata.txt +7 -0
- data/doc/imported/0020-fffff/post.html +24 -0
- data/doc/imported/0020-fffff/source.lt3 +12 -0
- data/doc/imported/0021-trying-ror-yet-again/metadata.txt +7 -0
- data/doc/imported/0021-trying-ror-yet-again/post.html +26 -0
- data/doc/imported/0021-trying-ror-yet-again/source.lt3 +12 -0
- data/doc/imported/0023-doctor-sleep/metadata.txt +7 -0
- data/doc/imported/0023-doctor-sleep/post.html +63 -0
- data/doc/imported/0023-doctor-sleep/source.lt3 +44 -0
- data/doc/imported/0024-just-a-test/metadata.txt +7 -0
- data/doc/imported/0024-just-a-test/post.html +24 -0
- data/doc/imported/0024-just-a-test/source.lt3 +12 -0
- data/doc/imported/import_summary.txt +98 -0
- data/doc/livetext-informal-spec.txt +65 -0
- data/doc/myuserdoc/ch-0.lt3 +31 -0
- data/doc/myuserdoc/ch-1.lt3 +37 -0
- data/doc/myuserdoc/ch-10.lt3 +22 -0
- data/doc/myuserdoc/ch-2.lt3 +37 -0
- data/doc/myuserdoc/ch-3.lt3 +19 -0
- data/doc/myuserdoc/ch-4.lt3 +43 -0
- data/doc/myuserdoc/ch-5.lt3 +22 -0
- data/doc/myuserdoc/ch-6.lt3 +19 -0
- data/doc/myuserdoc/ch-7.lt3 +16 -0
- data/doc/myuserdoc/ch-8.lt3 +13 -0
- data/doc/myuserdoc/ch-9.lt3 +19 -0
- data/doc/myuserdoc/tweak.rb +18 -0
- data/doc/myuserdoc/userdoc-toc.txt +88 -0
- data/doc/old-posts/0001-elixir-conf-2014.lt3 +24 -0
- data/doc/old-posts/0002-programmers-and-word-processing.lt3 +150 -0
- data/doc/old-posts/0003-how-to-turn-your-brain-sideways.lt3 +43 -0
- data/doc/old-posts/0004-upcoming-lone-star-ruby-conference.lt3 +26 -0
- data/doc/old-posts/0005-elixir-conf-2015-announced.lt3 +17 -0
- data/doc/old-posts/0006-ruby-for-dinosaurs.lt3 +30 -0
- data/doc/old-posts/0007-phoenix-isnt-rails.lt3 +90 -0
- data/doc/old-posts/0008-concerning-the-term-monkeypatching.lt3 +105 -0
- data/doc/old-posts/0009-announcement-coming-soon.lt3 +20 -0
- data/doc/old-posts/0010-immutable-data-ditching-the-wax-tablet.lt3 +142 -0
- data/doc/old-posts/0011-computer-science-as-a-lost-art.lt3 +117 -0
- data/doc/old-posts/0012-ruby-day-in-turin-italy.lt3 +26 -0
- data/doc/old-posts/0013-rubyday-was-a-success.lt3 +28 -0
- data/doc/old-posts/0014-working-on-the-blogging-software.lt3 +42 -0
- data/doc/old-posts/0015-ok-its-not-really-a-lost-art.lt3 +137 -0
- data/doc/old-posts/0016-an-in-operator-for-ruby.lt3 +142 -0
- data/doc/old-posts/0017-the-forgotten-mathematician.lt3 +129 -0
- data/doc/old-posts/0018-ruby-puns.lt3 +31 -0
- data/doc/old-posts/0019-custom-exceptions-via-metaprogramming.lt3 +116 -0
- data/doc/old-posts/0021-trying-ror-yet-again.lt3 +35 -0
- data/doc/old-posts/0023-doctor-sleep.lt3 +43 -0
- data/doc/old-posts/0024-just-a-test.lt3 +12 -0
- data/doc/old-posts/0025-trying-another-post.lt3 +12 -0
- data/doc/old-repo +1 -0
- data/doc/reddit_credentials_template.json +8 -0
- data/doc/reddit_integration.md +207 -0
- data/doc/user.lt3 +35 -0
- data/doc/user_guide_section_1.md +137 -0
- data/doc/user_guide_section_10.md +515 -0
- data/doc/user_guide_section_11.md +708 -0
- data/doc/user_guide_section_2.md +233 -0
- data/doc/user_guide_section_3.md +5 -0
- data/doc/user_guide_section_4.md +221 -0
- data/doc/user_guide_section_5.md +243 -0
- data/doc/user_guide_section_6.md +147 -0
- data/doc/user_guide_section_7.md +311 -0
- data/doc/user_guide_section_8.md +224 -0
- data/doc/user_guide_section_9.md +375 -0
- data/lib/rouge/lexers/livetext.rb +74 -0
- data/lib/scriptorium/api.rb +2373 -0
- data/lib/scriptorium/banner_svg.rb +729 -0
- data/lib/scriptorium/contract.rb +34 -0
- data/lib/scriptorium/exceptions.rb +201 -1
- data/lib/scriptorium/helpers.rb +675 -0
- data/lib/scriptorium/post.rb +259 -0
- data/lib/scriptorium/reddit.rb +83 -0
- data/lib/scriptorium/repo.rb +938 -0
- data/lib/scriptorium/standard_files.rb +149 -0
- data/lib/scriptorium/support/bootstrap/css.txt +5 -0
- data/lib/scriptorium/support/bootstrap/js.txt +4 -0
- data/lib/scriptorium/support/common_js/clipboard.js +35 -0
- data/lib/scriptorium/support/common_js/content-loader.js +187 -0
- data/lib/scriptorium/support/common_js/navigation.js +52 -0
- data/lib/scriptorium/support/common_js/syntax-highlighting.js +27 -0
- data/lib/scriptorium/support/config/reddit.txt +10 -0
- data/lib/scriptorium/support/config/reddit_template.txt +17 -0
- data/lib/scriptorium/support/config/social.txt +8 -0
- data/lib/scriptorium/support/highlight/css.txt +2 -0
- data/lib/scriptorium/support/highlight/custom.css +119 -0
- data/lib/scriptorium/support/highlight/js.txt +1 -0
- data/lib/scriptorium/support/post_index/config.txt +15 -0
- data/lib/scriptorium/support/post_index/style.css +55 -0
- data/lib/scriptorium/support/templates/index_entry.lt3 +16 -0
- data/lib/scriptorium/support/templates/initial_post.lt3 +12 -0
- data/lib/scriptorium/support/templates/layout.txt +5 -0
- data/lib/scriptorium/support/templates/post.lt3 +104 -0
- data/lib/scriptorium/support/theme/footer.lt3 +2 -0
- data/lib/scriptorium/support/theme/header.lt3 +4 -0
- data/lib/scriptorium/support/theme/left.lt3 +3 -0
- data/lib/scriptorium/support/theme/main.lt3 +5 -0
- data/lib/scriptorium/support/theme/right.lt3 +3 -0
- data/lib/scriptorium/theme.rb +192 -0
- data/lib/scriptorium/version.rb +1 -1
- data/lib/scriptorium/view.rb +1021 -0
- data/lib/scriptorium/widgets/featured_posts.rb +149 -0
- data/lib/scriptorium/widgets/links.rb +112 -0
- data/lib/scriptorium/widgets/pages.rb +133 -0
- data/lib/scriptorium/widgets/widget.rb +133 -0
- data/lib/scriptorium.rb +38 -34
- data/lib/skeleton.rb +10 -1
- data/scriptorium.gemspec +17 -5
- data/test/README.md +69 -0
- data/test/WEB_INTEGRATION_README.md +196 -0
- data/test/all +83 -0
- data/test/api_demo.rb +99 -0
- data/test/assets/imagenotfound.jpg +0 -0
- data/test/assets/images/.DS_Store +0 -0
- data/test/assets/images/README.md +27 -0
- data/test/assets/images/odd_aspect.png +0 -0
- data/test/assets/images/perfect.png +0 -0
- data/test/assets/images/small.png +0 -0
- data/test/assets/images/tall.png +0 -0
- data/test/assets/images/very_tall.png +0 -0
- data/test/assets/images/very_wide.png +0 -0
- data/test/assets/images/wide.png +0 -0
- data/test/assets/testbanner.jpg +0 -0
- data/test/banner_svg/simple_helpers.rb +13 -0
- data/test/banner_svg/unit.rb +1000 -0
- data/test/config/deployment.txt +5 -0
- data/test/ed_test.rb +204 -0
- data/test/integration/cursor_banner_combinations.rb +193 -0
- data/test/integration/cursor_banner_features.rb +374 -0
- data/test/integration/integration_test.rb +326 -0
- data/test/integration/preview_flow_test.rb +94 -0
- data/test/livetext_plugin_test.rb +500 -0
- data/test/manual/asset_mgmt.rb +67 -0
- data/test/manual/banner-tests/index.html +45 -0
- data/test/manual/banner-tests/svg.txt +3 -0
- data/test/manual/banner-tests/test01.html +122 -0
- data/test/manual/banner-tests/test02.html +122 -0
- data/test/manual/banner-tests/test03.html +122 -0
- data/test/manual/banner-tests/test04.html +129 -0
- data/test/manual/banner-tests/test05.html +129 -0
- data/test/manual/banner-tests/test06.html +129 -0
- data/test/manual/banner-tests/test07.html +129 -0
- data/test/manual/banner-tests/test08.html +123 -0
- data/test/manual/banner-tests/test09.html +123 -0
- data/test/manual/banner-tests/test10.html +123 -0
- data/test/manual/banner-tests/test11.html +123 -0
- data/test/manual/banner-tests/test12.html +123 -0
- data/test/manual/banner-tests/test13.html +123 -0
- data/test/manual/banner-tests/test14.html +123 -0
- data/test/manual/banner-tests/test15.html +122 -0
- data/test/manual/banner-tests/test16.html +122 -0
- data/test/manual/banner-tests/test17.html +122 -0
- data/test/manual/banner-tests/test18.html +132 -0
- data/test/manual/banner-tests/test19.html +132 -0
- data/test/manual/banner-tests/test20.html +132 -0
- data/test/manual/banner-tests/test21.html +132 -0
- data/test/manual/banner-tests/test22.html +132 -0
- data/test/manual/banner-tests/test23.html +132 -0
- data/test/manual/banner-tests/test24.html +132 -0
- data/test/manual/banner-tests/test25.html +131 -0
- data/test/manual/banner_environment.rb +205 -0
- data/test/manual/codemirror_demo.html +773 -0
- data/test/manual/create_posts_for_web.rb +114 -0
- data/test/manual/environment.rb +67 -0
- data/test/manual/make_banner.rb +153 -0
- data/test/manual/preview_manual_test.rb +129 -0
- data/test/manual/sample_banner_config.txt +12 -0
- data/test/manual/test_advanced_widgets.rb +73 -0
- data/test/manual/test_banner_combinations.rb +120 -0
- data/test/manual/test_banner_features.rb +306 -0
- data/test/manual/test_banner_integration.rb +115 -0
- data/test/manual/test_banner_radial.rb +87 -0
- data/test/manual/test_basic_posts.rb +47 -0
- data/test/manual/test_layout_widgets.rb +40 -0
- data/test/manual/test_pagination.rb +24 -0
- data/test/manual/test_random_posts.rb +38 -0
- data/test/manual/test_syntax_highlighting.rb +167 -0
- data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
- data/test/rubytext/rubytext_demo_test.rb +42 -0
- data/test/rubytext/rubytext_testing_guide.md +277 -0
- data/test/run_automated_tests.rb +45 -0
- data/test/staging/.DS_Store +0 -0
- data/test/support/preview_utils.rb +88 -0
- data/test/syntax_highlighting_test.lt3 +124 -0
- data/test/test_gem_assets.rb +48 -0
- data/test/test_helpers.rb +240 -0
- data/test/tui_editor_integration_test.rb +296 -0
- data/test/tui_integration_test.rb +883 -0
- data/test/unit/api.rb +1776 -0
- data/test/unit/asset_management.rb +219 -0
- data/test/unit/backup_test.rb +451 -0
- data/test/unit/clipboard_test.rb +60 -0
- data/test/unit/contract_test.rb +69 -0
- data/test/unit/core.rb +1211 -0
- data/test/unit/deploy_config_test.rb +248 -0
- data/test/unit/deploy_test.rb +478 -0
- data/test/unit/edit_post_test.rb +168 -0
- data/test/unit/gem_asset_management.rb +183 -0
- data/test/unit/livetext_basic.rb +57 -0
- data/test/unit/livetext_compatibility.rb +82 -0
- data/test/unit/parse_cmd_test.rb +260 -0
- data/test/unit/permalink_copy_test.rb +211 -0
- data/test/unit/post.rb +309 -0
- data/test/unit/post_index_config_test.rb +258 -0
- data/test/unit/post_state_helpers_test.rb +137 -0
- data/test/unit/read_commented_file_test.rb +278 -0
- data/test/unit/reddit_test.rb +235 -0
- data/test/unit/repo.rb +569 -0
- data/test/unit/social_test.rb +366 -0
- data/test/unit/syntax_highlighting.rb +70 -0
- data/test/unit/theme_management_test.rb +91 -0
- data/test/unit/view.rb +498 -0
- data/test/unit/widgets.rb +669 -0
- data/test/web_integration_test.rb +231 -0
- data/test/web_test_helper.rb +218 -0
- data/test/web_workflow_test.rb +527 -0
- data/test/wizard_test.rb +123 -0
- data/ui/README.md +67 -0
- data/ui/common/lib/ui_common.rb +8 -0
- data/ui/rubytext/README.md +191 -0
- data/ui/rubytext/bin/scriptorium-rubytext +402 -0
- data/ui/rubytext/lib/rubytext_ui.rb +300 -0
- data/ui/tui/bin/scriptorium +1890 -0
- data/ui/tui/test/tui_test.rb +23 -0
- data/ui/web/app/app.rb +2600 -0
- data/ui/web/app/assets/livetext_mode.js +244 -0
- data/ui/web/app/error_helpers.rb +150 -0
- data/ui/web/app/views/advanced_config.erb +196 -0
- data/ui/web/app/views/asset_management.erb +645 -0
- data/ui/web/app/views/backup_management.erb +238 -0
- data/ui/web/app/views/banner_config.erb +200 -0
- data/ui/web/app/views/config_widget.erb +232 -0
- data/ui/web/app/views/configure_view.erb +401 -0
- data/ui/web/app/views/dashboard.erb +154 -0
- data/ui/web/app/views/deploy_config.erb +149 -0
- data/ui/web/app/views/edit_pages.erb +363 -0
- data/ui/web/app/views/edit_post.erb +175 -0
- data/ui/web/app/views/edit_theme.erb +73 -0
- data/ui/web/app/views/edit_theme_file.erb +74 -0
- data/ui/web/app/views/error_page.erb +29 -0
- data/ui/web/app/views/header_config.erb +155 -0
- data/ui/web/app/views/layout_config.erb +147 -0
- data/ui/web/app/views/navbar_config.erb +411 -0
- data/ui/web/app/views/theme_management.erb +130 -0
- data/ui/web/app/views/view_dashboard.erb +779 -0
- data/ui/web/app/views/widgets.erb +249 -0
- data/ui/web/bin/scriptorium-web +164 -0
- data/ui/web/test/web_basic_test.rb +38 -0
- data/ui/web/test_navbar.txt +7 -0
- data/ui/web/tmp/timing.log +17 -0
- data/ui/web/tmp/web_server.log +0 -0
- metadata +434 -8
- data/lib/scriptorium/engine.rb +0 -22
- data/test/engine/unit.rb +0 -44
data/test/unit/core.rb
ADDED
@@ -0,0 +1,1211 @@
|
|
1
|
+
# This test file primarily tests the core helper methods from lib/scriptorium/helpers.rb
|
2
|
+
# including file I/O operations, directory creation, system commands, and existence validation
|
3
|
+
# test/unit/core.rb
|
4
|
+
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require_relative '../../lib/scriptorium'
|
7
|
+
require_relative '../test_helpers'
|
8
|
+
require 'fileutils'
|
9
|
+
require 'tempfile'
|
10
|
+
|
11
|
+
class TestReadWrite < Minitest::Test
|
12
|
+
include Scriptorium::Helpers
|
13
|
+
include Scriptorium::Exceptions
|
14
|
+
include TestHelpers
|
15
|
+
|
16
|
+
def setup
|
17
|
+
@test_dir = "test/core_test_files"
|
18
|
+
FileUtils.mkdir_p(@test_dir)
|
19
|
+
Scriptorium::Repo.testing = true # Ensure testing mode is enabled
|
20
|
+
end
|
21
|
+
|
22
|
+
def teardown
|
23
|
+
FileUtils.rm_rf(@test_dir) if File.exist?(@test_dir)
|
24
|
+
end
|
25
|
+
|
26
|
+
# ========================================
|
27
|
+
# need() tests
|
28
|
+
# ========================================
|
29
|
+
|
30
|
+
def test_001_need_file_basic_functionality
|
31
|
+
file_path = "#{@test_dir}/test_file.txt"
|
32
|
+
write_file(file_path, "test content")
|
33
|
+
|
34
|
+
result = need(:file, file_path)
|
35
|
+
assert_equal file_path, result
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_002_need_dir_basic_functionality
|
39
|
+
dir_path = "#{@test_dir}/test_dir"
|
40
|
+
Dir.mkdir(dir_path)
|
41
|
+
|
42
|
+
result = need(:dir, dir_path)
|
43
|
+
assert_equal dir_path, result
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_003_need_with_custom_exception
|
47
|
+
file_path = "#{@test_dir}/nonexistent.txt"
|
48
|
+
|
49
|
+
# Create a simple custom exception for testing
|
50
|
+
custom_error_class = Class.new(StandardError) do
|
51
|
+
def self.call(path)
|
52
|
+
new("Custom error for: #{path}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
begin
|
57
|
+
need(:file, file_path, custom_error_class)
|
58
|
+
flunk "Expected need() to raise an error"
|
59
|
+
rescue custom_error_class => e
|
60
|
+
assert_match /Custom error for: #{file_path}/, e.message
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_004_need_nil_path_raises_error
|
65
|
+
assert_raises(RequirePathNil) do
|
66
|
+
need(:file, nil)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_005_need_empty_path_raises_error
|
71
|
+
assert_raises(RequirePathEmpty) do
|
72
|
+
need(:file, "")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_006_need_whitespace_path_raises_error
|
77
|
+
assert_raises(RequirePathEmpty) do
|
78
|
+
need(:file, " ")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_007_need_invalid_type_raises_error
|
83
|
+
assert_raises(InvalidType) do
|
84
|
+
need(:invalid, "some/path")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_008_need_file_nonexistent_raises_error
|
89
|
+
file_path = "#{@test_dir}/nonexistent.txt"
|
90
|
+
|
91
|
+
assert_raises(RequiredFileNotFound) do
|
92
|
+
need(:file, file_path)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_009_need_dir_nonexistent_raises_error
|
97
|
+
dir_path = "#{@test_dir}/nonexistent_dir"
|
98
|
+
|
99
|
+
assert_raises(RequiredFileNotFound) do
|
100
|
+
need(:dir, dir_path)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# ========================================
|
105
|
+
# system! tests
|
106
|
+
# ========================================
|
107
|
+
|
108
|
+
def test_010_system_basic_functionality
|
109
|
+
# Test a simple command that should succeed
|
110
|
+
result = system!("echo 'test' > /dev/null", "basic echo test")
|
111
|
+
assert result
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_011_system_with_description
|
115
|
+
# Test that description is included in error message
|
116
|
+
system!("false", "testing failure")
|
117
|
+
flunk "Expected system! to raise an error"
|
118
|
+
rescue CommandFailedWithDesc => e
|
119
|
+
assert_match /testing failure/, e.message
|
120
|
+
assert_match /Command failed/, e.message
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_012_system_nil_command_raises_error
|
124
|
+
assert_raises(CommandNil) do
|
125
|
+
system!(nil)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_013_system_empty_command_raises_error
|
130
|
+
assert_raises(CommandEmpty) do
|
131
|
+
system!("")
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_014_system_whitespace_command_raises_error
|
136
|
+
assert_raises(CommandEmpty) do
|
137
|
+
system!(" ")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_015_system_failing_command_raises_error
|
142
|
+
assert_raises(CommandFailedWithDesc) do
|
143
|
+
system!("false")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_016_system_nonexistent_command_raises_error
|
148
|
+
assert_raises(CommandFailedWithDesc) do
|
149
|
+
system!("nonexistent_command_that_should_fail")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# ========================================
|
154
|
+
# make_dir tests
|
155
|
+
# ========================================
|
156
|
+
|
157
|
+
def test_017_make_dir_basic_functionality
|
158
|
+
dir_path = "#{@test_dir}/new_dir"
|
159
|
+
|
160
|
+
make_dir(dir_path)
|
161
|
+
|
162
|
+
assert Dir.exist?(dir_path)
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_018_make_dir_with_parents
|
166
|
+
dir_path = "#{@test_dir}/nested/deep/path"
|
167
|
+
|
168
|
+
make_dir(dir_path, create_parents: true)
|
169
|
+
|
170
|
+
assert Dir.exist?(dir_path)
|
171
|
+
assert Dir.exist?("#{@test_dir}/nested")
|
172
|
+
assert Dir.exist?("#{@test_dir}/nested/deep")
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_019_make_dir_existing_directory
|
176
|
+
dir_path = "#{@test_dir}/existing_dir"
|
177
|
+
Dir.mkdir(dir_path)
|
178
|
+
|
179
|
+
# Should not raise an error
|
180
|
+
make_dir(dir_path)
|
181
|
+
|
182
|
+
assert Dir.exist?(dir_path)
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_020_make_dir_nil_path_raises_error
|
186
|
+
assert_raises(DirectoryPathNil) do
|
187
|
+
make_dir(nil)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_021_make_dir_empty_path_raises_error
|
192
|
+
assert_raises(DirectoryPathEmpty) do
|
193
|
+
make_dir("")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def test_022_make_dir_whitespace_path_raises_error
|
198
|
+
assert_raises(DirectoryPathEmpty) do
|
199
|
+
make_dir(" ")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_023_make_dir_permission_denied_simulation
|
204
|
+
# Create a read-only directory
|
205
|
+
read_only_dir = "#{@test_dir}/readonly"
|
206
|
+
Dir.mkdir(read_only_dir)
|
207
|
+
FileUtils.chmod(0444, read_only_dir)
|
208
|
+
|
209
|
+
file_path = "#{read_only_dir}/test_dir"
|
210
|
+
|
211
|
+
# This should raise a permission denied error
|
212
|
+
assert_raises(DirectoryPermissionDenied) do
|
213
|
+
make_dir(file_path)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Clean up
|
217
|
+
FileUtils.chmod(0755, read_only_dir)
|
218
|
+
end
|
219
|
+
|
220
|
+
# ========================================
|
221
|
+
# write_file tests
|
222
|
+
# ========================================
|
223
|
+
|
224
|
+
def test_024_write_file_basic_functionality
|
225
|
+
file_path = "#{@test_dir}/basic.txt"
|
226
|
+
content = ["line1", "line2", "line3"]
|
227
|
+
|
228
|
+
write_file(file_path, content.join("\n"))
|
229
|
+
|
230
|
+
assert File.exist?(file_path)
|
231
|
+
assert_equal content.join("\n") + "\n", read_file(file_path)
|
232
|
+
end
|
233
|
+
|
234
|
+
def test_025_write_file_creates_parent_directories
|
235
|
+
file_path = "#{@test_dir}/nested/deep/path/file.txt"
|
236
|
+
content = ["test content"]
|
237
|
+
|
238
|
+
write_file(file_path, content.join("\n"))
|
239
|
+
|
240
|
+
assert File.exist?(file_path)
|
241
|
+
assert File.exist?("#{@test_dir}/nested/deep/path")
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_026_write_file_empty_content
|
245
|
+
file_path = "#{@test_dir}/empty.txt"
|
246
|
+
|
247
|
+
write_file(file_path, "")
|
248
|
+
|
249
|
+
assert File.exist?(file_path)
|
250
|
+
assert_equal "\n", read_file(file_path)
|
251
|
+
end
|
252
|
+
|
253
|
+
def test_027_write_file_single_line
|
254
|
+
file_path = "#{@test_dir}/single.txt"
|
255
|
+
content = "single line content"
|
256
|
+
|
257
|
+
write_file(file_path, content)
|
258
|
+
|
259
|
+
assert File.exist?(file_path)
|
260
|
+
assert_equal content + "\n", read_file(file_path)
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_028_write_file_multiple_lines
|
264
|
+
file_path = "#{@test_dir}/multi.txt"
|
265
|
+
content = ["first line", "second line", "third line"]
|
266
|
+
|
267
|
+
write_file(file_path, content.join("\n"))
|
268
|
+
|
269
|
+
assert File.exist?(file_path)
|
270
|
+
expected = content.join("\n") + "\n"
|
271
|
+
assert_equal expected, read_file(file_path)
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_029_write_file_nil_path_raises_error
|
275
|
+
assert_raises(FilePathNil) do
|
276
|
+
write_file(nil, "content")
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_030_write_file_empty_path_raises_error
|
281
|
+
assert_raises(FilePathEmpty) do
|
282
|
+
write_file("", "content")
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_031_write_file_whitespace_path_raises_error
|
287
|
+
assert_raises(FilePathEmpty) do
|
288
|
+
write_file(" ", "content")
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_032_write_file_permission_denied_simulation
|
293
|
+
# Create a read-only directory
|
294
|
+
read_only_dir = "#{@test_dir}/readonly"
|
295
|
+
FileUtils.mkdir_p(read_only_dir)
|
296
|
+
FileUtils.chmod(0444, read_only_dir)
|
297
|
+
|
298
|
+
file_path = "#{read_only_dir}/test.txt"
|
299
|
+
|
300
|
+
# This should raise a permission denied error
|
301
|
+
assert_raises(FilePermissionDenied) do
|
302
|
+
write_file(file_path, "content")
|
303
|
+
end
|
304
|
+
|
305
|
+
# Clean up
|
306
|
+
FileUtils.chmod(0755, read_only_dir)
|
307
|
+
end
|
308
|
+
|
309
|
+
def test_033_write_file_empty_true_creates_file
|
310
|
+
file_path = "#{@test_dir}/empty_true.txt"
|
311
|
+
|
312
|
+
# Should create file with empty: true even for empty content
|
313
|
+
write_file(file_path, "", empty: true)
|
314
|
+
|
315
|
+
assert File.exist?(file_path)
|
316
|
+
assert_equal "", read_file(file_path) # No newline added
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_034_write_file_empty_true_nil_content
|
320
|
+
file_path = "#{@test_dir}/empty_true_nil.txt"
|
321
|
+
|
322
|
+
# Should create file with empty: true even for nil content
|
323
|
+
write_file(file_path, nil, empty: true)
|
324
|
+
|
325
|
+
assert File.exist?(file_path)
|
326
|
+
assert_equal "", read_file(file_path) # No newline added
|
327
|
+
end
|
328
|
+
|
329
|
+
def test_035_write_file_empty_true_whitespace_content
|
330
|
+
file_path = "#{@test_dir}/empty_true_whitespace.txt"
|
331
|
+
|
332
|
+
# Should create file with empty: true for whitespace-only content
|
333
|
+
write_file(file_path, " ", empty: true)
|
334
|
+
|
335
|
+
assert File.exist?(file_path)
|
336
|
+
assert_equal "", read_file(file_path) # No newline added
|
337
|
+
end
|
338
|
+
|
339
|
+
def test_036_write_file_empty_true_existing_file
|
340
|
+
file_path = "#{@test_dir}/empty_true_existing.txt"
|
341
|
+
|
342
|
+
# Create file with content first
|
343
|
+
write_file(file_path, "original content")
|
344
|
+
original_size = File.size(file_path)
|
345
|
+
|
346
|
+
# Now write empty content with empty: true
|
347
|
+
write_file(file_path, "", empty: true)
|
348
|
+
|
349
|
+
assert File.exist?(file_path)
|
350
|
+
assert_equal "original content\n", read_file(file_path) # File should preserve original content
|
351
|
+
assert_equal original_size, File.size(file_path) # File size should be unchanged
|
352
|
+
end
|
353
|
+
|
354
|
+
def test_037_write_file_empty_true_with_content
|
355
|
+
file_path = "#{@test_dir}/empty_true_with_content.txt"
|
356
|
+
content = "some content"
|
357
|
+
|
358
|
+
# empty: true should be ignored when there's actual content
|
359
|
+
write_file(file_path, content, empty: true)
|
360
|
+
|
361
|
+
assert File.exist?(file_path)
|
362
|
+
assert_equal content + "\n", read_file(file_path) # Normal behavior
|
363
|
+
end
|
364
|
+
|
365
|
+
# ========================================
|
366
|
+
# write_file! tests
|
367
|
+
# ========================================
|
368
|
+
|
369
|
+
def test_038_write_file_bang_basic_functionality
|
370
|
+
file_path = "#{@test_dir}/bang_basic.txt"
|
371
|
+
|
372
|
+
write_file!(file_path, "line1", "line2", "line3")
|
373
|
+
|
374
|
+
assert File.exist?(file_path)
|
375
|
+
assert_equal "line1\nline2\nline3\n", read_file(file_path)
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_039_write_file_bang_empty_true_no_lines
|
379
|
+
file_path = "#{@test_dir}/bang_empty_true.txt"
|
380
|
+
|
381
|
+
# Should create file with empty: true when no lines provided
|
382
|
+
write_file!(file_path, empty: true)
|
383
|
+
|
384
|
+
assert File.exist?(file_path)
|
385
|
+
assert_equal "", read_file(file_path) # No newline added
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_040_write_file_bang_empty_true_nil_lines
|
389
|
+
file_path = "#{@test_dir}/bang_empty_true_nil.txt"
|
390
|
+
|
391
|
+
# Should create file with empty: true when all lines are nil
|
392
|
+
write_file!(file_path, nil, nil, nil, empty: true)
|
393
|
+
|
394
|
+
assert File.exist?(file_path)
|
395
|
+
assert_equal "", read_file(file_path) # No newline added
|
396
|
+
end
|
397
|
+
|
398
|
+
def test_041_write_file_bang_empty_true_whitespace_lines
|
399
|
+
file_path = "#{@test_dir}/bang_empty_true_whitespace.txt"
|
400
|
+
|
401
|
+
# Should create file with empty: true when all lines are whitespace
|
402
|
+
write_file!(file_path, "", " ", "", empty: true)
|
403
|
+
|
404
|
+
assert File.exist?(file_path)
|
405
|
+
assert_equal "", read_file(file_path) # No newline added
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_042_write_file_bang_empty_true_with_content
|
409
|
+
file_path = "#{@test_dir}/bang_empty_true_with_content.txt"
|
410
|
+
|
411
|
+
# empty: true should be ignored when there's actual content
|
412
|
+
write_file!(file_path, "line1", "", "line3", empty: true)
|
413
|
+
|
414
|
+
assert File.exist?(file_path)
|
415
|
+
assert_equal "line1\n\nline3\n", read_file(file_path) # Normal behavior
|
416
|
+
end
|
417
|
+
|
418
|
+
# ========================================
|
419
|
+
# read_file tests
|
420
|
+
# ========================================
|
421
|
+
|
422
|
+
def test_033_read_file_basic_functionality
|
423
|
+
file_path = "#{@test_dir}/read_test.txt"
|
424
|
+
content = "line1\nline2\nline3"
|
425
|
+
write_file(file_path, content)
|
426
|
+
|
427
|
+
result = read_file(file_path)
|
428
|
+
|
429
|
+
assert_equal content + "\n", result
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_034_read_file_as_lines
|
433
|
+
file_path = "#{@test_dir}/lines_test.txt"
|
434
|
+
content = "line1\nline2\nline3"
|
435
|
+
write_file(file_path, content)
|
436
|
+
|
437
|
+
result = read_file(file_path, lines: true)
|
438
|
+
|
439
|
+
assert_equal ["line1\n", "line2\n", "line3\n"], result
|
440
|
+
end
|
441
|
+
|
442
|
+
def test_035_read_file_as_lines_with_chomp
|
443
|
+
file_path = "#{@test_dir}/chomp_test.txt"
|
444
|
+
content = "line1\nline2\nline3\n"
|
445
|
+
write_file(file_path, content)
|
446
|
+
|
447
|
+
result = read_file(file_path, lines: true, chomp: true)
|
448
|
+
|
449
|
+
assert_equal ["line1", "line2", "line3"], result
|
450
|
+
end
|
451
|
+
|
452
|
+
def test_036_read_file_as_lines_without_chomp
|
453
|
+
file_path = "#{@test_dir}/no_chomp_test.txt"
|
454
|
+
content = "line1\nline2\nline3\n"
|
455
|
+
write_file(file_path, content)
|
456
|
+
|
457
|
+
result = read_file(file_path, lines: true, chomp: false)
|
458
|
+
|
459
|
+
assert_equal ["line1\n", "line2\n", "line3\n"], result
|
460
|
+
end
|
461
|
+
|
462
|
+
def test_037_read_file_missing_file_with_fallback
|
463
|
+
file_path = "#{@test_dir}/nonexistent.txt"
|
464
|
+
fallback = "fallback content"
|
465
|
+
|
466
|
+
result = read_file(file_path, missing_fallback: fallback)
|
467
|
+
|
468
|
+
assert_equal fallback, result
|
469
|
+
end
|
470
|
+
|
471
|
+
def test_038_read_file_missing_file_without_fallback_raises_error
|
472
|
+
file_path = "#{@test_dir}/nonexistent.txt"
|
473
|
+
|
474
|
+
assert_raises(ReadFileNotFound) do
|
475
|
+
read_file(file_path)
|
476
|
+
end
|
477
|
+
end
|
478
|
+
|
479
|
+
def test_039_read_file_nil_path_raises_error
|
480
|
+
assert_raises(ReadFilePathNil) do
|
481
|
+
read_file(nil)
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
def test_040_read_file_empty_path_raises_error
|
486
|
+
assert_raises(ReadFilePathEmpty) do
|
487
|
+
read_file("")
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
def test_041_read_file_whitespace_path_raises_error
|
492
|
+
assert_raises(ReadFilePathEmpty) do
|
493
|
+
read_file(" ")
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
def test_042_read_file_permission_denied_simulation
|
498
|
+
# Create a file and make it unreadable
|
499
|
+
file_path = "#{@test_dir}/unreadable.txt"
|
500
|
+
write_file(file_path, "content")
|
501
|
+
FileUtils.chmod(0000, file_path)
|
502
|
+
|
503
|
+
assert_raises(ReadFilePermissionDenied) do
|
504
|
+
read_file(file_path)
|
505
|
+
end
|
506
|
+
|
507
|
+
# Clean up
|
508
|
+
FileUtils.chmod(0644, file_path)
|
509
|
+
end
|
510
|
+
|
511
|
+
def test_043_read_file_empty_file
|
512
|
+
file_path = "#{@test_dir}/empty.txt"
|
513
|
+
write_file(file_path, "")
|
514
|
+
|
515
|
+
result = read_file(file_path)
|
516
|
+
|
517
|
+
assert_equal "\n", result
|
518
|
+
end
|
519
|
+
|
520
|
+
def test_044_read_file_empty_file_as_lines
|
521
|
+
file_path = "#{@test_dir}/empty_lines.txt"
|
522
|
+
write_file(file_path, "")
|
523
|
+
|
524
|
+
result = read_file(file_path, lines: true)
|
525
|
+
|
526
|
+
assert_equal ["\n"], result
|
527
|
+
end
|
528
|
+
|
529
|
+
def test_045_read_file_single_line
|
530
|
+
file_path = "#{@test_dir}/single_line.txt"
|
531
|
+
content = "single line"
|
532
|
+
write_file(file_path, content)
|
533
|
+
|
534
|
+
result = read_file(file_path)
|
535
|
+
|
536
|
+
assert_equal content + "\n", result
|
537
|
+
end
|
538
|
+
|
539
|
+
def test_046_read_file_single_line_as_lines
|
540
|
+
file_path = "#{@test_dir}/single_line.txt"
|
541
|
+
content = "single line"
|
542
|
+
write_file(file_path, content)
|
543
|
+
|
544
|
+
result = read_file(file_path, lines: true)
|
545
|
+
|
546
|
+
assert_equal [content + "\n"], result
|
547
|
+
end
|
548
|
+
|
549
|
+
def test_047_read_file_with_trailing_newline
|
550
|
+
file_path = "#{@test_dir}/trailing_newline.txt"
|
551
|
+
content = "line1\nline2\n"
|
552
|
+
write_file(file_path, content)
|
553
|
+
|
554
|
+
result = read_file(file_path)
|
555
|
+
|
556
|
+
assert_equal content, result
|
557
|
+
end
|
558
|
+
|
559
|
+
def test_048_read_file_with_trailing_newline_as_lines
|
560
|
+
file_path = "#{@test_dir}/trailing_newline.txt"
|
561
|
+
content = "line1\nline2\n"
|
562
|
+
write_file(file_path, content)
|
563
|
+
|
564
|
+
result = read_file(file_path, lines: true)
|
565
|
+
|
566
|
+
assert_equal ["line1\n", "line2\n"], result
|
567
|
+
end
|
568
|
+
|
569
|
+
def test_049_read_file_with_trailing_newline_as_lines_no_chomp
|
570
|
+
file_path = "#{@test_dir}/trailing_newline.txt"
|
571
|
+
content = "line1\nline2\n"
|
572
|
+
write_file(file_path, content)
|
573
|
+
|
574
|
+
result = read_file(file_path, lines: true, chomp: false)
|
575
|
+
|
576
|
+
assert_equal ["line1\n", "line2\n"], result
|
577
|
+
end
|
578
|
+
|
579
|
+
# ========================================
|
580
|
+
# Integration tests
|
581
|
+
# ========================================
|
582
|
+
|
583
|
+
def test_050_write_then_read_cycle
|
584
|
+
file_path = "#{@test_dir}/cycle.txt"
|
585
|
+
original_content = ["first line", "second line", "third line"]
|
586
|
+
|
587
|
+
# Write content
|
588
|
+
write_file(file_path, original_content.join("\n"))
|
589
|
+
|
590
|
+
# Read it back
|
591
|
+
read_content = read_file(file_path)
|
592
|
+
|
593
|
+
# Verify
|
594
|
+
expected_content = original_content.join("\n") + "\n"
|
595
|
+
assert_equal expected_content, read_content
|
596
|
+
end
|
597
|
+
|
598
|
+
def test_051_write_then_read_as_lines_cycle
|
599
|
+
file_path = "#{@test_dir}/cycle_lines.txt"
|
600
|
+
original_content = ["first line", "second line", "third line"]
|
601
|
+
|
602
|
+
# Write content
|
603
|
+
write_file(file_path, original_content.join("\n"))
|
604
|
+
|
605
|
+
# Read it back as lines
|
606
|
+
read_content = read_file(file_path, lines: true)
|
607
|
+
|
608
|
+
# Verify
|
609
|
+
assert_equal ["first line\n", "second line\n", "third line\n"], read_content
|
610
|
+
end
|
611
|
+
|
612
|
+
def test_052_multiple_write_operations
|
613
|
+
file_path = "#{@test_dir}/multiple.txt"
|
614
|
+
|
615
|
+
# First write
|
616
|
+
write_file(file_path, "first content")
|
617
|
+
assert_equal "first content\n", read_file(file_path)
|
618
|
+
|
619
|
+
# Second write (should overwrite)
|
620
|
+
write_file(file_path, "second content")
|
621
|
+
assert_equal "second content\n", read_file(file_path)
|
622
|
+
end
|
623
|
+
|
624
|
+
def test_053_write_file_with_special_characters
|
625
|
+
file_path = "#{@test_dir}/special.txt"
|
626
|
+
content = ["line with spaces", "line\twith\ttabs", "line with # comments"]
|
627
|
+
|
628
|
+
write_file(file_path, content.join("\n"))
|
629
|
+
|
630
|
+
result = read_file(file_path, lines: true)
|
631
|
+
assert_equal ["line with spaces\n", "line\twith\ttabs\n", "line with # comments\n"], result
|
632
|
+
end
|
633
|
+
|
634
|
+
def test_054_read_file_with_unicode_content
|
635
|
+
file_path = "#{@test_dir}/unicode.txt"
|
636
|
+
content = ["café", "naïve", "résumé", "über"]
|
637
|
+
|
638
|
+
write_file(file_path, content.join("\n"))
|
639
|
+
|
640
|
+
result = read_file(file_path, lines: true)
|
641
|
+
assert_equal ["café\n", "naïve\n", "résumé\n", "über\n"], result
|
642
|
+
end
|
643
|
+
|
644
|
+
# ========================================
|
645
|
+
# Edge case tests
|
646
|
+
# ========================================
|
647
|
+
|
648
|
+
def test_055_write_file_with_nil_lines
|
649
|
+
file_path = "#{@test_dir}/nil_lines.txt"
|
650
|
+
|
651
|
+
write_file!(file_path, nil, "content", nil)
|
652
|
+
|
653
|
+
result = read_file(file_path, lines: true)
|
654
|
+
assert_equal ["\n", "content\n", "\n"], result
|
655
|
+
end
|
656
|
+
|
657
|
+
def test_056_write_file_with_empty_strings
|
658
|
+
file_path = "#{@test_dir}/empty_strings.txt"
|
659
|
+
|
660
|
+
write_file!(file_path, "", "content", "")
|
661
|
+
|
662
|
+
result = read_file(file_path, lines: true)
|
663
|
+
assert_equal ["\n", "content\n", "\n"], result
|
664
|
+
end
|
665
|
+
|
666
|
+
def test_057_read_file_missing_fallback_with_lines_option
|
667
|
+
file_path = "#{@test_dir}/nonexistent.txt"
|
668
|
+
fallback = ["fallback", "lines"]
|
669
|
+
|
670
|
+
result = read_file(file_path, lines: true, missing_fallback: fallback)
|
671
|
+
|
672
|
+
assert_equal fallback, result
|
673
|
+
end
|
674
|
+
|
675
|
+
def test_058_read_file_missing_fallback_with_chomp_option
|
676
|
+
file_path = "#{@test_dir}/nonexistent.txt"
|
677
|
+
fallback = ["fallback", "lines"]
|
678
|
+
|
679
|
+
result = read_file(file_path, lines: true, chomp: true, missing_fallback: fallback)
|
680
|
+
|
681
|
+
assert_equal fallback, result
|
682
|
+
end
|
683
|
+
|
684
|
+
def test_059_write_file_very_long_line
|
685
|
+
file_path = "#{@test_dir}/long_line.txt"
|
686
|
+
long_line = "x" * 10000
|
687
|
+
|
688
|
+
write_file(file_path, long_line)
|
689
|
+
|
690
|
+
result = read_file(file_path)
|
691
|
+
assert_equal long_line + "\n", result
|
692
|
+
end
|
693
|
+
|
694
|
+
def test_060_write_file_many_lines
|
695
|
+
file_path = "#{@test_dir}/many_lines.txt"
|
696
|
+
many_lines = (1..1000).map { |i| "line #{i}" }
|
697
|
+
|
698
|
+
write_file(file_path, many_lines.join("\n"))
|
699
|
+
|
700
|
+
result = read_file(file_path, lines: true)
|
701
|
+
expected_lines = many_lines.map { |line| line + "\n" }
|
702
|
+
assert_equal expected_lines, result
|
703
|
+
end
|
704
|
+
|
705
|
+
# ========================================
|
706
|
+
# Moved helper method tests (3 tests)
|
707
|
+
# ========================================
|
708
|
+
|
709
|
+
def test_061_change_config
|
710
|
+
cfg_file = "#{@test_dir}/myconfig.txt"
|
711
|
+
File.open(cfg_file, "w") do |f|
|
712
|
+
f.puts <<~EOS
|
713
|
+
alpha foo # nothing much
|
714
|
+
beta bar # meh again
|
715
|
+
gamma baz # whatever
|
716
|
+
EOS
|
717
|
+
end
|
718
|
+
change_config(cfg_file, "beta", "new-value")
|
719
|
+
lines = File.readlines(cfg_file).map(&:chomp)
|
720
|
+
assert lines[0] == "alpha foo # nothing much", "Expected alpha text"
|
721
|
+
assert lines[1] == "beta new-value # meh again", "Expected beta text"
|
722
|
+
assert lines[2] == "gamma baz # whatever", "Expected gamma text"
|
723
|
+
end
|
724
|
+
|
725
|
+
def test_062_read_commented_file
|
726
|
+
# Setup: Create a temporary test config file
|
727
|
+
test_file = "#{@test_dir}/test_config.txt"
|
728
|
+
File.open(test_file, "w") do |f|
|
729
|
+
f.puts "# This is a comment"
|
730
|
+
f.puts ""
|
731
|
+
f.puts "header 20% # This is a header line with a comment"
|
732
|
+
f.puts "footer # This is a footer line with another comment"
|
733
|
+
f.puts "# Another full-line comment"
|
734
|
+
f.puts "main # Main content area"
|
735
|
+
end
|
736
|
+
|
737
|
+
# Expected result: an array of non-comment lines, with comments stripped
|
738
|
+
expected_result = ["header 20%", "footer", "main"]
|
739
|
+
|
740
|
+
# Run the method
|
741
|
+
result = read_commented_file(test_file)
|
742
|
+
|
743
|
+
# Assert the result matches the expected array
|
744
|
+
assert_equal expected_result, result
|
745
|
+
end
|
746
|
+
|
747
|
+
def test_063_get_asset_path
|
748
|
+
name = "back.png"
|
749
|
+
result = get_asset_path(name)
|
750
|
+
assert result == "assets/icons/ui/#{name}", "Expected #{name} to be found recursively (got #{result})"
|
751
|
+
assert_raises(AssetNotFound) { get_asset_path("nonexistent.png") }
|
752
|
+
end
|
753
|
+
|
754
|
+
# ========================================
|
755
|
+
# New helper method tests
|
756
|
+
# ========================================
|
757
|
+
|
758
|
+
def test_064_slugify_basic
|
759
|
+
result = slugify(42, "My Test Post")
|
760
|
+
assert_equal "0042-my-test-post", result
|
761
|
+
end
|
762
|
+
|
763
|
+
def test_065_slugify_with_special_characters
|
764
|
+
result = slugify(1, "Post with & < > \" ' characters!")
|
765
|
+
assert_equal "0001-post-with-characters", result
|
766
|
+
end
|
767
|
+
|
768
|
+
def test_066_slugify_with_underscores_and_hyphens
|
769
|
+
result = slugify(123, "Post with_underscores-and-hyphens")
|
770
|
+
assert_equal "0123-post-with-underscores-and-hyphens", result
|
771
|
+
end
|
772
|
+
|
773
|
+
def test_067_slugify_with_multiple_spaces
|
774
|
+
result = slugify(5, "Post with multiple spaces")
|
775
|
+
assert_equal "0005-post-with-multiple-spaces", result
|
776
|
+
end
|
777
|
+
|
778
|
+
def test_068_slugify_with_leading_trailing_hyphens
|
779
|
+
result = slugify(99, "-Post with leading/trailing hyphens-")
|
780
|
+
assert_equal "0099-post-with-leadingtrailing-hyphens", result
|
781
|
+
end
|
782
|
+
|
783
|
+
# ========================================
|
784
|
+
# clean_slugify tests
|
785
|
+
# ========================================
|
786
|
+
|
787
|
+
def test_083_clean_slugify_basic
|
788
|
+
result = clean_slugify("My Test Post")
|
789
|
+
assert_equal "my-test-post", result
|
790
|
+
end
|
791
|
+
|
792
|
+
def test_084_clean_slugify_with_special_characters
|
793
|
+
result = clean_slugify("Post with & < > \" ' characters!")
|
794
|
+
assert_equal "post-with-characters", result
|
795
|
+
end
|
796
|
+
|
797
|
+
def test_085_clean_slugify_with_underscores_and_hyphens
|
798
|
+
result = clean_slugify("Post with_underscores-and-hyphens")
|
799
|
+
assert_equal "post-with-underscores-and-hyphens", result
|
800
|
+
end
|
801
|
+
|
802
|
+
def test_086_clean_slugify_with_multiple_spaces
|
803
|
+
result = clean_slugify("Post with multiple spaces")
|
804
|
+
assert_equal "post-with-multiple-spaces", result
|
805
|
+
end
|
806
|
+
|
807
|
+
def test_087_clean_slugify_with_leading_trailing_hyphens
|
808
|
+
result = clean_slugify("-Post with leading/trailing hyphens-")
|
809
|
+
assert_equal "post-with-leadingtrailing-hyphens", result
|
810
|
+
end
|
811
|
+
|
812
|
+
def test_088_clean_slugify_empty_string
|
813
|
+
result = clean_slugify("")
|
814
|
+
assert_equal "", result
|
815
|
+
end
|
816
|
+
|
817
|
+
def test_089_clean_slugify_nil_string
|
818
|
+
result = clean_slugify(nil)
|
819
|
+
assert_equal "title-is-missing", result
|
820
|
+
end
|
821
|
+
|
822
|
+
def test_069_escape_html_basic
|
823
|
+
result = escape_html("<script>alert('test')</script>")
|
824
|
+
assert_equal "<script>alert('test')</script>", result
|
825
|
+
end
|
826
|
+
|
827
|
+
def test_070_escape_html_with_quotes
|
828
|
+
result = escape_html('He said "Hello" and she said \'Hi\'')
|
829
|
+
assert_equal "He said "Hello" and she said 'Hi'", result
|
830
|
+
end
|
831
|
+
|
832
|
+
def test_071_escape_html_with_ampersand
|
833
|
+
result = escape_html("Fish & Chips")
|
834
|
+
assert_equal "Fish & Chips", result
|
835
|
+
end
|
836
|
+
|
837
|
+
def test_072_escape_html_with_mixed_content
|
838
|
+
result = escape_html('<a href="test">Link & Text</a>')
|
839
|
+
assert_equal "<a href="test">Link & Text</a>", result
|
840
|
+
end
|
841
|
+
|
842
|
+
def test_073_getvars_basic
|
843
|
+
config_file = "#{@test_dir}/config.txt"
|
844
|
+
write_file(config_file, <<~EOS)
|
845
|
+
title My Blog
|
846
|
+
subtitle A test blog
|
847
|
+
theme standard
|
848
|
+
EOS
|
849
|
+
|
850
|
+
result = getvars(config_file)
|
851
|
+
assert_equal "My Blog", result[:title]
|
852
|
+
assert_equal "A test blog", result[:subtitle]
|
853
|
+
assert_equal "standard", result[:theme]
|
854
|
+
end
|
855
|
+
|
856
|
+
def test_074_getvars_with_comments
|
857
|
+
config_file = "#{@test_dir}/config_with_comments.txt"
|
858
|
+
write_file(config_file, <<~EOS)
|
859
|
+
# This is a comment
|
860
|
+
title My Blog # Another comment
|
861
|
+
subtitle A test blog
|
862
|
+
# Empty line below
|
863
|
+
|
864
|
+
theme standard
|
865
|
+
EOS
|
866
|
+
|
867
|
+
result = getvars(config_file)
|
868
|
+
assert_equal "My Blog", result[:title]
|
869
|
+
assert_equal "A test blog", result[:subtitle]
|
870
|
+
assert_equal "standard", result[:theme]
|
871
|
+
assert_equal 3, result.size # Only valid key-value pairs
|
872
|
+
end
|
873
|
+
|
874
|
+
def test_075_getvars_with_empty_values
|
875
|
+
config_file = "#{@test_dir}/config_empty.txt"
|
876
|
+
write_file(config_file, <<~EOS)
|
877
|
+
title My Blog
|
878
|
+
subtitle
|
879
|
+
theme standard
|
880
|
+
EOS
|
881
|
+
|
882
|
+
result = getvars(config_file)
|
883
|
+
assert_equal "My Blog", result[:title]
|
884
|
+
assert_equal "", result[:subtitle] # When no value after key, split returns empty string
|
885
|
+
assert_equal "standard", result[:theme]
|
886
|
+
end
|
887
|
+
|
888
|
+
def test_076_d4_basic
|
889
|
+
assert_equal "0001", d4(1)
|
890
|
+
assert_equal "0042", d4(42)
|
891
|
+
assert_equal "0123", d4(123)
|
892
|
+
assert_equal "9999", d4(9999)
|
893
|
+
end
|
894
|
+
|
895
|
+
def test_077_d4_with_large_numbers
|
896
|
+
assert_equal "10000", d4(10000)
|
897
|
+
assert_equal "12345", d4(12345)
|
898
|
+
end
|
899
|
+
|
900
|
+
def test_078_substitute_with_hash
|
901
|
+
vars = {title: "My Title", content: "My Content"}
|
902
|
+
template = "Title: %{title}\nContent: %{content}"
|
903
|
+
|
904
|
+
result = substitute(vars, template)
|
905
|
+
assert_equal "Title: My Title\nContent: My Content", result
|
906
|
+
end
|
907
|
+
|
908
|
+
def test_079_substitute_with_object
|
909
|
+
# Create a mock object with vars method
|
910
|
+
mock_obj = Object.new
|
911
|
+
def mock_obj.vars
|
912
|
+
{title: "My Title", content: "My Content"}
|
913
|
+
end
|
914
|
+
|
915
|
+
template = "Title: %{title}\nContent: %{content}"
|
916
|
+
result = substitute(mock_obj, template)
|
917
|
+
assert_equal "Title: My Title\nContent: My Content", result
|
918
|
+
end
|
919
|
+
|
920
|
+
def test_080_substitute_with_missing_vars
|
921
|
+
vars = {title: "My Title"}
|
922
|
+
template = "Title: %{title}\nContent: %{content}"
|
923
|
+
|
924
|
+
# The substitute method raises KeyError for missing keys
|
925
|
+
assert_raises(KeyError) do
|
926
|
+
substitute(vars, template)
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
930
|
+
def test_081_make_tree_basic
|
931
|
+
tree_text = <<~EOS
|
932
|
+
.
|
933
|
+
├── file1.txt
|
934
|
+
├── dir1/
|
935
|
+
│ ├── file2.txt
|
936
|
+
│ └── subdir/
|
937
|
+
│ └── file3.txt
|
938
|
+
└── file4.txt
|
939
|
+
EOS
|
940
|
+
|
941
|
+
make_tree("#{@test_dir}/test_tree", tree_text)
|
942
|
+
|
943
|
+
assert File.exist?("#{@test_dir}/test_tree/file1.txt")
|
944
|
+
assert File.exist?("#{@test_dir}/test_tree/dir1/file2.txt")
|
945
|
+
assert File.exist?("#{@test_dir}/test_tree/dir1/subdir/file3.txt")
|
946
|
+
assert File.exist?("#{@test_dir}/test_tree/file4.txt")
|
947
|
+
end
|
948
|
+
|
949
|
+
def test_082_make_tree_with_comments
|
950
|
+
tree_text = <<~EOS
|
951
|
+
.
|
952
|
+
├── file1.txt # This is a comment
|
953
|
+
├── dir1/ # Another comment
|
954
|
+
│ └── file2.txt
|
955
|
+
└── file3.txt
|
956
|
+
EOS
|
957
|
+
|
958
|
+
make_tree("#{@test_dir}/test_tree_with_comments", tree_text)
|
959
|
+
|
960
|
+
assert File.exist?("#{@test_dir}/test_tree_with_comments/file1.txt")
|
961
|
+
assert File.exist?("#{@test_dir}/test_tree_with_comments/dir1/file2.txt")
|
962
|
+
assert File.exist?("#{@test_dir}/test_tree_with_comments/file3.txt")
|
963
|
+
end
|
964
|
+
|
965
|
+
def test_083_make_tree_simplified
|
966
|
+
tree_text = <<~EOS
|
967
|
+
.
|
968
|
+
├── config/
|
969
|
+
├── views/
|
970
|
+
├── drafts/
|
971
|
+
├── posts/
|
972
|
+
├── assets/
|
973
|
+
│ └── library/
|
974
|
+
└── themes/
|
975
|
+
EOS
|
976
|
+
|
977
|
+
target_dir = "#{@test_dir}/simplified_tree"
|
978
|
+
make_tree(target_dir, tree_text)
|
979
|
+
|
980
|
+
assert File.exist?("#{target_dir}/config")
|
981
|
+
assert File.exist?("#{target_dir}/views")
|
982
|
+
assert File.exist?("#{target_dir}/drafts")
|
983
|
+
assert File.exist?("#{target_dir}/posts")
|
984
|
+
assert File.exist?("#{target_dir}/assets/library")
|
985
|
+
assert File.exist?("#{target_dir}/themes")
|
986
|
+
end
|
987
|
+
|
988
|
+
# ========================================
|
989
|
+
# Additional exception tests for untested exceptions
|
990
|
+
# ========================================
|
991
|
+
|
992
|
+
def test_093_general_validation_exceptions
|
993
|
+
# Test that exception classes exist
|
994
|
+
assert NilValueError
|
995
|
+
assert EmptyValueError
|
996
|
+
assert InvalidFormatError
|
997
|
+
|
998
|
+
# Test actual exception raising for some that we can trigger
|
999
|
+
assert_raises(InvalidType) do
|
1000
|
+
need(:invalid_type, "some/path")
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
# Test require path exceptions
|
1004
|
+
assert_raises(RequirePathNil) do
|
1005
|
+
need(:file, nil)
|
1006
|
+
end
|
1007
|
+
|
1008
|
+
assert_raises(RequirePathEmpty) do
|
1009
|
+
need(:file, "")
|
1010
|
+
end
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def test_094_repository_exceptions
|
1014
|
+
# Test RepoDirAlreadyExists
|
1015
|
+
assert RepoDirAlreadyExists
|
1016
|
+
|
1017
|
+
# Test ViewDirDoesntExist
|
1018
|
+
assert ViewDirDoesntExist
|
1019
|
+
|
1020
|
+
# Test ThemeFileNotFound
|
1021
|
+
assert ThemeFileNotFound
|
1022
|
+
|
1023
|
+
# Test NoGemPath
|
1024
|
+
assert NoGemPath
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
def test_095_file_io_exceptions
|
1028
|
+
# Test that exception classes exist
|
1029
|
+
assert FileNotFoundError
|
1030
|
+
assert DirectoryNotFoundError
|
1031
|
+
assert FileDiskFull
|
1032
|
+
assert FileDirectoryNotFound
|
1033
|
+
assert CannotWriteFileError
|
1034
|
+
assert DirectoryParentNotFound
|
1035
|
+
assert DirectoryDiskFull
|
1036
|
+
assert DirectoryError
|
1037
|
+
assert ReadFileError
|
1038
|
+
|
1039
|
+
# Test actual exception raising for some that we can trigger
|
1040
|
+
assert_raises(ReadFilePathNil) do
|
1041
|
+
read_file(nil)
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
assert_raises(ReadFilePathEmpty) do
|
1045
|
+
read_file("")
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
assert_raises(FilePathNil) do
|
1049
|
+
write_file(nil, "content")
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
assert_raises(FilePathEmpty) do
|
1053
|
+
write_file("", "content")
|
1054
|
+
end
|
1055
|
+
|
1056
|
+
# Test directory-related exceptions
|
1057
|
+
assert_raises(DirectoryPathNil) do
|
1058
|
+
make_dir(nil)
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
assert_raises(DirectoryPathEmpty) do
|
1062
|
+
make_dir("")
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
def test_096_command_system_exceptions
|
1067
|
+
# Test that exception classes exist
|
1068
|
+
assert CommandFailed
|
1069
|
+
assert CannotExecuteCommand
|
1070
|
+
assert SectionOutputError
|
1071
|
+
assert WriteFrontPageError
|
1072
|
+
|
1073
|
+
# Test actual exception raising for some that we can trigger
|
1074
|
+
assert_raises(CommandNil) do
|
1075
|
+
system!(nil)
|
1076
|
+
end
|
1077
|
+
|
1078
|
+
assert_raises(CommandEmpty) do
|
1079
|
+
system!("")
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
def test_097_validation_exceptions
|
1084
|
+
# Test ViewTargetNil
|
1085
|
+
assert ViewTargetNil
|
1086
|
+
|
1087
|
+
# Test ViewTargetEmpty
|
1088
|
+
assert ViewTargetEmpty
|
1089
|
+
|
1090
|
+
# Test ViewTargetInvalid
|
1091
|
+
assert ViewTargetInvalid
|
1092
|
+
|
1093
|
+
# Test PostIdNil
|
1094
|
+
assert PostIdNil
|
1095
|
+
|
1096
|
+
# Test PostIdEmpty
|
1097
|
+
assert PostIdEmpty
|
1098
|
+
|
1099
|
+
# Test PostIdInvalid
|
1100
|
+
assert PostIdInvalid
|
1101
|
+
|
1102
|
+
# Test CannotCreateView
|
1103
|
+
assert CannotCreateView
|
1104
|
+
|
1105
|
+
# Test CannotBuildWidget
|
1106
|
+
assert CannotBuildWidget
|
1107
|
+
|
1108
|
+
# Test CannotGetPost
|
1109
|
+
assert CannotGetPost
|
1110
|
+
|
1111
|
+
# Test CannotSetPubdate
|
1112
|
+
assert CannotSetPubdate
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
# ========================================
|
1116
|
+
# format_date() tests
|
1117
|
+
# ========================================
|
1118
|
+
|
1119
|
+
def test_001_format_date_basic_functionality
|
1120
|
+
# Test basic date formatting
|
1121
|
+
result = format_date("month dd yyyy", Date.new(2025, 2, 22))
|
1122
|
+
assert_equal "February 22 2025", result
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
def test_002_format_date_with_ordinal
|
1126
|
+
# Test ordinal day formatting
|
1127
|
+
result = format_date("month day, yyyy", Date.new(2025, 2, 22))
|
1128
|
+
assert_equal "February 22nd, 2025", result
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
def test_003_format_date_with_break
|
1132
|
+
# Test line break formatting
|
1133
|
+
result = format_date("month dd break yyyy", Date.new(2025, 2, 22))
|
1134
|
+
assert_equal "February 22<br>2025", result
|
1135
|
+
end
|
1136
|
+
|
1137
|
+
def test_004_format_date_string_input
|
1138
|
+
# Test string date input
|
1139
|
+
result = format_date("dd month yyyy", "2025-02-22")
|
1140
|
+
assert_equal "22 February 2025", result
|
1141
|
+
end
|
1142
|
+
|
1143
|
+
def test_005_format_date_nil_input
|
1144
|
+
# Test nil date input (should return original format)
|
1145
|
+
result = format_date("month dd yyyy", nil)
|
1146
|
+
assert_equal "month dd yyyy", result
|
1147
|
+
end
|
1148
|
+
|
1149
|
+
def test_006_format_date_invalid_string
|
1150
|
+
# Test invalid date string (should return original format)
|
1151
|
+
result = format_date("month dd yyyy", "invalid-date")
|
1152
|
+
assert_equal "month dd yyyy", result
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
def test_007_format_date_ordinal_edge_cases
|
1156
|
+
# Test ordinal edge cases
|
1157
|
+
assert_equal "1st", ordinalize(1)
|
1158
|
+
assert_equal "2nd", ordinalize(2)
|
1159
|
+
assert_equal "3rd", ordinalize(3)
|
1160
|
+
assert_equal "4th", ordinalize(4)
|
1161
|
+
assert_equal "11th", ordinalize(11)
|
1162
|
+
assert_equal "12th", ordinalize(12)
|
1163
|
+
assert_equal "13th", ordinalize(13)
|
1164
|
+
assert_equal "21st", ordinalize(21)
|
1165
|
+
assert_equal "22nd", ordinalize(22)
|
1166
|
+
assert_equal "23rd", ordinalize(23)
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
def test_008_format_date_various_formats
|
1170
|
+
# Test various format combinations
|
1171
|
+
date = Date.new(2025, 2, 22)
|
1172
|
+
|
1173
|
+
assert_equal "02/22/2025", format_date("mm/dd/yyyy", date)
|
1174
|
+
assert_equal "22/02/25", format_date("dd/mm/yy", date)
|
1175
|
+
assert_equal "February 22nd, 2025", format_date("month day, yyyy", date)
|
1176
|
+
assert_equal "22 February 2025", format_date("dd month yyyy", date)
|
1177
|
+
assert_equal "February 22<br>2025", format_date("month dd break yyyy", date)
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
def test_009_format_date_smart_padding
|
1181
|
+
# Test smart padding logic
|
1182
|
+
date = Date.new(2025, 7, 4)
|
1183
|
+
|
1184
|
+
# Should pad when surrounded by punctuation
|
1185
|
+
assert_equal "04/07/2025", format_date("dd/mm/yyyy", date)
|
1186
|
+
assert_equal "07/04/2025", format_date("mm/dd/yyyy", date)
|
1187
|
+
assert_equal "2025-07-04", format_date("yyyy-mm-dd", date)
|
1188
|
+
assert_equal "04.07.2025", format_date("dd.mm.yyyy", date)
|
1189
|
+
|
1190
|
+
# Should not pad when surrounded by spaces
|
1191
|
+
assert_equal "July 4, 2025", format_date("month dd, yyyy", date)
|
1192
|
+
assert_equal "4 July 2025", format_date("dd month yyyy", date)
|
1193
|
+
assert_equal "July 4 2025", format_date("month dd yyyy", date)
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
private
|
1197
|
+
|
1198
|
+
def ordinalize(number)
|
1199
|
+
case number % 100
|
1200
|
+
when 11, 12, 13
|
1201
|
+
"#{number}th"
|
1202
|
+
else
|
1203
|
+
case number % 10
|
1204
|
+
when 1 then "#{number}st"
|
1205
|
+
when 2 then "#{number}nd"
|
1206
|
+
when 3 then "#{number}rd"
|
1207
|
+
else "#{number}th"
|
1208
|
+
end
|
1209
|
+
end
|
1210
|
+
end
|
1211
|
+
end
|