scriptorium 0.6.1 → 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/assets/icons/social/reddit.png +0 -0
- data/assets/icons/social/x-logo.png +0 -0
- data/assets/imagenotfound.jpg +0 -0
- data/bin/sblog +84 -5
- data/bin/scriptorium +1 -0
- data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +0 -1
- data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +0 -29
- data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +0 -19
- data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +1 -1
- data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +1 -1
- data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +1 -1
- data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +0 -10
- data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +1 -4
- 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/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/{userdoc-toc.txt → myuserdoc/userdoc-toc.txt} +27 -27
- 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_integration.md +2 -2
- data/doc/user.lt3 +0 -3
- data/lib/scriptorium/api.rb +1811 -78
- data/lib/scriptorium/banner_svg.rb +55 -68
- data/lib/scriptorium/contract.rb +3 -2
- data/lib/scriptorium/exceptions.rb +133 -102
- data/lib/scriptorium/helpers.rb +282 -82
- data/lib/scriptorium/post.rb +81 -17
- data/lib/scriptorium/reddit.rb +1 -1
- data/lib/scriptorium/repo.rb +478 -164
- data/lib/scriptorium/standard_files.rb +30 -396
- 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_template.txt +17 -0
- data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/social.txt +1 -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/{test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 → lib/scriptorium/support/templates/initial_post.lt3} +5 -5
- data/lib/scriptorium/support/templates/post.lt3 +104 -0
- data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt → lib/scriptorium/support/theme/header.lt3} +1 -1
- data/lib/scriptorium/theme.rb +83 -70
- data/lib/scriptorium/version.rb +2 -2
- data/lib/scriptorium/view.rb +194 -149
- data/lib/scriptorium.rb +24 -1
- data/lib/skeleton.rb +4 -1
- data/scriptorium.gemspec +2 -1
- data/test/WEB_INTEGRATION_README.md +196 -0
- data/test/all +40 -0
- data/test/banner_svg/unit.rb +267 -35
- data/test/config/deployment.txt +5 -0
- data/test/integration/integration_test.rb +7 -7
- data/test/integration/preview_flow_test.rb +94 -0
- data/test/livetext_plugin_test.rb +453 -182
- data/test/manual/banner-tests/test01.html +82 -18
- data/test/manual/banner-tests/test02.html +82 -18
- data/test/manual/banner-tests/test03.html +82 -18
- data/test/manual/banner-tests/test04.html +89 -25
- data/test/manual/banner-tests/test05.html +89 -25
- data/test/manual/banner-tests/test06.html +89 -25
- data/test/manual/banner-tests/test07.html +89 -25
- data/test/manual/banner-tests/test08.html +82 -18
- data/test/manual/banner-tests/test09.html +82 -18
- data/test/manual/banner-tests/test10.html +82 -18
- data/test/manual/banner-tests/test11.html +82 -18
- data/test/manual/banner-tests/test12.html +82 -18
- data/test/manual/banner-tests/test13.html +82 -18
- data/test/manual/banner-tests/test14.html +82 -18
- data/test/manual/banner-tests/test15.html +82 -18
- data/test/manual/banner-tests/test16.html +82 -18
- data/test/manual/banner-tests/test17.html +82 -18
- data/test/manual/banner-tests/test18.html +90 -26
- data/test/manual/banner-tests/test19.html +90 -26
- data/test/manual/banner-tests/test20.html +90 -26
- data/test/manual/banner-tests/test21.html +90 -26
- data/test/manual/banner-tests/test22.html +90 -26
- data/test/manual/banner-tests/test23.html +90 -26
- data/test/manual/banner-tests/test24.html +90 -26
- data/test/manual/banner-tests/test25.html +89 -25
- data/test/manual/banner_environment.rb +15 -2
- data/test/manual/codemirror_demo.html +773 -0
- data/test/manual/create_posts_for_web.rb +114 -0
- data/test/manual/preview_manual_test.rb +129 -0
- data/test/manual/test_banner_features.rb +14 -14
- data/test/manual/test_banner_integration.rb +115 -0
- data/test/manual/test_banner_radial.rb +87 -0
- data/test/manual/test_syntax_highlighting.rb +60 -40
- data/test/support/preview_utils.rb +88 -0
- data/test/test_gem_assets.rb +48 -0
- data/test/test_helpers.rb +10 -0
- data/test/tui_editor_integration_test.rb +15 -15
- data/test/tui_integration_test.rb +687 -441
- data/test/unit/api.rb +757 -37
- data/test/unit/asset_management.rb +195 -221
- data/test/unit/backup_test.rb +451 -0
- data/test/unit/contract_test.rb +1 -23
- data/test/unit/core.rb +415 -61
- data/test/unit/deploy_config_test.rb +248 -0
- data/test/unit/deploy_test.rb +312 -21
- data/test/unit/edit_post_test.rb +168 -0
- data/test/unit/gem_asset_management.rb +36 -42
- data/test/unit/livetext_basic.rb +23 -35
- data/test/unit/livetext_compatibility.rb +7 -14
- data/test/unit/parse_cmd_test.rb +260 -0
- data/test/unit/{symlink_test.rb → permalink_copy_test.rb} +47 -49
- data/test/unit/post.rb +91 -26
- 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 +8 -6
- data/test/unit/repo.rb +75 -54
- data/test/unit/social_test.rb +41 -44
- data/test/unit/syntax_highlighting.rb +70 -0
- data/test/unit/theme_management_test.rb +91 -0
- data/test/unit/view.rb +79 -12
- data/test/unit/widgets.rb +8 -8
- 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/ui/tui/bin/scriptorium +885 -415
- data/ui/web/app/app.rb +1398 -176
- data/ui/web/app/assets/livetext_mode.js +244 -0
- data/ui/web/app/error_helpers.rb +16 -16
- data/ui/web/app/views/advanced_config.erb +8 -2
- data/ui/web/app/views/asset_management.erb +56 -0
- data/ui/web/app/views/backup_management.erb +238 -0
- data/ui/web/app/views/config_widget.erb +232 -0
- data/ui/web/app/views/dashboard.erb +64 -72
- data/ui/web/app/views/deploy_config.erb +3 -0
- data/ui/web/app/views/edit_pages.erb +170 -2
- data/ui/web/app/views/edit_post.erb +130 -9
- 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/theme_management.erb +130 -0
- data/ui/web/app/views/view_dashboard.erb +666 -25
- data/ui/web/app/views/widgets.erb +249 -0
- data/ui/web/bin/scriptorium-web +35 -24
- data/ui/web/tmp/timing.log +17 -0
- data/ui/web/tmp/web_server.log +0 -5
- metadata +190 -116
- data/assets/back-icon.png +0 -0
- data/assets/icons/facebook.svg +0 -1
- data/assets/icons/github.svg +0 -1
- data/assets/icons/instagram.svg +0 -1
- data/assets/icons/reddit.svg +0 -1
- data/assets/icons/x.svg +0 -1
- data/assets/icons/youtube.svg +0 -1
- data/bin/scriptorium +0 -1511
- data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +0 -34
- data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +0 -50
- data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +0 -73
- data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +0 -70
- data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +0 -110
- data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +0 -73
- data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +0 -124
- data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +0 -46
- data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +0 -97
- data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +0 -211
- data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +0 -141
- data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +0 -211
- data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +0 -134
- data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +0 -41
- data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +0 -49
- data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +0 -46
- data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +0 -41
- data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +0 -41
- data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +0 -256
- data/lib/scriptorium/syntax_highlighter.rb +0 -234
- data/test/manual/deploy_symlink_demo.rb +0 -142
- data/test/manual/symlink_demo.rb +0 -117
- data/test/manual/test2.rb +0 -12
- data/test/manual/test_banner_from_file.rb +0 -150
- data/test/manual/test_banner_in_header.rb +0 -35
- data/test/manual/test_code_highlighting.rb +0 -68
- data/test/manual/test_complex_header.rb +0 -74
- data/test/manual/test_empty_header.rb +0 -32
- data/test/manual/test_radial_custom.rb +0 -58
- data/test/manual/test_radial_large_radius.rb +0 -52
- data/test/manual/test_svg_debug.rb +0 -47
- data/test/pages-demo/config/currentview.txt +0 -1
- data/test/pages-demo/views/demo/config/common.js +0 -57
- data/test/pages-demo/views/demo/config/footer.txt +0 -1
- data/test/pages-demo/views/demo/config/global-head.txt +0 -8
- data/test/pages-demo/views/demo/config/header.txt +0 -1
- data/test/pages-demo/views/demo/config/layout.txt +0 -1
- data/test/pages-demo/views/demo/config/left.txt +0 -1
- data/test/pages-demo/views/demo/config/main.txt +0 -1
- data/test/pages-demo/views/demo/config/right.txt +0 -1
- data/test/pages-demo/views/demo/config.txt +0 -3
- data/test/pages-demo/views/demo/output/panes/footer.html +0 -1
- data/test/pages-demo/views/demo/output/panes/header.html +0 -1
- data/test/pages-demo/views/demo/output/panes/left.html +0 -1
- data/test/pages-demo/views/demo/output/panes/main.html +0 -1
- data/test/pages-demo/views/demo/output/panes/right.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +0 -4
- data/test/scriptorium-TEST-1754622690-146/config/common.js +0 -57
- data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +0 -1
- data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +0 -9
- data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +0 -1
- data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +0 -4
- data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +0 -3
- data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +0 -8
- data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +0 -6
- data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +0 -1
- data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +0 -1
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +0 -1
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +0 -1
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +0 -14
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +0 -13
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +0 -4
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +0 -57
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +0 -2
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +0 -9
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +0 -4
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +0 -5
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +0 -7
- data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +0 -3
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +0 -1
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +0 -1
- data/ui/web/tmp/web_server.pid +0 -1
- /data/{test/pages-demo/views/demo/config/bootstrap_css.txt → lib/scriptorium/support/bootstrap/css.txt} +0 -0
- /data/{test/pages-demo/views/demo/config/bootstrap_js.txt → lib/scriptorium/support/bootstrap/js.txt} +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/views/sample → lib/scriptorium/support}/config/reddit.txt +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout → lib/scriptorium/support/templates}/layout.txt +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt → lib/scriptorium/support/theme/footer.lt3} +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt → lib/scriptorium/support/theme/left.lt3} +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt → lib/scriptorium/support/theme/main.lt3} +0 -0
- /data/{test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt → lib/scriptorium/support/theme/right.lt3} +0 -0
- /data/test/manual/banner-tests/{config.txt → svg.txt} +0 -0
- /data/test/manual/{test6.rb → test_advanced_widgets.rb} +0 -0
- /data/test/manual/{test1.rb → test_basic_posts.rb} +0 -0
- /data/test/manual/{test4.rb → test_layout_widgets.rb} +0 -0
- /data/test/manual/{test5.rb → test_pagination.rb} +0 -0
- /data/test/manual/{test3.rb → test_random_posts.rb} +0 -0
@@ -0,0 +1,451 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'json'
|
6
|
+
require_relative '../../lib/scriptorium'
|
7
|
+
require_relative '../test_helpers'
|
8
|
+
|
9
|
+
class BackupTestFixed < Minitest::Test
|
10
|
+
include Scriptorium::Exceptions
|
11
|
+
include Scriptorium::Helpers
|
12
|
+
|
13
|
+
def setup
|
14
|
+
@test_dir = "test/scriptorium-TEST"
|
15
|
+
# Clean up any existing test directory first
|
16
|
+
FileUtils.rm_rf(@test_dir) if Dir.exist?(@test_dir)
|
17
|
+
@api = Scriptorium::API.new(testmode: true)
|
18
|
+
@api.create_repo(@test_dir)
|
19
|
+
end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
FileUtils.rm_rf(@test_dir) if Dir.exist?(@test_dir)
|
23
|
+
# Clean up backup directory too
|
24
|
+
if @api
|
25
|
+
backup_dir = @api.get_backup_directory
|
26
|
+
FileUtils.rm_rf(backup_dir) if Dir.exist?(backup_dir)
|
27
|
+
end
|
28
|
+
@api = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
private def count_posts_in_compressed_backup(backup_dir)
|
32
|
+
tar_gz_path = backup_dir/"data.tar.gz"
|
33
|
+
return 0 unless File.exist?(tar_gz_path)
|
34
|
+
|
35
|
+
# Use tar -tf to list files and count posts directories
|
36
|
+
output = `tar -tf '#{tar_gz_path}' 2>/dev/null`
|
37
|
+
return 0 unless $?.success?
|
38
|
+
|
39
|
+
# Count unique post directories (tar output has ./ prefix)
|
40
|
+
post_dirs = output.lines.select { |line| line.strip.match(/^\.\/posts\/\d+\//) }
|
41
|
+
post_dirs.map { |line| line.strip.split('/')[2] }.uniq.length
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_001_create_full_backup
|
45
|
+
# Create some test content
|
46
|
+
@api.create_view("test-view", "Test View", "A test view")
|
47
|
+
@api.create_post("Test Post", "This is a test post", views: "test-view")
|
48
|
+
|
49
|
+
# Create a full backup
|
50
|
+
backup_name = @api.create_backup(type: :full, label: "test-backup")
|
51
|
+
|
52
|
+
# Verify backup was created
|
53
|
+
assert_match(/^\d{8}-\d{6}-full$/, backup_name)
|
54
|
+
|
55
|
+
backup_dir = @api.get_backup_directory/"data"/backup_name
|
56
|
+
assert Dir.exist?(backup_dir), "Backup directory should exist"
|
57
|
+
|
58
|
+
# Verify compressed backup structure
|
59
|
+
assert File.exist?(backup_dir/"data.tar.gz"), "Compressed backup data should exist"
|
60
|
+
|
61
|
+
# Verify backup info file exists (uncompressed)
|
62
|
+
assert File.exist?(backup_dir/"backup-info.txt"), "Backup info file should exist"
|
63
|
+
|
64
|
+
# Verify manifest was created
|
65
|
+
manifest_file = @api.get_backup_directory/"manifest.txt"
|
66
|
+
assert File.exist?(manifest_file), "Backup manifest should exist"
|
67
|
+
|
68
|
+
manifest_content = File.read(manifest_file)
|
69
|
+
assert_includes manifest_content, backup_name, "Backup should be in manifest"
|
70
|
+
assert_includes manifest_content, "test-backup", "Label should be in manifest"
|
71
|
+
|
72
|
+
# Verify backup info file was created
|
73
|
+
backup_info_file = backup_dir/"backup-info.txt"
|
74
|
+
assert File.exist?(backup_info_file), "Backup info file should exist"
|
75
|
+
|
76
|
+
info_content = File.read(backup_info_file)
|
77
|
+
assert_includes info_content, "scriptorium_version:", "Should contain scriptorium version"
|
78
|
+
assert_includes info_content, "livetext_version:", "Should contain livetext version"
|
79
|
+
assert_includes info_content, "ruby_version:", "Should contain ruby version"
|
80
|
+
assert_includes info_content, "backup_type: full", "Should contain backup type"
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_002_create_incremental_backup
|
84
|
+
# Create some test content
|
85
|
+
@api.create_view("test-view", "Test View", "A test view")
|
86
|
+
@api.create_post("Test Post", "This is a test post", views: "test-view")
|
87
|
+
|
88
|
+
# Create an incremental backup
|
89
|
+
backup_name = @api.create_backup(type: :incremental, label: "incremental-test")
|
90
|
+
|
91
|
+
# Verify backup was created
|
92
|
+
assert_match(/^\d{8}-\d{6}-incr$/, backup_name)
|
93
|
+
|
94
|
+
backup_dir = @api.get_backup_directory/"data"/backup_name
|
95
|
+
assert Dir.exist?(backup_dir), "Backup directory should exist"
|
96
|
+
|
97
|
+
# Verify compressed backup structure
|
98
|
+
assert File.exist?(backup_dir/"data.tar.gz"), "Compressed backup data should exist"
|
99
|
+
|
100
|
+
# Verify manifest was created
|
101
|
+
manifest_file = @api.get_backup_directory/"manifest.txt"
|
102
|
+
assert File.exist?(manifest_file), "Backup manifest should exist"
|
103
|
+
|
104
|
+
manifest_content = File.read(manifest_file)
|
105
|
+
assert_includes manifest_content, backup_name, "Backup should be in manifest"
|
106
|
+
assert_includes manifest_content, "incremental-test", "Label should be in manifest"
|
107
|
+
|
108
|
+
# Verify backup info file was created
|
109
|
+
backup_info_file = backup_dir/"backup-info.txt"
|
110
|
+
assert File.exist?(backup_info_file), "Backup info file should exist"
|
111
|
+
|
112
|
+
info_content = File.read(backup_info_file)
|
113
|
+
assert_includes info_content, "scriptorium_version:", "Should contain scriptorium version"
|
114
|
+
assert_includes info_content, "livetext_version:", "Should contain livetext version"
|
115
|
+
assert_includes info_content, "ruby_version:", "Should contain ruby version"
|
116
|
+
assert_includes info_content, "backup_type: incremental", "Should contain backup type"
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_003_list_backups
|
120
|
+
# Create multiple backups
|
121
|
+
backup1 = @api.create_backup(type: :full, label: "first")
|
122
|
+
sleep(1) # Ensure different timestamps
|
123
|
+
backup2 = @api.create_backup(type: :incremental, label: "second")
|
124
|
+
|
125
|
+
# List backups
|
126
|
+
backups = @api.list_backups
|
127
|
+
|
128
|
+
assert_equal 2, backups.length, "Should have 2 backups"
|
129
|
+
|
130
|
+
# Should be sorted by creation time, newest first
|
131
|
+
assert_equal backup2, backups[0][:name], "Newest backup should be first"
|
132
|
+
assert_equal backup1, backups[1][:name], "Older backup should be second"
|
133
|
+
|
134
|
+
# Verify backup info
|
135
|
+
backup_info = backups[0]
|
136
|
+
assert_equal backup2, backup_info[:name]
|
137
|
+
assert_equal :incremental, backup_info[:type]
|
138
|
+
assert_equal "second", backup_info[:description]
|
139
|
+
assert backup_info[:timestamp].is_a?(Time)
|
140
|
+
assert backup_info[:size].is_a?(Integer)
|
141
|
+
assert backup_info[:file_count].is_a?(Integer)
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_004_restore_backup_safe_strategy
|
145
|
+
# Create initial content
|
146
|
+
@api.create_view("test-view", "Test View", "A test view")
|
147
|
+
@api.create_post("Original Post", "Original content", views: "test-view")
|
148
|
+
|
149
|
+
# Create a backup
|
150
|
+
backup_name = @api.create_backup(type: :full, label: "before-changes")
|
151
|
+
|
152
|
+
# Modify content
|
153
|
+
@api.create_post("New Post", "New content", views: "test-view")
|
154
|
+
|
155
|
+
# Restore from backup using safe strategy (default)
|
156
|
+
result = @api.restore_backup(backup_name, strategy: :safe)
|
157
|
+
assert result.is_a?(Hash), "Restore should return a hash"
|
158
|
+
assert_equal backup_name, result[:restored], "Should return the restored backup name"
|
159
|
+
assert result[:pre_restore], "Should have created a pre-restore backup"
|
160
|
+
|
161
|
+
# Verify content was restored
|
162
|
+
posts = @api.posts("test-view")
|
163
|
+
assert_equal 1, posts.length, "Should have only 1 post after restore"
|
164
|
+
assert_equal "Original Post", posts[0].title, "Should have original post"
|
165
|
+
|
166
|
+
# Verify pre-restore backup was created
|
167
|
+
backups = @api.list_backups
|
168
|
+
pre_restore = backups.find { |b| b[:description]&.include?("pre-restore") }
|
169
|
+
assert pre_restore, "Should have created a pre-restore backup"
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_004b_restore_backup_destroy_strategy
|
173
|
+
# Create initial content
|
174
|
+
@api.create_view("test-view", "Test View", "A test view")
|
175
|
+
@api.create_post("Original Post", "Original content", views: "test-view")
|
176
|
+
|
177
|
+
# Create a backup
|
178
|
+
backup_name = @api.create_backup(type: :full, label: "before-changes")
|
179
|
+
|
180
|
+
# Modify content
|
181
|
+
@api.create_post("New Post", "New content", views: "test-view")
|
182
|
+
|
183
|
+
# Restore from backup using destroy strategy
|
184
|
+
result = @api.restore_backup(backup_name, strategy: :destroy)
|
185
|
+
assert result.is_a?(Hash), "Restore should return a hash"
|
186
|
+
assert_equal backup_name, result[:restored], "Should return the restored backup name"
|
187
|
+
assert_equal :destroy, result[:strategy], "Should indicate destroy strategy"
|
188
|
+
|
189
|
+
# Verify content was restored
|
190
|
+
posts = @api.posts("test-view")
|
191
|
+
assert_equal 1, posts.length, "Should have only 1 post after restore"
|
192
|
+
assert_equal "Original Post", posts[0].title, "Should have original post"
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_004c_restore_backup_merge_strategy
|
196
|
+
# Create initial content
|
197
|
+
@api.create_view("test-view", "Test View", "A test view")
|
198
|
+
@api.create_post("Original Post", "Original content", views: "test-view")
|
199
|
+
|
200
|
+
# Create a backup
|
201
|
+
backup_name = @api.create_backup(type: :full, label: "before-changes")
|
202
|
+
|
203
|
+
# Modify content
|
204
|
+
@api.create_post("New Post", "New content", views: "test-view")
|
205
|
+
|
206
|
+
# Restore from backup using merge strategy
|
207
|
+
result = @api.restore_backup(backup_name, strategy: :merge)
|
208
|
+
assert result.is_a?(Hash), "Restore should return a hash"
|
209
|
+
assert_equal backup_name, result[:restored], "Should return the restored backup name"
|
210
|
+
assert_equal :merge, result[:strategy], "Should indicate merge strategy"
|
211
|
+
|
212
|
+
# Verify content was restored (merge should keep existing files)
|
213
|
+
posts = @api.posts("test-view")
|
214
|
+
assert_equal 2, posts.length, "Should have 2 posts after merge restore"
|
215
|
+
post_titles = posts.map(&:title).sort
|
216
|
+
assert_equal ["New Post", "Original Post"], post_titles, "Should have both posts"
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_005_delete_backup
|
220
|
+
# Create a backup
|
221
|
+
backup_name = @api.create_backup(type: :full, label: "to-delete")
|
222
|
+
|
223
|
+
# Verify it exists
|
224
|
+
backups = @api.list_backups
|
225
|
+
assert_equal 1, backups.length, "Should have 1 backup"
|
226
|
+
|
227
|
+
# Delete the backup
|
228
|
+
result = @api.delete_backup(backup_name)
|
229
|
+
assert result, "Delete should succeed"
|
230
|
+
|
231
|
+
# Verify it's gone
|
232
|
+
backups = @api.list_backups
|
233
|
+
assert_equal 0, backups.length, "Should have 0 backups after delete"
|
234
|
+
|
235
|
+
# Verify directory is gone
|
236
|
+
backup_dir = @api.get_backup_directory/"data"/backup_name
|
237
|
+
assert !Dir.exist?(backup_dir), "Backup directory should be deleted"
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_006_incremental_backup_tracks_changes
|
241
|
+
# Create initial content and full backup first
|
242
|
+
@api.create_view("test-view", "Test View", "A test view")
|
243
|
+
@api.create_post("Post 1", "Content 1", views: "test-view")
|
244
|
+
|
245
|
+
|
246
|
+
backup1 = @api.create_backup(type: :full, label: "initial")
|
247
|
+
|
248
|
+
# Now add new content and create incremental backup
|
249
|
+
@api.create_post("Post 2", "Content 2", views: "test-view")
|
250
|
+
backup2 = @api.create_backup(type: :incremental, label: "after-changes")
|
251
|
+
|
252
|
+
# Verify backups contain expected content
|
253
|
+
backup1_dir = @api.get_backup_directory/"data"/backup1
|
254
|
+
backup2_dir = @api.get_backup_directory/"data"/backup2
|
255
|
+
|
256
|
+
# Full backup should have 1 post (check compressed content)
|
257
|
+
backup1_posts = count_posts_in_compressed_backup(backup1_dir)
|
258
|
+
assert_equal 1, backup1_posts, "Full backup should have 1 post"
|
259
|
+
|
260
|
+
# Incremental backup should have 2 posts (both posts, since post creation modifies existing files)
|
261
|
+
backup2_posts = count_posts_in_compressed_backup(backup2_dir)
|
262
|
+
assert_equal 2, backup2_posts, "Incremental backup should have 2 posts (both posts, since post creation modifies existing files)"
|
263
|
+
|
264
|
+
# Verify the incremental backup contains the new post
|
265
|
+
# Extract and check compressed content
|
266
|
+
temp_extract_dir = backup2_dir/"temp_extract"
|
267
|
+
FileUtils.mkdir_p(temp_extract_dir)
|
268
|
+
|
269
|
+
begin
|
270
|
+
# Extract tar.gz to temporary directory
|
271
|
+
system("tar -xzf '#{backup2_dir}/data.tar.gz' -C '#{temp_extract_dir}'")
|
272
|
+
assert $?.success?, "Should successfully extract compressed backup"
|
273
|
+
|
274
|
+
# Check for post directories
|
275
|
+
backup2_post_dirs = Dir.glob("#{temp_extract_dir}/posts/*")
|
276
|
+
assert_equal 2, backup2_post_dirs.length, "Should have exactly two post directories"
|
277
|
+
|
278
|
+
# The incremental backup should contain both posts
|
279
|
+
# Check that both post directories exist and contain the expected content
|
280
|
+
post_dirs = backup2_post_dirs.sort
|
281
|
+
|
282
|
+
# Check first post (0001)
|
283
|
+
source_file_1 = "#{post_dirs[0]}/source.lt3"
|
284
|
+
assert File.exist?(source_file_1), "Source file should exist for post 1"
|
285
|
+
content_1 = File.read(source_file_1)
|
286
|
+
assert_includes content_1, "Post 1", "Should contain Post 1"
|
287
|
+
|
288
|
+
# Check second post (0002)
|
289
|
+
source_file_2 = "#{post_dirs[1]}/source.lt3"
|
290
|
+
assert File.exist?(source_file_2), "Source file should exist for post 2"
|
291
|
+
content_2 = File.read(source_file_2)
|
292
|
+
assert_includes content_2, "Post 2", "Should contain Post 2"
|
293
|
+
ensure
|
294
|
+
# Clean up temporary directory
|
295
|
+
FileUtils.rm_rf(temp_extract_dir) if Dir.exist?(temp_extract_dir)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_007_backup_validation
|
300
|
+
# Temporarily enable contracts for this test
|
301
|
+
original_dbc = ENV['DBC_DISABLED']
|
302
|
+
ENV['DBC_DISABLED'] = nil
|
303
|
+
|
304
|
+
begin
|
305
|
+
# Test invalid backup type - this should fail the assume check
|
306
|
+
assert_raises(RuntimeError) do
|
307
|
+
@api.create_backup(type: :invalid)
|
308
|
+
end
|
309
|
+
|
310
|
+
# Test with nil repo - this should fail the assume check
|
311
|
+
api_no_repo = Scriptorium::API.new(testmode: true)
|
312
|
+
assert_raises(RuntimeError) do
|
313
|
+
api_no_repo.create_backup(type: :full)
|
314
|
+
end
|
315
|
+
ensure
|
316
|
+
# Restore original contract setting
|
317
|
+
ENV['DBC_DISABLED'] = original_dbc
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
def test_008_restore_nonexistent_backup
|
322
|
+
# Try to restore a backup that doesn't exist
|
323
|
+
assert_raises(BackupNotFound) do
|
324
|
+
@api.restore_backup("nonexistent-backup")
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_009_delete_nonexistent_backup
|
329
|
+
# Try to delete a backup that doesn't exist
|
330
|
+
assert_raises(BackupNotFound) do
|
331
|
+
@api.delete_backup("nonexistent-backup")
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_010_restore_incremental_backup_with_dependencies
|
336
|
+
# Create initial content
|
337
|
+
@api.create_view("test-view", "Test View", "A test view")
|
338
|
+
@api.create_post("Post 1", "Content 1", views: "test-view")
|
339
|
+
|
340
|
+
# Create full backup
|
341
|
+
full_backup = @api.create_backup(type: :full, label: "initial")
|
342
|
+
sleep(1) # Ensure different timestamps
|
343
|
+
|
344
|
+
# Add more content
|
345
|
+
@api.create_post("Post 2", "Content 2", views: "test-view")
|
346
|
+
|
347
|
+
# Create incremental backup
|
348
|
+
incr_backup = @api.create_backup(type: :incremental, label: "after-post-2")
|
349
|
+
sleep(1) # Ensure different timestamps
|
350
|
+
|
351
|
+
# Add more content
|
352
|
+
@api.create_post("Post 3", "Content 3", views: "test-view")
|
353
|
+
|
354
|
+
# Restore from incremental backup using safe strategy
|
355
|
+
result = @api.restore_backup(incr_backup, strategy: :safe)
|
356
|
+
assert result.is_a?(Hash), "Restore should return a hash"
|
357
|
+
assert_equal incr_backup, result[:restored], "Should return the restored backup name"
|
358
|
+
assert result[:pre_restore], "Should have created a pre-restore backup"
|
359
|
+
|
360
|
+
# Verify content was restored correctly (should have Post 1 and Post 2)
|
361
|
+
posts = @api.posts("test-view")
|
362
|
+
assert_equal 2, posts.length, "Should have 2 posts after restore"
|
363
|
+
post_titles = posts.map(&:title).sort
|
364
|
+
assert_equal ["Post 1", "Post 2"], post_titles, "Should have correct posts"
|
365
|
+
end
|
366
|
+
|
367
|
+
def test_011_restore_invalid_strategy
|
368
|
+
# Create a backup first
|
369
|
+
@api.create_view("test-view", "Test View", "A test view")
|
370
|
+
@api.create_post("Test Post", "Test content", views: "test-view")
|
371
|
+
backup_name = @api.create_backup(type: :full, label: "test")
|
372
|
+
|
373
|
+
# Try to restore with invalid strategy
|
374
|
+
assert_raises(ArgumentError) do
|
375
|
+
@api.restore_backup(backup_name, strategy: :invalid)
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
def test_012_restore_default_strategy_is_safe
|
380
|
+
# Create initial content
|
381
|
+
@api.create_view("test-view", "Test View", "A test view")
|
382
|
+
@api.create_post("Original Post", "Original content", views: "test-view")
|
383
|
+
|
384
|
+
# Create a backup
|
385
|
+
backup_name = @api.create_backup(type: :full, label: "before-changes")
|
386
|
+
|
387
|
+
# Modify content
|
388
|
+
@api.create_post("New Post", "New content", views: "test-view")
|
389
|
+
|
390
|
+
# Restore from backup without specifying strategy (should default to :safe)
|
391
|
+
result = @api.restore_backup(backup_name)
|
392
|
+
assert result.is_a?(Hash), "Restore should return a hash"
|
393
|
+
assert_equal backup_name, result[:restored], "Should return the restored backup name"
|
394
|
+
assert result[:pre_restore], "Should have created a pre-restore backup (default is safe)"
|
395
|
+
|
396
|
+
# Verify content was restored
|
397
|
+
posts = @api.posts("test-view")
|
398
|
+
assert_equal 1, posts.length, "Should have only 1 post after restore"
|
399
|
+
assert_equal "Original Post", posts[0].title, "Should have original post"
|
400
|
+
end
|
401
|
+
|
402
|
+
def test_013_restore_with_pre_restore_backup_timestamp_handling
|
403
|
+
# Create initial content
|
404
|
+
@api.create_view("test-view", "Test View", "A test view")
|
405
|
+
@api.create_post("Original Post", "Original content", views: "test-view")
|
406
|
+
|
407
|
+
# Create a backup
|
408
|
+
backup_name = @api.create_backup(type: :full, label: "before-changes")
|
409
|
+
|
410
|
+
# Modify content
|
411
|
+
@api.create_post("New Post", "New content", views: "test-view")
|
412
|
+
|
413
|
+
# Restore from backup using safe strategy
|
414
|
+
result = @api.restore_backup(backup_name, strategy: :safe)
|
415
|
+
|
416
|
+
# Verify that the pre-restore backup was created and is not used as the base for restore
|
417
|
+
backups = @api.list_backups
|
418
|
+
pre_restore = backups.find { |b| b[:description]&.include?("pre-restore") }
|
419
|
+
assert pre_restore, "Should have created a pre-restore backup"
|
420
|
+
|
421
|
+
# The pre-restore backup should not be the same as the original backup
|
422
|
+
refute_equal backup_name, pre_restore[:name], "Pre-restore backup should be different from original"
|
423
|
+
|
424
|
+
# Verify content was restored correctly
|
425
|
+
posts = @api.posts("test-view")
|
426
|
+
assert_equal 1, posts.length, "Should have only 1 post after restore"
|
427
|
+
assert_equal "Original Post", posts[0].title, "Should have original post"
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_014_merge_strategy_preserves_existing_files
|
431
|
+
# Create initial content
|
432
|
+
@api.create_view("test-view", "Test View", "A test view")
|
433
|
+
@api.create_post("Original Post", "Original content", views: "test-view")
|
434
|
+
|
435
|
+
# Create a backup
|
436
|
+
backup_name = @api.create_backup(type: :full, label: "before-changes")
|
437
|
+
|
438
|
+
# Add content that should be preserved
|
439
|
+
@api.create_post("Keep This Post", "This should be kept", views: "test-view")
|
440
|
+
|
441
|
+
# Restore from backup using merge strategy
|
442
|
+
result = @api.restore_backup(backup_name, strategy: :merge)
|
443
|
+
|
444
|
+
# Verify both posts exist (merge should preserve existing files)
|
445
|
+
posts = @api.posts("test-view")
|
446
|
+
assert_equal 2, posts.length, "Should have 2 posts after merge restore"
|
447
|
+
post_titles = posts.map(&:title).sort
|
448
|
+
assert_equal ["Keep This Post", "Original Post"], post_titles, "Should have both posts"
|
449
|
+
end
|
450
|
+
|
451
|
+
end
|
data/test/unit/contract_test.rb
CHANGED
@@ -65,27 +65,5 @@ class TestContract < Minitest::Test
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
|
69
|
-
# Enable DBC
|
70
|
-
ENV['DBC_DISABLED'] = nil
|
71
|
-
|
72
|
-
begin
|
73
|
-
post = @repo.create_post(title: "Test Post", body: "Test body")
|
74
|
-
|
75
|
-
# Test save_metadata contracts
|
76
|
-
post.meta["post.title"] = "Updated Title"
|
77
|
-
post.save_metadata # Should not raise
|
78
|
-
|
79
|
-
# Test deleted= contracts
|
80
|
-
post.deleted = true # Should not raise
|
81
|
-
assert post.deleted == true
|
82
|
-
|
83
|
-
post.deleted = false # Should not raise
|
84
|
-
assert post.deleted == false
|
85
|
-
|
86
|
-
ensure
|
87
|
-
# Restore disabled state
|
88
|
-
ENV['DBC_DISABLED'] = 'true'
|
89
|
-
end
|
90
|
-
end
|
68
|
+
|
91
69
|
end
|