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.
Files changed (290) hide show
  1. checksums.yaml +4 -4
  2. data/README.lt3 +324 -0
  3. data/README.md +3155 -1
  4. data/assets/.DS_Store +0 -0
  5. data/assets/README.md +44 -0
  6. data/assets/back-icon.png +0 -0
  7. data/assets/icons/facebook.svg +1 -0
  8. data/assets/icons/github.svg +1 -0
  9. data/assets/icons/instagram.svg +1 -0
  10. data/assets/icons/reddit.svg +1 -0
  11. data/assets/icons/ui/.DS_Store +0 -0
  12. data/assets/icons/ui/back.png +0 -0
  13. data/assets/icons/ui/copy.png +0 -0
  14. data/assets/icons/ui/down.png +0 -0
  15. data/assets/icons/ui/end.png +0 -0
  16. data/assets/icons/ui/exit.png +0 -0
  17. data/assets/icons/ui/foo +10 -0
  18. data/assets/icons/ui/home.png +0 -0
  19. data/assets/icons/ui/left.png +0 -0
  20. data/assets/icons/ui/next.png +0 -0
  21. data/assets/icons/ui/right.png +0 -0
  22. data/assets/icons/ui/start.png +0 -0
  23. data/assets/icons/ui/up.png +0 -0
  24. data/assets/icons/x.svg +1 -0
  25. data/assets/icons/youtube.svg +1 -0
  26. data/assets/samples/placeholder.svg +9 -0
  27. data/assets/themes/standard/favicon.svg +6 -0
  28. data/bin/scriptorium +1511 -0
  29. data/doc/README.txt +6 -0
  30. data/doc/anti-amnesia/20250727-054000-scriptorium-overview.md +95 -0
  31. data/doc/anti-amnesia/20250727-060000-api-design-tui-planning.md +34 -0
  32. data/doc/anti-amnesia/20250727-061000-runeblog-tui-analysis.md +50 -0
  33. data/doc/anti-amnesia/20250727-123000-anti-amnesia-conventions.md +31 -0
  34. data/doc/anti-amnesia/20250727-154000-livetext-plugin-file-stats.md +73 -0
  35. data/doc/anti-amnesia/20250727-172600-cursor-rbenv-ruby-version-mystery.md +64 -0
  36. data/doc/anti-amnesia/20250727-172600-unified-minitest-framework.md +70 -0
  37. data/doc/anti-amnesia/20250727-172900-ai-cognitive-assessment-capabilities.md +40 -0
  38. data/doc/anti-amnesia/20250727-173000-widget-testing-achievement.md +110 -0
  39. data/doc/anti-amnesia/20250727-180000-post-id-num-refactoring.md +73 -0
  40. data/doc/anti-amnesia/20250728-124243-aaa-syntax-clarification.md +46 -0
  41. data/doc/anti-amnesia/20250728-124421-conversation-summary-concise.md +124 -0
  42. data/doc/anti-amnesia/20250729-190000-scriptorium-tui-testing-complete.md +46 -0
  43. data/doc/anti-amnesia/20250729-200000-scriptorium-tui-testing-edit-file-workflow.md +97 -0
  44. data/doc/anti-amnesia/20250729-210000-reddit-autopost-integration-complete.md +158 -0
  45. data/doc/anti-amnesia/20250729-211500-dependency-management-system.md +211 -0
  46. data/doc/anti-amnesia/20250729-213000-python-virtual-environment-setup.md +141 -0
  47. data/doc/anti-amnesia/20250729-214500-theme-management-commands.md +211 -0
  48. data/doc/anti-amnesia/20250729-215000-version-update-to-0.6.0.md +134 -0
  49. data/doc/anti-amnesia/20250729-220000-user-guide-complete.md +41 -0
  50. data/doc/anti-amnesia/20250804-190500-cognitive-loop-bug.md +45 -0
  51. data/doc/anti-amnesia/20250804-190700-anti-amnesia-timestamping-fix.md +30 -0
  52. data/doc/anti-amnesia/20250804-213700-publishing-test-fix.md +49 -0
  53. data/doc/anti-amnesia/20250804-214400-additional-test-fixes.md +46 -0
  54. data/doc/anti-amnesia/20250804-220000-asset-function-logic-clarification.md +41 -0
  55. data/doc/anti-amnesia/20250806-202032-asset-function-logic-clarification.md +41 -0
  56. data/doc/anti-amnesia/20250807-213025.md +116 -0
  57. data/doc/anti-amnesia/20250813-082428-syntax-highlighting-and-navigation-improvements.md +256 -0
  58. data/doc/banner_svg_config.md +114 -0
  59. data/doc/contrib.lt3 +8 -0
  60. data/doc/dependencies.md +281 -0
  61. data/doc/hacker.lt3 +5 -0
  62. data/doc/reddit_credentials_template.json +8 -0
  63. data/doc/reddit_integration.md +207 -0
  64. data/doc/user.lt3 +38 -0
  65. data/doc/user_guide_section_1.md +137 -0
  66. data/doc/user_guide_section_10.md +515 -0
  67. data/doc/user_guide_section_11.md +708 -0
  68. data/doc/user_guide_section_2.md +233 -0
  69. data/doc/user_guide_section_3.md +5 -0
  70. data/doc/user_guide_section_4.md +221 -0
  71. data/doc/user_guide_section_5.md +243 -0
  72. data/doc/user_guide_section_6.md +147 -0
  73. data/doc/user_guide_section_7.md +311 -0
  74. data/doc/user_guide_section_8.md +224 -0
  75. data/doc/user_guide_section_9.md +375 -0
  76. data/doc/userdoc-toc.txt +88 -0
  77. data/lib/rouge/lexers/livetext.rb +74 -0
  78. data/lib/scriptorium/api.rb +640 -0
  79. data/lib/scriptorium/banner_svg.rb +742 -0
  80. data/lib/scriptorium/contract.rb +33 -0
  81. data/lib/scriptorium/exceptions.rb +174 -0
  82. data/lib/scriptorium/helpers.rb +475 -0
  83. data/lib/scriptorium/post.rb +195 -0
  84. data/lib/scriptorium/reddit.rb +83 -0
  85. data/lib/scriptorium/repo.rb +624 -0
  86. data/lib/scriptorium/standard_files.rb +515 -0
  87. data/lib/scriptorium/syntax_highlighter.rb +234 -0
  88. data/lib/scriptorium/theme.rb +179 -0
  89. data/lib/scriptorium/version.rb +2 -2
  90. data/lib/scriptorium/view.rb +976 -0
  91. data/lib/scriptorium/widgets/featured_posts.rb +149 -0
  92. data/lib/scriptorium/widgets/links.rb +112 -0
  93. data/lib/scriptorium/widgets/pages.rb +133 -0
  94. data/lib/scriptorium/widgets/widget.rb +133 -0
  95. data/lib/scriptorium.rb +22 -9
  96. data/lib/skeleton.rb +11 -2
  97. data/scriptorium.gemspec +15 -4
  98. data/test/README.md +69 -0
  99. data/test/all +43 -0
  100. data/test/api_demo.rb +99 -0
  101. data/test/assets/imagenotfound.jpg +0 -0
  102. data/test/assets/images/.DS_Store +0 -0
  103. data/test/assets/images/README.md +27 -0
  104. data/test/assets/images/odd_aspect.png +0 -0
  105. data/test/assets/images/perfect.png +0 -0
  106. data/test/assets/images/small.png +0 -0
  107. data/test/assets/images/tall.png +0 -0
  108. data/test/assets/images/very_tall.png +0 -0
  109. data/test/assets/images/very_wide.png +0 -0
  110. data/test/assets/images/wide.png +0 -0
  111. data/test/assets/testbanner.jpg +0 -0
  112. data/test/banner_svg/simple_helpers.rb +13 -0
  113. data/test/banner_svg/unit.rb +768 -0
  114. data/test/ed_test.rb +204 -0
  115. data/test/integration/cursor_banner_combinations.rb +193 -0
  116. data/test/integration/cursor_banner_features.rb +374 -0
  117. data/test/integration/integration_test.rb +326 -0
  118. data/test/livetext_plugin_test.rb +229 -0
  119. data/test/manual/asset_mgmt.rb +67 -0
  120. data/test/manual/banner-tests/config.txt +3 -0
  121. data/test/manual/banner-tests/index.html +45 -0
  122. data/test/manual/banner-tests/test01.html +58 -0
  123. data/test/manual/banner-tests/test02.html +58 -0
  124. data/test/manual/banner-tests/test03.html +58 -0
  125. data/test/manual/banner-tests/test04.html +65 -0
  126. data/test/manual/banner-tests/test05.html +65 -0
  127. data/test/manual/banner-tests/test06.html +65 -0
  128. data/test/manual/banner-tests/test07.html +65 -0
  129. data/test/manual/banner-tests/test08.html +59 -0
  130. data/test/manual/banner-tests/test09.html +59 -0
  131. data/test/manual/banner-tests/test10.html +59 -0
  132. data/test/manual/banner-tests/test11.html +59 -0
  133. data/test/manual/banner-tests/test12.html +59 -0
  134. data/test/manual/banner-tests/test13.html +59 -0
  135. data/test/manual/banner-tests/test14.html +59 -0
  136. data/test/manual/banner-tests/test15.html +58 -0
  137. data/test/manual/banner-tests/test16.html +58 -0
  138. data/test/manual/banner-tests/test17.html +58 -0
  139. data/test/manual/banner-tests/test18.html +68 -0
  140. data/test/manual/banner-tests/test19.html +68 -0
  141. data/test/manual/banner-tests/test20.html +68 -0
  142. data/test/manual/banner-tests/test21.html +68 -0
  143. data/test/manual/banner-tests/test22.html +68 -0
  144. data/test/manual/banner-tests/test23.html +68 -0
  145. data/test/manual/banner-tests/test24.html +68 -0
  146. data/test/manual/banner-tests/test25.html +67 -0
  147. data/test/manual/banner_environment.rb +192 -0
  148. data/test/manual/deploy_symlink_demo.rb +142 -0
  149. data/test/manual/environment.rb +67 -0
  150. data/test/manual/make_banner.rb +153 -0
  151. data/test/manual/sample_banner_config.txt +12 -0
  152. data/test/manual/symlink_demo.rb +117 -0
  153. data/test/manual/test1.rb +47 -0
  154. data/test/manual/test2.rb +12 -0
  155. data/test/manual/test3.rb +38 -0
  156. data/test/manual/test4.rb +40 -0
  157. data/test/manual/test5.rb +24 -0
  158. data/test/manual/test6.rb +73 -0
  159. data/test/manual/test_banner_combinations.rb +120 -0
  160. data/test/manual/test_banner_features.rb +306 -0
  161. data/test/manual/test_banner_from_file.rb +150 -0
  162. data/test/manual/test_banner_in_header.rb +35 -0
  163. data/test/manual/test_code_highlighting.rb +68 -0
  164. data/test/manual/test_complex_header.rb +74 -0
  165. data/test/manual/test_empty_header.rb +32 -0
  166. data/test/manual/test_radial_custom.rb +58 -0
  167. data/test/manual/test_radial_large_radius.rb +52 -0
  168. data/test/manual/test_svg_debug.rb +47 -0
  169. data/test/manual/test_syntax_highlighting.rb +147 -0
  170. data/test/pages-demo/config/currentview.txt +1 -0
  171. data/test/pages-demo/views/demo/config/bootstrap_css.txt +5 -0
  172. data/test/pages-demo/views/demo/config/bootstrap_js.txt +4 -0
  173. data/test/pages-demo/views/demo/config/common.js +57 -0
  174. data/test/pages-demo/views/demo/config/footer.txt +1 -0
  175. data/test/pages-demo/views/demo/config/global-head.txt +8 -0
  176. data/test/pages-demo/views/demo/config/header.txt +1 -0
  177. data/test/pages-demo/views/demo/config/layout.txt +1 -0
  178. data/test/pages-demo/views/demo/config/left.txt +1 -0
  179. data/test/pages-demo/views/demo/config/main.txt +1 -0
  180. data/test/pages-demo/views/demo/config/right.txt +1 -0
  181. data/test/pages-demo/views/demo/config.txt +3 -0
  182. data/test/pages-demo/views/demo/output/panes/footer.html +1 -0
  183. data/test/pages-demo/views/demo/output/panes/header.html +1 -0
  184. data/test/pages-demo/views/demo/output/panes/left.html +1 -0
  185. data/test/pages-demo/views/demo/output/panes/main.html +1 -0
  186. data/test/pages-demo/views/demo/output/panes/right.html +1 -0
  187. data/test/rubytext/rubytext_comprehensive_test.rb +307 -0
  188. data/test/rubytext/rubytext_demo_test.rb +42 -0
  189. data/test/rubytext/rubytext_testing_guide.md +277 -0
  190. data/test/run_automated_tests.rb +45 -0
  191. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_css.txt +5 -0
  192. data/test/scriptorium-TEST-1754622690-146/config/bootstrap_js.txt +4 -0
  193. data/test/scriptorium-TEST-1754622690-146/config/common.js +57 -0
  194. data/test/scriptorium-TEST-1754622690-146/config/currentview.txt +1 -0
  195. data/test/scriptorium-TEST-1754622690-146/config/global-head.txt +9 -0
  196. data/test/scriptorium-TEST-1754622690-146/config/last_post_num.txt +1 -0
  197. data/test/scriptorium-TEST-1754622690-146/config/os_helpers.rb +4 -0
  198. data/test/scriptorium-TEST-1754622690-146/config/widgets.txt +3 -0
  199. data/test/scriptorium-TEST-1754622690-146/posts/0001/meta.txt +8 -0
  200. data/test/scriptorium-TEST-1754622690-146/posts/0001/source.lt3 +6 -0
  201. data/test/scriptorium-TEST-1754622690-146/themes/standard/README.txt +1 -0
  202. data/test/scriptorium-TEST-1754622690-146/themes/standard/config.txt +1 -0
  203. data/test/scriptorium-TEST-1754622690-146/themes/standard/initial/post.lt3 +12 -0
  204. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/footer.txt +2 -0
  205. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/header.txt +4 -0
  206. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/left.txt +3 -0
  207. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/main.txt +5 -0
  208. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/config/right.txt +3 -0
  209. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/gen/text.css +1 -0
  210. data/test/scriptorium-TEST-1754622690-146/themes/standard/layout/layout.txt +5 -0
  211. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index.lt3 +1 -0
  212. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/index_entry.lt3 +14 -0
  213. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/post.lt3 +13 -0
  214. data/test/scriptorium-TEST-1754622690-146/themes/standard/templates/widget.lt3 +1 -0
  215. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_css.txt +5 -0
  216. data/test/scriptorium-TEST-1754622690-146/views/sample/config/bootstrap_js.txt +4 -0
  217. data/test/scriptorium-TEST-1754622690-146/views/sample/config/common.js +57 -0
  218. data/test/scriptorium-TEST-1754622690-146/views/sample/config/deploy.txt +5 -0
  219. data/test/scriptorium-TEST-1754622690-146/views/sample/config/footer.txt +2 -0
  220. data/test/scriptorium-TEST-1754622690-146/views/sample/config/global-head.txt +9 -0
  221. data/test/scriptorium-TEST-1754622690-146/views/sample/config/header.txt +4 -0
  222. data/test/scriptorium-TEST-1754622690-146/views/sample/config/layout.txt +5 -0
  223. data/test/scriptorium-TEST-1754622690-146/views/sample/config/left.txt +3 -0
  224. data/test/scriptorium-TEST-1754622690-146/views/sample/config/main.txt +5 -0
  225. data/test/scriptorium-TEST-1754622690-146/views/sample/config/reddit.txt +10 -0
  226. data/test/scriptorium-TEST-1754622690-146/views/sample/config/right.txt +3 -0
  227. data/test/scriptorium-TEST-1754622690-146/views/sample/config/social.txt +7 -0
  228. data/test/scriptorium-TEST-1754622690-146/views/sample/config/status.txt +7 -0
  229. data/test/scriptorium-TEST-1754622690-146/views/sample/config.txt +3 -0
  230. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/footer.html +3 -0
  231. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/header.html +3 -0
  232. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/left.html +3 -0
  233. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/main.html +3 -0
  234. data/test/scriptorium-TEST-1754622690-146/views/sample/layout/right.html +3 -0
  235. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/footer.html +1 -0
  236. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/header.html +1 -0
  237. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/left.html +1 -0
  238. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/main.html +1 -0
  239. data/test/scriptorium-TEST-1754622690-146/views/sample/output/panes/right.html +1 -0
  240. data/test/staging/.DS_Store +0 -0
  241. data/test/syntax_highlighting_test.lt3 +124 -0
  242. data/test/test_helpers.rb +230 -0
  243. data/test/tui_editor_integration_test.rb +296 -0
  244. data/test/tui_integration_test.rb +637 -0
  245. data/test/unit/api.rb +1056 -0
  246. data/test/unit/asset_management.rb +245 -0
  247. data/test/unit/clipboard_test.rb +60 -0
  248. data/test/unit/contract_test.rb +91 -0
  249. data/test/unit/core.rb +857 -0
  250. data/test/unit/deploy_test.rb +187 -0
  251. data/test/unit/gem_asset_management.rb +189 -0
  252. data/test/unit/livetext_basic.rb +69 -0
  253. data/test/unit/livetext_compatibility.rb +89 -0
  254. data/test/unit/post.rb +244 -0
  255. data/test/unit/read_commented_file_test.rb +276 -0
  256. data/test/unit/reddit_test.rb +235 -0
  257. data/test/unit/repo.rb +548 -0
  258. data/test/unit/social_test.rb +369 -0
  259. data/test/unit/symlink_test.rb +213 -0
  260. data/test/unit/view.rb +431 -0
  261. data/test/unit/widgets.rb +669 -0
  262. data/test/wizard_test.rb +123 -0
  263. data/ui/README.md +67 -0
  264. data/ui/common/lib/ui_common.rb +8 -0
  265. data/ui/rubytext/README.md +191 -0
  266. data/ui/rubytext/bin/scriptorium-rubytext +402 -0
  267. data/ui/rubytext/lib/rubytext_ui.rb +300 -0
  268. data/ui/tui/bin/scriptorium +1420 -0
  269. data/ui/tui/test/tui_test.rb +23 -0
  270. data/ui/web/app/app.rb +1378 -0
  271. data/ui/web/app/error_helpers.rb +150 -0
  272. data/ui/web/app/views/advanced_config.erb +190 -0
  273. data/ui/web/app/views/asset_management.erb +589 -0
  274. data/ui/web/app/views/banner_config.erb +200 -0
  275. data/ui/web/app/views/configure_view.erb +401 -0
  276. data/ui/web/app/views/dashboard.erb +162 -0
  277. data/ui/web/app/views/deploy_config.erb +146 -0
  278. data/ui/web/app/views/edit_pages.erb +195 -0
  279. data/ui/web/app/views/edit_post.erb +54 -0
  280. data/ui/web/app/views/error_page.erb +29 -0
  281. data/ui/web/app/views/header_config.erb +155 -0
  282. data/ui/web/app/views/layout_config.erb +147 -0
  283. data/ui/web/app/views/navbar_config.erb +411 -0
  284. data/ui/web/app/views/view_dashboard.erb +138 -0
  285. data/ui/web/bin/scriptorium-web +153 -0
  286. data/ui/web/test/web_basic_test.rb +38 -0
  287. data/ui/web/test_navbar.txt +7 -0
  288. data/ui/web/tmp/web_server.log +5 -0
  289. data/ui/web/tmp/web_server.pid +1 -0
  290. metadata +360 -5
data/test/unit/post.rb ADDED
@@ -0,0 +1,244 @@
1
+ # test/unit/post.rb
2
+
3
+ require 'minitest/autorun'
4
+ require_relative '../../lib/scriptorium'
5
+ require_relative '../test_helpers'
6
+ require_relative '../../lib/scriptorium/post'
7
+
8
+ class TestScriptoriumPost < Minitest::Test
9
+ include Scriptorium::Exceptions
10
+ include Scriptorium::Helpers
11
+
12
+ def setup
13
+ @test_dir = "test/post_test_files"
14
+ make_dir(@test_dir)
15
+ @repo = Scriptorium::Repo.create("test/scriptorium-TEST", testmode: true)
16
+ @post = Scriptorium::Post.new(@repo, 1)
17
+ end
18
+
19
+ def teardown
20
+ FileUtils.rm_rf(@test_dir) if Dir.exist?(@test_dir)
21
+ Scriptorium::Repo.destroy if Scriptorium::Repo.testing
22
+ end
23
+
24
+ # Constructor validation tests
25
+ def test_001_initialize_with_valid_params
26
+ post = Scriptorium::Post.new(@repo, 123)
27
+ assert_equal @repo, post.repo
28
+ assert_equal "0123", post.num
29
+ end
30
+
31
+ def test_002_initialize_with_nil_repo
32
+ assert_raises(CannotCreatePostRepoNil) do
33
+ Scriptorium::Post.new(nil, 1)
34
+ end
35
+ end
36
+
37
+ def test_003_initialize_with_nil_num
38
+ assert_raises(CannotCreatePostNumNil) do
39
+ Scriptorium::Post.new(@repo, nil)
40
+ end
41
+ end
42
+
43
+ def test_004_initialize_with_empty_num
44
+ assert_raises(CannotCreatePostNumEmpty) do
45
+ Scriptorium::Post.new(@repo, "")
46
+ end
47
+ end
48
+
49
+ def test_005_initialize_with_whitespace_num
50
+ assert_raises(CannotCreatePostNumEmpty) do
51
+ Scriptorium::Post.new(@repo, " ")
52
+ end
53
+ end
54
+
55
+ def test_006_initialize_with_invalid_num_format
56
+ assert_raises(CannotCreatePostNumInvalid) do
57
+ Scriptorium::Post.new(@repo, "abc")
58
+ end
59
+ end
60
+
61
+ def test_007_initialize_with_negative_num
62
+ assert_raises(CannotCreatePostNumInvalid) do
63
+ Scriptorium::Post.new(@repo, -1)
64
+ end
65
+ end
66
+
67
+ # Basic property tests
68
+ def test_008_dir
69
+ expected_dir = @repo.root/:posts/"0001"
70
+ assert_equal expected_dir, @post.dir
71
+ end
72
+
73
+ def test_009_meta_file
74
+ expected_file = @repo.root/:posts/"0001"/"meta.txt"
75
+ assert_equal expected_file, @post.meta_file
76
+ end
77
+
78
+ def test_010_id
79
+ assert_equal 1, @post.id
80
+ end
81
+
82
+ def test_011_num_with_leading_zeros
83
+ post = Scriptorium::Post.new(@repo, 1)
84
+ assert_equal "0001", post.num
85
+ end
86
+
87
+ def test_012_num_without_leading_zeros
88
+ post = Scriptorium::Post.new(@repo, 123)
89
+ assert_equal "0123", post.num
90
+ end
91
+
92
+ def test_013_num_with_existing_zeros
93
+ post = Scriptorium::Post.new(@repo, 0001)
94
+ assert_equal "0001", post.num
95
+ end
96
+
97
+
98
+
99
+ # Metadata tests
100
+ def test_014_meta_without_file
101
+ # When meta file doesn't exist, should return empty hash
102
+ assert_equal({}, @post.meta)
103
+ end
104
+
105
+ def test_015_meta_with_file
106
+ # Create a meta file
107
+ meta_content = "post.title Test Post\npost.blurb Test blurb\npost.slug test-post\npost.pubdate 2023-01-01 12:00:00"
108
+ write_file(@post.meta_file, meta_content)
109
+
110
+ meta = @post.meta
111
+ assert_equal "Test Post", meta["post.title"]
112
+ assert_equal "Test blurb", meta["post.blurb"]
113
+ assert_equal "test-post", meta["post.slug"]
114
+ assert_equal "2023-01-01 12:00:00", meta["post.pubdate"]
115
+ end
116
+
117
+ # Individual metadata field tests
118
+ def test_016_title
119
+ write_file(@post.meta_file, "post.title Test Post")
120
+ assert_equal "Test Post", @post.title
121
+ end
122
+
123
+ def test_017_blurb
124
+ write_file(@post.meta_file, "post.blurb Test blurb")
125
+ assert_equal "Test blurb", @post.blurb
126
+ end
127
+
128
+ def test_018_slug
129
+ write_file(@post.meta_file, "post.slug test-post")
130
+ assert_equal "test-post", @post.slug
131
+ end
132
+
133
+ def test_019_pubdate
134
+ write_file(@post.meta_file, "post.pubdate 2023-01-01 12:00:00")
135
+ assert_equal "2023-01-01 12:00:00", @post.pubdate
136
+ end
137
+
138
+ def test_020_views
139
+ write_file(@post.meta_file, "post.views view1 view2")
140
+ assert_equal "view1 view2", @post.views
141
+ end
142
+
143
+ def test_021_tags
144
+ write_file(@post.meta_file, "post.tags tag1,tag2")
145
+ assert_equal "tag1,tag2", @post.tags
146
+ end
147
+
148
+ # set_pubdate tests
149
+ def test_022_set_pubdate_with_valid_date
150
+ Scriptorium::Repo.testing = true
151
+ @post.set_pubdate("2023-01-15")
152
+
153
+ meta = @post.meta
154
+ assert_equal "2023-01-15 00:00:00", meta["post.pubdate"]
155
+ assert_equal "January", meta["post.pubdate.month"]
156
+ assert_equal "15", meta["post.pubdate.day"]
157
+ assert_equal "2023", meta["post.pubdate.year"]
158
+ end
159
+
160
+ def test_023_set_pubdate_with_nil_date
161
+ Scriptorium::Repo.testing = true
162
+ assert_raises(CannotSetPubdateYmdNil) do
163
+ @post.set_pubdate(nil)
164
+ end
165
+ end
166
+
167
+ def test_024_set_pubdate_with_empty_date
168
+ Scriptorium::Repo.testing = true
169
+ assert_raises(CannotSetPubdateYmdEmpty) do
170
+ @post.set_pubdate("")
171
+ end
172
+ end
173
+
174
+ def test_025_set_pubdate_with_invalid_format
175
+ Scriptorium::Repo.testing = true
176
+ assert_raises(CannotSetPubdateInvalidFormat) do
177
+ @post.set_pubdate("2023/01/15")
178
+ end
179
+ end
180
+
181
+ def test_026_set_pubdate_with_invalid_date
182
+ Scriptorium::Repo.testing = true
183
+ assert_raises(ArgumentError) do
184
+ @post.set_pubdate("2023-13-45")
185
+ end
186
+ end
187
+
188
+ def test_027_set_pubdate_without_testing_mode
189
+ Scriptorium::Repo.testing = false
190
+ assert_raises(TestModeOnly) do
191
+ @post.set_pubdate("2023-01-15")
192
+ end
193
+ Scriptorium::Repo.testing = true
194
+ end
195
+
196
+ # set_pubdate_with_seconds tests
197
+ def test_028_set_pubdate_with_seconds
198
+ Scriptorium::Repo.testing = true
199
+ @post.set_pubdate_with_seconds("2023-01-15", 30)
200
+
201
+ meta = @post.meta
202
+ assert_equal "2023-01-15 12:00:30", meta["post.pubdate"]
203
+ end
204
+
205
+ def test_029_pubdate_month_day_year
206
+ write_file(@post.meta_file, "post.pubdate.month January\npost.pubdate.day 15\npost.pubdate.year 2023")
207
+ assert_equal ["January", "15", "2023"], @post.pubdate_month_day_year
208
+ end
209
+
210
+ # attrs tests
211
+ def test_030_attrs_single
212
+ write_file(@post.meta_file, "post.title Test Post")
213
+ assert_equal ["Test Post"], @post.attrs(:title)
214
+ end
215
+
216
+ def test_031_attrs_multiple
217
+ write_file(@post.meta_file, "post.title Test Post\npost.blurb Test blurb")
218
+ assert_equal ["Test Post", "Test blurb"], @post.attrs(:title, :blurb)
219
+ end
220
+
221
+ # vars tests
222
+ def test_032_vars
223
+ write_file(@post.meta_file, "post.title Test Post\npost.blurb Test blurb")
224
+ vars = @post.vars
225
+ assert_equal "Test Post", vars[:"post.title"]
226
+ assert_equal "Test blurb", vars[:"post.blurb"]
227
+ end
228
+
229
+ def test_033_vars_default_behavior
230
+ vars = @post.vars
231
+ assert_equal "", vars[:nonexistent_key]
232
+ end
233
+
234
+ # Class method tests
235
+ def test_034_read
236
+ # Create a meta file
237
+ meta_content = "post.title Test Post\npost.blurb Test blurb"
238
+ write_file(@post.meta_file, meta_content)
239
+
240
+ post = Scriptorium::Post.read(@repo, 1)
241
+ assert_equal "Test Post", post.title
242
+ assert_equal "Test blurb", post.blurb
243
+ end
244
+ end
@@ -0,0 +1,276 @@
1
+ require 'minitest/autorun'
2
+ require_relative '../../lib/scriptorium'
3
+ require_relative '../test_helpers'
4
+
5
+ # Simple class to access the Helpers method
6
+ class TestHelper
7
+ include Scriptorium::Helpers
8
+ end
9
+
10
+ class ReadCommentedFileTest < Minitest::Test
11
+ def setup
12
+ ENV['DBC_DISABLED'] = 'true'
13
+ @test_file = "test_comments.txt"
14
+ @helper = TestHelper.new
15
+ @banner = Scriptorium::BannerSVG.new("Test", "Subtitle")
16
+ end
17
+
18
+ def teardown
19
+ File.delete(@test_file) if File.exist?(@test_file)
20
+ end
21
+
22
+ def test_comprehensive_comparison
23
+ # Test file with comprehensive comment scenarios
24
+ test_content = <<~CONTENT
25
+ # Full line comment
26
+ simple_line
27
+ line_with_inline_comment # this is a comment
28
+ line_with_spaces # comment with spaces
29
+ line_with_tab # comment with tab
30
+
31
+ # Lines with # in values (should be preserved)
32
+ color #ff0000
33
+ color #ff0000 # this is red
34
+ url http://example.com#fragment
35
+ url http://example.com#fragment # URL with fragment
36
+ hex #123456
37
+ hex #123456 # hex value
38
+
39
+ # Edge cases
40
+ line#nospace
41
+ line#nospace # comment
42
+ line # comment with # in it
43
+ line # comment with # and spaces
44
+
45
+ # Multiple # characters
46
+ multiple #ff0000 #ff0001 #ff0002
47
+ multiple #ff0000 #ff0001 #ff0002 # three colors
48
+
49
+ # Empty lines and whitespace
50
+
51
+ line_after_empty
52
+ # indented comment
53
+ indented_line
54
+
55
+ # Final line
56
+ last_line
57
+ CONTENT
58
+
59
+ File.write(@test_file, test_content)
60
+
61
+ helpers_result = @helper.read_commented_file(@test_file)
62
+ banner_result = @banner.read_commented_file(@test_file)
63
+
64
+ # Both methods should now produce identical results
65
+ assert_equal helpers_result, banner_result, "Both methods should produce identical results"
66
+ end
67
+
68
+ def test_whitespace_edge_cases
69
+ test_cases = [
70
+ {
71
+ name: "leading spaces",
72
+ content: " line with leading spaces",
73
+ expected: ["line with leading spaces"]
74
+ },
75
+ {
76
+ name: "leading tabs",
77
+ content: "\tline with leading tab",
78
+ expected: ["line with leading tab"]
79
+ },
80
+ {
81
+ name: "mixed leading whitespace",
82
+ content: " \t line with mixed whitespace",
83
+ expected: ["line with mixed whitespace"]
84
+ },
85
+ {
86
+ name: "trailing spaces",
87
+ content: "line with trailing spaces ",
88
+ expected: ["line with trailing spaces"]
89
+ },
90
+ {
91
+ name: "trailing tabs",
92
+ content: "line with trailing tab\t",
93
+ expected: ["line with trailing tab"]
94
+ },
95
+ {
96
+ name: "line with only spaces",
97
+ content: " ",
98
+ expected: []
99
+ },
100
+ {
101
+ name: "line with only tabs",
102
+ content: "\t\t",
103
+ expected: []
104
+ },
105
+ {
106
+ name: "line with only mixed whitespace",
107
+ content: " \t \t ",
108
+ expected: []
109
+ },
110
+ {
111
+ name: "line with spaces and comment",
112
+ content: " line # comment",
113
+ expected: ["line"]
114
+ },
115
+ {
116
+ name: "line with tabs and comment",
117
+ content: "\t\tline # comment",
118
+ expected: ["line"]
119
+ },
120
+ {
121
+ name: "line with mixed whitespace and comment",
122
+ content: " \t line # comment",
123
+ expected: ["line"]
124
+ },
125
+ {
126
+ name: "line with spaces and # in value",
127
+ content: " color #ff0000",
128
+ expected: ["color #ff0000"]
129
+ },
130
+ {
131
+ name: "line with tabs and # in value",
132
+ content: "\t\tcolor #ff0000",
133
+ expected: ["color #ff0000"]
134
+ },
135
+ {
136
+ name: "line with mixed whitespace and # in value",
137
+ content: " \t color #ff0000",
138
+ expected: ["color #ff0000"]
139
+ },
140
+ {
141
+ name: "line with spaces and # in value and comment",
142
+ content: " color #ff0000 # this is red",
143
+ expected: ["color #ff0000"]
144
+ },
145
+ {
146
+ name: "line with tabs and # in value and comment",
147
+ content: "\t\tcolor #ff0000 # this is red",
148
+ expected: ["color #ff0000"]
149
+ },
150
+ {
151
+ name: "line with mixed whitespace and # in value and comment",
152
+ content: " \t color #ff0000 # this is red",
153
+ expected: ["color #ff0000"]
154
+ },
155
+ {
156
+ name: "indented comment",
157
+ content: " # indented comment",
158
+ expected: []
159
+ },
160
+ {
161
+ name: "tabbed comment",
162
+ content: "\t# tabbed comment",
163
+ expected: []
164
+ },
165
+ {
166
+ name: "mixed whitespace comment",
167
+ content: " \t # mixed whitespace comment",
168
+ expected: []
169
+ },
170
+ {
171
+ name: "line with internal spaces",
172
+ content: "line with multiple spaces",
173
+ expected: ["line with multiple spaces"]
174
+ },
175
+ {
176
+ name: "line with internal tabs",
177
+ content: "line\twith\ttabs",
178
+ expected: ["line\twith\ttabs"]
179
+ }
180
+ ]
181
+
182
+ test_cases.each do |test_case|
183
+ File.write(@test_file, test_case[:content])
184
+
185
+ helpers_result = @helper.read_commented_file(@test_file)
186
+ banner_result = @banner.read_commented_file(@test_file)
187
+
188
+ assert_equal test_case[:expected], helpers_result, "Helpers failed for: #{test_case[:name]}"
189
+ assert_equal test_case[:expected], banner_result, "BannerSVG failed for: #{test_case[:name]}"
190
+ end
191
+ end
192
+
193
+ def test_individual_cases
194
+ test_cases = [
195
+ {
196
+ name: "simple line",
197
+ content: "simple_line",
198
+ expected: ["simple_line"]
199
+ },
200
+ {
201
+ name: "line with inline comment",
202
+ content: "line # comment",
203
+ expected: ["line"]
204
+ },
205
+ {
206
+ name: "line with # in value",
207
+ content: "color #ff0000",
208
+ expected: ["color #ff0000"]
209
+ },
210
+ {
211
+ name: "line with # in value and comment",
212
+ content: "color #ff0000 # this is red",
213
+ expected: ["color #ff0000"]
214
+ },
215
+ {
216
+ name: "line with # in URL",
217
+ content: "url http://example.com#fragment",
218
+ expected: ["url http://example.com#fragment"]
219
+ },
220
+ {
221
+ name: "line with # in URL and comment",
222
+ content: "url http://example.com#fragment # URL with fragment",
223
+ expected: ["url http://example.com#fragment"]
224
+ },
225
+ {
226
+ name: "line with # no space",
227
+ content: "line#nospace",
228
+ expected: ["line#nospace"]
229
+ },
230
+ {
231
+ name: "line with # no space and comment",
232
+ content: "line#nospace # comment",
233
+ expected: ["line#nospace"]
234
+ },
235
+ {
236
+ name: "comment with # in it",
237
+ content: "line # comment with # in it",
238
+ expected: ["line"]
239
+ },
240
+ {
241
+ name: "multiple # characters",
242
+ content: "multiple #ff0000 #ff0001 #ff0002",
243
+ expected: ["multiple #ff0000 #ff0001 #ff0002"]
244
+ }
245
+ ]
246
+
247
+ test_cases.each do |test_case|
248
+ File.write(@test_file, test_case[:content])
249
+
250
+ helpers_result = @helper.read_commented_file(@test_file)
251
+ banner_result = @banner.read_commented_file(@test_file)
252
+
253
+ assert_equal test_case[:expected], helpers_result, "Helpers failed for: #{test_case[:name]}"
254
+ assert_equal test_case[:expected], banner_result, "BannerSVG failed for: #{test_case[:name]}"
255
+ end
256
+ end
257
+
258
+ def test_edge_cases
259
+ # Test with empty file
260
+ File.write(@test_file, "")
261
+ helpers_result = @helper.read_commented_file(@test_file)
262
+ banner_result = @banner.read_commented_file(@test_file)
263
+ assert_equal helpers_result, banner_result, "Empty file should produce same result"
264
+
265
+ # Test with file that doesn't exist
266
+ helpers_result = @helper.read_commented_file("nonexistent.txt")
267
+ banner_result = @banner.read_commented_file("nonexistent.txt")
268
+ assert_equal helpers_result, banner_result, "Nonexistent file should produce same result"
269
+
270
+ # Test with only comments
271
+ File.write(@test_file, "# Only comments\n# Another comment\n # Indented comment")
272
+ helpers_result = @helper.read_commented_file(@test_file)
273
+ banner_result = @banner.read_commented_file(@test_file)
274
+ assert_equal helpers_result, banner_result, "File with only comments should produce same result"
275
+ end
276
+ end