scriptorium 0.0.2 → 0.6.1
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/back-icon.png +0 -0
- data/assets/icons/facebook.svg +1 -0
- data/assets/icons/github.svg +1 -0
- data/assets/icons/instagram.svg +1 -0
- data/assets/icons/reddit.svg +1 -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/icons/x.svg +1 -0
- data/assets/icons/youtube.svg +1 -0
- data/assets/samples/placeholder.svg +9 -0
- data/assets/themes/standard/favicon.svg +6 -0
- data/bin/scriptorium +1511 -0
- data/doc/README.txt +6 -0
- data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +95 -0
- data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +34 -0
- data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +50 -0
- data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +31 -0
- data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +73 -0
- data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +64 -0
- data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +70 -0
- data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
- data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +110 -0
- data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +73 -0
- data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
- data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +124 -0
- data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +46 -0
- data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +97 -0
- data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
- data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +211 -0
- data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +141 -0
- data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +211 -0
- data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +134 -0
- data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +41 -0
- data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +45 -0
- data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +30 -0
- data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +49 -0
- data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +46 -0
- data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +41 -0
- data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +41 -0
- data/doc/anti-amnesia/20250807-213025.md +116 -0
- data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +256 -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/reddit_credentials_template.json +8 -0
- data/doc/reddit_integration.md +207 -0
- data/doc/user.lt3 +38 -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/doc/userdoc-toc.txt +88 -0
- data/lib/rouge/lexers/livetext.rb +74 -0
- data/lib/scriptorium/api.rb +640 -0
- data/lib/scriptorium/banner_svg.rb +742 -0
- data/lib/scriptorium/contract.rb +33 -0
- data/lib/scriptorium/exceptions.rb +174 -0
- data/lib/scriptorium/helpers.rb +475 -0
- data/lib/scriptorium/post.rb +195 -0
- data/lib/scriptorium/reddit.rb +83 -0
- data/lib/scriptorium/repo.rb +624 -0
- data/lib/scriptorium/standard_files.rb +515 -0
- data/lib/scriptorium/syntax_highlighter.rb +234 -0
- data/lib/scriptorium/theme.rb +179 -0
- data/lib/scriptorium/version.rb +2 -2
- data/lib/scriptorium/view.rb +976 -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 +22 -9
- data/lib/skeleton.rb +11 -2
- data/scriptorium.gemspec +15 -4
- data/test/README.md +69 -0
- data/test/all +43 -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 +768 -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/livetext_plugin_test.rb +229 -0
- data/test/manual/asset_mgmt.rb +67 -0
- data/test/manual/banner-tests/config.txt +3 -0
- data/test/manual/banner-tests/index.html +45 -0
- data/test/manual/banner-tests/test01.html +58 -0
- data/test/manual/banner-tests/test02.html +58 -0
- data/test/manual/banner-tests/test03.html +58 -0
- data/test/manual/banner-tests/test04.html +65 -0
- data/test/manual/banner-tests/test05.html +65 -0
- data/test/manual/banner-tests/test06.html +65 -0
- data/test/manual/banner-tests/test07.html +65 -0
- data/test/manual/banner-tests/test08.html +59 -0
- data/test/manual/banner-tests/test09.html +59 -0
- data/test/manual/banner-tests/test10.html +59 -0
- data/test/manual/banner-tests/test11.html +59 -0
- data/test/manual/banner-tests/test12.html +59 -0
- data/test/manual/banner-tests/test13.html +59 -0
- data/test/manual/banner-tests/test14.html +59 -0
- data/test/manual/banner-tests/test15.html +58 -0
- data/test/manual/banner-tests/test16.html +58 -0
- data/test/manual/banner-tests/test17.html +58 -0
- data/test/manual/banner-tests/test18.html +68 -0
- data/test/manual/banner-tests/test19.html +68 -0
- data/test/manual/banner-tests/test20.html +68 -0
- data/test/manual/banner-tests/test21.html +68 -0
- data/test/manual/banner-tests/test22.html +68 -0
- data/test/manual/banner-tests/test23.html +68 -0
- data/test/manual/banner-tests/test24.html +68 -0
- data/test/manual/banner-tests/test25.html +67 -0
- data/test/manual/banner_environment.rb +192 -0
- data/test/manual/deploy_symlink_demo.rb +142 -0
- data/test/manual/environment.rb +67 -0
- data/test/manual/make_banner.rb +153 -0
- data/test/manual/sample_banner_config.txt +12 -0
- data/test/manual/symlink_demo.rb +117 -0
- data/test/manual/test1.rb +47 -0
- data/test/manual/test2.rb +12 -0
- data/test/manual/test3.rb +38 -0
- data/test/manual/test4.rb +40 -0
- data/test/manual/test5.rb +24 -0
- data/test/manual/test6.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_from_file.rb +150 -0
- data/test/manual/test_banner_in_header.rb +35 -0
- data/test/manual/test_code_highlighting.rb +68 -0
- data/test/manual/test_complex_header.rb +74 -0
- data/test/manual/test_empty_header.rb +32 -0
- data/test/manual/test_radial_custom.rb +58 -0
- data/test/manual/test_radial_large_radius.rb +52 -0
- data/test/manual/test_svg_debug.rb +47 -0
- data/test/manual/test_syntax_highlighting.rb +147 -0
- data/test/pages-demo/config/currentview.txt +1 -0
- data/test/pages-demo/views/demo/config/bootstrap_css.txt +5 -0
- data/test/pages-demo/views/demo/config/bootstrap_js.txt +4 -0
- data/test/pages-demo/views/demo/config/common.js +57 -0
- data/test/pages-demo/views/demo/config/footer.txt +1 -0
- data/test/pages-demo/views/demo/config/global-head.txt +8 -0
- data/test/pages-demo/views/demo/config/header.txt +1 -0
- data/test/pages-demo/views/demo/config/layout.txt +1 -0
- data/test/pages-demo/views/demo/config/left.txt +1 -0
- data/test/pages-demo/views/demo/config/main.txt +1 -0
- data/test/pages-demo/views/demo/config/right.txt +1 -0
- data/test/pages-demo/views/demo/config.txt +3 -0
- data/test/pages-demo/views/demo/output/panes/footer.html +1 -0
- data/test/pages-demo/views/demo/output/panes/header.html +1 -0
- data/test/pages-demo/views/demo/output/panes/left.html +1 -0
- data/test/pages-demo/views/demo/output/panes/main.html +1 -0
- data/test/pages-demo/views/demo/output/panes/right.html +1 -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/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +5 -0
- data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +4 -0
- data/test/scriptorium-TEST-1754622690-146/config/common.js +57 -0
- data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +1 -0
- data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +9 -0
- data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +1 -0
- data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +4 -0
- data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +3 -0
- data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +8 -0
- data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +6 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +1 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +1 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 +12 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt +2 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt +4 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt +3 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt +5 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt +3 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +1 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/layout.txt +5 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +1 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +14 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +13 -0
- data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +1 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +5 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +4 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +57 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +5 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +2 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +9 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +4 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +5 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +3 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +5 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/reddit.txt +10 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +3 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/social.txt +7 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +7 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +3 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +3 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +3 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +3 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +3 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +3 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +1 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +1 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +1 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +1 -0
- data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +1 -0
- data/test/staging/.DS_Store +0 -0
- data/test/syntax_highlighting_test.lt3 +124 -0
- data/test/test_helpers.rb +230 -0
- data/test/tui_editor_integration_test.rb +296 -0
- data/test/tui_integration_test.rb +637 -0
- data/test/unit/api.rb +1056 -0
- data/test/unit/asset_management.rb +245 -0
- data/test/unit/clipboard_test.rb +60 -0
- data/test/unit/contract_test.rb +91 -0
- data/test/unit/core.rb +857 -0
- data/test/unit/deploy_test.rb +187 -0
- data/test/unit/gem_asset_management.rb +189 -0
- data/test/unit/livetext_basic.rb +69 -0
- data/test/unit/livetext_compatibility.rb +89 -0
- data/test/unit/post.rb +244 -0
- data/test/unit/read_commented_file_test.rb +276 -0
- data/test/unit/reddit_test.rb +235 -0
- data/test/unit/repo.rb +548 -0
- data/test/unit/social_test.rb +369 -0
- data/test/unit/symlink_test.rb +213 -0
- data/test/unit/view.rb +431 -0
- data/test/unit/widgets.rb +669 -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 +1420 -0
- data/ui/tui/test/tui_test.rb +23 -0
- data/ui/web/app/app.rb +1378 -0
- data/ui/web/app/error_helpers.rb +150 -0
- data/ui/web/app/views/advanced_config.erb +190 -0
- data/ui/web/app/views/asset_management.erb +589 -0
- data/ui/web/app/views/banner_config.erb +200 -0
- data/ui/web/app/views/configure_view.erb +401 -0
- data/ui/web/app/views/dashboard.erb +162 -0
- data/ui/web/app/views/deploy_config.erb +146 -0
- data/ui/web/app/views/edit_pages.erb +195 -0
- data/ui/web/app/views/edit_post.erb +54 -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/view_dashboard.erb +138 -0
- data/ui/web/bin/scriptorium-web +153 -0
- data/ui/web/test/web_basic_test.rb +38 -0
- data/ui/web/test_navbar.txt +7 -0
- data/ui/web/tmp/web_server.log +5 -0
- data/ui/web/tmp/web_server.pid +1 -0
- metadata +360 -5
data/test/ed_test.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# This file tests that we can interact with 'ed' correctly for automated testing.
|
4
|
+
# We are NOT testing 'ed' itself - we assume 'ed' works correctly.
|
5
|
+
# We ARE testing that our test infrastructure can properly invoke 'ed'
|
6
|
+
# and handle its input/output/error streams for automated testing scenarios.
|
7
|
+
|
8
|
+
require 'minitest/autorun'
|
9
|
+
require 'pty'
|
10
|
+
require 'expect'
|
11
|
+
require 'tempfile'
|
12
|
+
|
13
|
+
class EdTest < Minitest::Test
|
14
|
+
def test_001_ed_basic_functionality_pty
|
15
|
+
# Test that ed can create and edit a file using PTY
|
16
|
+
temp_file = Tempfile.new(['test', '.txt'])
|
17
|
+
temp_file.close
|
18
|
+
|
19
|
+
PTY.spawn("ed #{temp_file.path}") do |read, write, pid|
|
20
|
+
begin
|
21
|
+
# Wait for ed to start
|
22
|
+
sleep 0.5
|
23
|
+
|
24
|
+
# Send ed commands
|
25
|
+
write.puts "a" # Enter append mode
|
26
|
+
write.puts "Hello world" # Add text
|
27
|
+
write.puts "This is a test" # Add more text
|
28
|
+
write.puts "." # Exit append mode
|
29
|
+
write.puts "w" # Write the file
|
30
|
+
write.puts "q" # Quit ed
|
31
|
+
|
32
|
+
# Wait for ed to exit
|
33
|
+
Process.wait(pid)
|
34
|
+
|
35
|
+
# Verify the file was written
|
36
|
+
content = File.read(temp_file.path)
|
37
|
+
assert_includes content, "Hello world"
|
38
|
+
assert_includes content, "This is a test"
|
39
|
+
|
40
|
+
ensure
|
41
|
+
Process.kill('TERM', pid) rescue nil
|
42
|
+
Process.wait(pid) rescue nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
temp_file.unlink
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_002_ed_file_creation_pty
|
50
|
+
# Test that ed can create a new file using PTY
|
51
|
+
temp_file = Tempfile.new(['new', '.txt'])
|
52
|
+
file_path = temp_file.path # Save the path before closing
|
53
|
+
temp_file.close
|
54
|
+
temp_file.unlink # Remove the file so ed creates it
|
55
|
+
|
56
|
+
PTY.spawn("ed") do |read, write, pid|
|
57
|
+
begin
|
58
|
+
# Wait for ed to start
|
59
|
+
sleep 0.5
|
60
|
+
|
61
|
+
# Send ed commands
|
62
|
+
write.puts "a"
|
63
|
+
write.puts "New file content"
|
64
|
+
write.puts "Created by ed"
|
65
|
+
write.puts "."
|
66
|
+
write.puts "w #{file_path}"
|
67
|
+
write.puts "q"
|
68
|
+
|
69
|
+
# Wait for ed to exit
|
70
|
+
Process.wait(pid)
|
71
|
+
|
72
|
+
# Verify the file was created
|
73
|
+
assert File.exist?(file_path), "File should be created"
|
74
|
+
|
75
|
+
# Verify the file has content
|
76
|
+
content = File.read(file_path)
|
77
|
+
assert_includes content, "New file content"
|
78
|
+
assert_includes content, "Created by ed"
|
79
|
+
|
80
|
+
ensure
|
81
|
+
Process.kill('TERM', pid) rescue nil
|
82
|
+
Process.wait(pid) rescue nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
File.unlink(file_path) if File.exist?(file_path)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_003_ed_simulate_edit_file_usage_pty
|
90
|
+
# Test how edit_file would use ed with PTY
|
91
|
+
temp_file = Tempfile.new(['test', '.txt'])
|
92
|
+
temp_file.close
|
93
|
+
|
94
|
+
PTY.spawn("ed #{temp_file.path}") do |read, write, pid|
|
95
|
+
begin
|
96
|
+
# Wait for ed to start
|
97
|
+
sleep 0.5
|
98
|
+
|
99
|
+
# Send ed commands (simulating what edit_file would do)
|
100
|
+
write.puts "a"
|
101
|
+
write.puts "Content added by edit_file"
|
102
|
+
write.puts "This simulates user input"
|
103
|
+
write.puts "."
|
104
|
+
write.puts "w"
|
105
|
+
write.puts "q"
|
106
|
+
|
107
|
+
# Wait for ed to exit
|
108
|
+
Process.wait(pid)
|
109
|
+
|
110
|
+
# Verify the file was modified
|
111
|
+
content = File.read(temp_file.path)
|
112
|
+
assert_includes content, "Content added by edit_file"
|
113
|
+
assert_includes content, "This simulates user input"
|
114
|
+
|
115
|
+
ensure
|
116
|
+
Process.kill('TERM', pid) rescue nil
|
117
|
+
Process.wait(pid) rescue nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
temp_file.unlink
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_004_ed_with_empty_file_pty
|
125
|
+
# Test ed behavior with an empty file using PTY
|
126
|
+
temp_file = Tempfile.new(['empty', '.txt'])
|
127
|
+
temp_file.close
|
128
|
+
|
129
|
+
PTY.spawn("ed #{temp_file.path}") do |read, write, pid|
|
130
|
+
begin
|
131
|
+
# Wait for ed to start
|
132
|
+
sleep 0.5
|
133
|
+
|
134
|
+
# Add content to empty file
|
135
|
+
write.puts "a"
|
136
|
+
write.puts "First line"
|
137
|
+
write.puts "Second line"
|
138
|
+
write.puts "."
|
139
|
+
write.puts "w"
|
140
|
+
write.puts "q"
|
141
|
+
|
142
|
+
# Wait for ed to exit
|
143
|
+
Process.wait(pid)
|
144
|
+
|
145
|
+
content = File.read(temp_file.path)
|
146
|
+
assert_includes content, "First line"
|
147
|
+
assert_includes content, "Second line"
|
148
|
+
|
149
|
+
ensure
|
150
|
+
Process.kill('TERM', pid) rescue nil
|
151
|
+
Process.wait(pid) rescue nil
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
temp_file.unlink
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_005_ed_which_command
|
159
|
+
# Test that ed is available on the system
|
160
|
+
require 'open3'
|
161
|
+
stdout, stderr, status = Open3.capture3("which ed")
|
162
|
+
|
163
|
+
assert_equal 0, status.exitstatus, "ed should be available on the system"
|
164
|
+
assert_includes stdout, "ed", "which should find ed"
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_006_ed_error_handling
|
168
|
+
# Test that ed handles errors gracefully
|
169
|
+
require 'open3'
|
170
|
+
stdout, stderr, status = Open3.capture3("ed /nonexistent/directory/file.txt", stdin_data: "q\n")
|
171
|
+
|
172
|
+
# ed should exit with an error
|
173
|
+
refute_equal 0, status.exitstatus, "ed should fail on non-existent directory"
|
174
|
+
end
|
175
|
+
|
176
|
+
def test_007_ed_stderr_behavior
|
177
|
+
# Test that ed puts error messages on stderr, not stdout
|
178
|
+
require 'open3'
|
179
|
+
temp_file = Tempfile.new(['stderr_test', '.txt'])
|
180
|
+
file_path = temp_file.path
|
181
|
+
temp_file.close
|
182
|
+
temp_file.unlink # Remove file so ed will give error
|
183
|
+
|
184
|
+
ed_commands = [
|
185
|
+
"a",
|
186
|
+
"Test content",
|
187
|
+
".",
|
188
|
+
"w #{file_path}", # Specify the file path in the write command
|
189
|
+
"q"
|
190
|
+
].join("\n")
|
191
|
+
|
192
|
+
stdout, stderr, status = Open3.capture3("ed", stdin_data: ed_commands)
|
193
|
+
|
194
|
+
# The error message should be on stderr (when we specify file on command line)
|
195
|
+
# But when we use 'w /path/to/file', there's no error
|
196
|
+
# stdout should contain the character count
|
197
|
+
refute_includes stdout, "No such file or directory", "Error should not be on stdout"
|
198
|
+
|
199
|
+
# The file should be created successfully
|
200
|
+
assert File.exist?(file_path), "File should be created"
|
201
|
+
|
202
|
+
File.unlink(file_path) if File.exist?(file_path)
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# Automated equivalents to manual banner combination tests
|
2
|
+
#
|
3
|
+
# These tests verify sensible combinations of banner features,
|
4
|
+
# but in an automated way that's meaningful for me to run in Cursor.
|
5
|
+
#
|
6
|
+
# Instead of visual browser inspection, these tests:
|
7
|
+
# - Generate config files with the same syntax as manual combination tests
|
8
|
+
# - Create BannerSVG instances with the same parameters
|
9
|
+
# - Parse the generated HTML/JavaScript output
|
10
|
+
# - Verify that multiple features work together correctly
|
11
|
+
# - Check that gradients, colors, text positioning, etc. are all applied
|
12
|
+
#
|
13
|
+
# NOTE: These tests may not use the exact same config values as manual tests.
|
14
|
+
# Manual tests focus on realistic, complex combinations for visual inspection,
|
15
|
+
# while these automated tests focus on simple, isolated feature verification
|
16
|
+
# for reliable automated testing. Both test the same underlying features
|
17
|
+
# but with different complexity levels appropriate to their purpose.
|
18
|
+
#
|
19
|
+
# This allows me to verify that banner features work together properly
|
20
|
+
# while you use the manual tests for visual inspection in the browser.
|
21
|
+
|
22
|
+
require_relative 'lib/scriptorium/banner_svg'
|
23
|
+
require 'fileutils'
|
24
|
+
|
25
|
+
class CursorBannerCombinationTests
|
26
|
+
def initialize
|
27
|
+
@test_dir = "cursor-combination-test-temp"
|
28
|
+
setup_test_directory
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_test_directory
|
32
|
+
FileUtils.rm_rf(@test_dir) if Dir.exist?(@test_dir)
|
33
|
+
Dir.mkdir(@test_dir)
|
34
|
+
end
|
35
|
+
|
36
|
+
def cleanup
|
37
|
+
FileUtils.rm_rf(@test_dir) if Dir.exist?(@test_dir)
|
38
|
+
end
|
39
|
+
|
40
|
+
def run_all_tests
|
41
|
+
puts "Running automated banner combination tests..."
|
42
|
+
puts "=" * 50
|
43
|
+
|
44
|
+
test_count = 0
|
45
|
+
pass_count = 0
|
46
|
+
|
47
|
+
# Combination tests
|
48
|
+
test_count += 1
|
49
|
+
pass_count += 1 if test_red_gradient_bold_center
|
50
|
+
test_count += 1
|
51
|
+
pass_count += 1 if test_blue_gradient_large_italic
|
52
|
+
test_count += 1
|
53
|
+
pass_count += 1 if test_green_radial_small_right
|
54
|
+
test_count += 1
|
55
|
+
pass_count += 1 if test_yellow_gradient_blue_text
|
56
|
+
test_count += 1
|
57
|
+
pass_count += 1 if test_complex_combination
|
58
|
+
|
59
|
+
puts "=" * 50
|
60
|
+
puts "Results: #{pass_count}/#{test_count} tests passed"
|
61
|
+
|
62
|
+
cleanup
|
63
|
+
pass_count == test_count
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_001_banner(config_content, title, subtitle, expectations)
|
67
|
+
# Write config file
|
68
|
+
File.write("#{@test_dir}/config.txt", config_content)
|
69
|
+
|
70
|
+
# Create banner and parse config
|
71
|
+
Dir.chdir(@test_dir) do
|
72
|
+
banner = BannerSVG.new(title, subtitle)
|
73
|
+
banner.parse_header_svg
|
74
|
+
js_output = banner.get_svg
|
75
|
+
|
76
|
+
# Check each expectation
|
77
|
+
expectations.each do |expectation|
|
78
|
+
case expectation[:type]
|
79
|
+
when :contains
|
80
|
+
unless js_output.include?(expectation[:value])
|
81
|
+
puts "❌ FAIL: Expected to contain '#{expectation[:value]}'"
|
82
|
+
return false
|
83
|
+
end
|
84
|
+
when :not_contains
|
85
|
+
if js_output.include?(expectation[:value])
|
86
|
+
puts "❌ FAIL: Expected NOT to contain '#{expectation[:value]}'"
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
when :instance_variable
|
90
|
+
actual_value = banner.instance_variable_get(expectation[:variable])
|
91
|
+
expected_value = expectation[:value]
|
92
|
+
unless actual_value == expected_value
|
93
|
+
puts "❌ FAIL: #{expectation[:variable]} expected '#{expected_value}', got '#{actual_value}'"
|
94
|
+
return false
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
puts "✅ PASS: #{title}"
|
100
|
+
true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Red gradient with bold text and center positioning
|
105
|
+
def test_002_red_gradient_bold_center
|
106
|
+
test_banner(
|
107
|
+
"back.linear red blue lr\ntitle.style bold\ntext.position center",
|
108
|
+
"Red Gradient Bold Center",
|
109
|
+
"Test",
|
110
|
+
[
|
111
|
+
{ type: :contains, value: "linearGradient" },
|
112
|
+
{ type: :contains, value: "stop-color:red" },
|
113
|
+
{ type: :contains, value: "stop-color:blue" },
|
114
|
+
{ type: :instance_variable, variable: :@title_weight, value: "bold" },
|
115
|
+
{ type: :instance_variable, variable: :@text_anchor, value: "middle" }
|
116
|
+
]
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Blue gradient with large text and italic style
|
121
|
+
def test_003_blue_gradient_large_italic
|
122
|
+
test_banner(
|
123
|
+
"back.linear blue green tb\ntitle.scale 1.2\ntitle.style italic",
|
124
|
+
"Blue Gradient Large Italic",
|
125
|
+
"Test",
|
126
|
+
[
|
127
|
+
{ type: :contains, value: "linearGradient" },
|
128
|
+
{ type: :contains, value: "stop-color:blue" },
|
129
|
+
{ type: :contains, value: "stop-color:green" },
|
130
|
+
{ type: :instance_variable, variable: :@title_scale, value: 1.2 },
|
131
|
+
{ type: :instance_variable, variable: :@title_style, value: "italic" }
|
132
|
+
]
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Green radial gradient with small text and right positioning
|
137
|
+
def test_004_green_radial_small_right
|
138
|
+
test_banner(
|
139
|
+
"back.radial green yellow\ntitle.scale 0.6\ntext.position right",
|
140
|
+
"Green Radial Small Right",
|
141
|
+
"Test",
|
142
|
+
[
|
143
|
+
{ type: :contains, value: "radialGradient" },
|
144
|
+
{ type: :contains, value: "stop-color:green" },
|
145
|
+
{ type: :contains, value: "stop-color:yellow" },
|
146
|
+
{ type: :instance_variable, variable: :@title_scale, value: 0.6 },
|
147
|
+
{ type: :instance_variable, variable: :@text_anchor, value: "end" }
|
148
|
+
]
|
149
|
+
)
|
150
|
+
end
|
151
|
+
|
152
|
+
# Yellow gradient with blue text
|
153
|
+
def test_005_yellow_gradient_blue_text
|
154
|
+
test_banner(
|
155
|
+
"back.linear yellow orange lr\ntext.color #0000ff",
|
156
|
+
"Yellow Gradient Blue Text",
|
157
|
+
"Test",
|
158
|
+
[
|
159
|
+
{ type: :contains, value: "linearGradient" },
|
160
|
+
{ type: :contains, value: "stop-color:yellow" },
|
161
|
+
{ type: :contains, value: "stop-color:orange" },
|
162
|
+
{ type: :instance_variable, variable: :@text_color, value: "#0000ff" }
|
163
|
+
]
|
164
|
+
)
|
165
|
+
end
|
166
|
+
|
167
|
+
# Complex combination with multiple features
|
168
|
+
def test_006_complex_combination
|
169
|
+
test_banner(
|
170
|
+
"back.radial red blue\ntitle.scale 1.1\nsubtitle.scale 0.6\ntitle.style bold italic\ntext.color #00ff00\ntext.position center",
|
171
|
+
"Complex Combination",
|
172
|
+
"Test Subtitle",
|
173
|
+
[
|
174
|
+
{ type: :contains, value: "radialGradient" },
|
175
|
+
{ type: :contains, value: "stop-color:red" },
|
176
|
+
{ type: :contains, value: "stop-color:blue" },
|
177
|
+
{ type: :instance_variable, variable: :@title_scale, value: 1.1 },
|
178
|
+
{ type: :instance_variable, variable: :@subtitle_scale, value: 0.6 },
|
179
|
+
{ type: :instance_variable, variable: :@title_weight, value: "bold" },
|
180
|
+
{ type: :instance_variable, variable: :@title_style, value: "italic" },
|
181
|
+
{ type: :instance_variable, variable: :@text_color, value: "#00ff00" },
|
182
|
+
{ type: :instance_variable, variable: :@text_anchor, value: "middle" }
|
183
|
+
]
|
184
|
+
)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Run the tests
|
189
|
+
if __FILE__ == $0
|
190
|
+
tests = CursorBannerCombinationTests.new
|
191
|
+
success = tests.run_all_tests
|
192
|
+
exit(success ? 0 : 1)
|
193
|
+
end
|