livetext 0.9.52 → 0.9.56
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/imports/bookish.rb +3 -3
- data/lib/livetext/ast/show_ast_clean.rb +10 -0
- data/lib/livetext/ast/show_ast_result.rb +60 -0
- data/lib/livetext/ast/show_raw_arrays.rb +13 -0
- data/lib/livetext/ast.rb +464 -0
- data/lib/livetext/ast_to_html.rb +32 -0
- data/lib/livetext/core.rb +110 -53
- data/lib/livetext/errors.rb +1 -0
- data/lib/livetext/expansion.rb +21 -21
- data/lib/livetext/formatter.rb +70 -200
- data/lib/livetext/formatter_component.rb +189 -0
- data/lib/livetext/function_registry.rb +163 -0
- data/lib/livetext/functions.rb +26 -0
- data/lib/livetext/handler/mixin.rb +53 -0
- data/lib/livetext/helpers.rb +33 -16
- data/lib/livetext/reopen.rb +2 -0
- data/lib/livetext/skeleton.rb +0 -3
- data/lib/livetext/standard.rb +120 -72
- data/lib/livetext/userapi.rb +20 -1
- data/lib/livetext/variable_manager.rb +78 -0
- data/lib/livetext/variables.rb +9 -1
- data/lib/livetext/version.rb +1 -1
- data/lib/livetext.rb +9 -3
- data/plugin/booktool.rb +14 -14
- data/plugin/lt3scriptor.rb +914 -0
- data/plugin/mixin_functions_class.rb +33 -0
- data/test/snapshots/complex_body/expected-error.txt +0 -0
- data/test/snapshots/complex_body/expected-output.txt +8 -0
- data/test/snapshots/complex_body/source.lt3 +19 -0
- data/test/snapshots/debug_command/expected-error.txt +0 -0
- data/test/snapshots/debug_command/expected-output.txt +1 -0
- data/test/snapshots/debug_command/source.lt3 +3 -0
- data/test/snapshots/def_parameters/expected-error.txt +0 -0
- data/test/snapshots/def_parameters/expected-output.txt +21 -0
- data/test/snapshots/def_parameters/source.lt3 +44 -0
- data/test/snapshots/error_missing_end/match-error.txt +1 -1
- data/test/snapshots/functions_reflection/expected-error.txt +0 -0
- data/test/snapshots/functions_reflection/expected-output.txt +27 -0
- data/test/snapshots/functions_reflection/source.lt3 +5 -0
- data/test/snapshots/mixin_functions_class/expected-error.txt +0 -0
- data/test/snapshots/mixin_functions_class/expected-output.txt +20 -0
- data/test/snapshots/mixin_functions_class/mixin_functions_class.rb +33 -0
- data/test/snapshots/mixin_functions_class/source.lt3 +17 -0
- data/test/snapshots/multiple_functions/expected-error.txt +0 -0
- data/test/snapshots/multiple_functions/expected-output.txt +5 -0
- data/test/snapshots/multiple_functions/source.lt3 +16 -0
- data/test/snapshots/nested_includes/expected-error.txt +0 -0
- data/test/snapshots/nested_includes/expected-output.txt +68 -0
- data/test/snapshots/nested_includes/level2.inc +34 -0
- data/test/snapshots/nested_includes/level3.inc +20 -0
- data/test/snapshots/nested_includes/source.lt3 +49 -0
- data/test/snapshots/parameter_handling/expected-error.txt +0 -0
- data/test/snapshots/parameter_handling/expected-output.txt +7 -0
- data/test/snapshots/parameter_handling/source.lt3 +10 -0
- data/test/snapshots/subset.txt +1 -0
- data/test/snapshots/system_info/expected-error.txt +0 -0
- data/test/snapshots/system_info/match-output.txt +18 -0
- data/test/snapshots/system_info/source.lt3 +16 -0
- data/test/unit/all.rb +7 -0
- data/test/unit/ast.rb +90 -0
- data/test/unit/ast_directives.rb +104 -0
- data/test/unit/ast_variables.rb +71 -0
- data/test/unit/core_methods.rb +317 -0
- data/test/unit/formatter.rb +84 -0
- data/test/unit/formatter_component.rb +84 -0
- data/test/unit/function_registry.rb +132 -0
- data/test/unit/mixin_functions_class.rb +131 -0
- data/test/unit/stringparser.rb +14 -32
- data/test/unit/variable_manager.rb +71 -0
- metadata +51 -5
- data/imports/markdown.rb +0 -44
- data/lib/livetext/processor.rb +0 -88
- data/plugin/markdown.rb +0 -43
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
require_relative '../../lib/livetext/ast'
|
4
|
+
|
5
|
+
class TestingLivetextASTDirectives < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@ast = LivetextAST.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_single_line_directives
|
11
|
+
# Single line directives (2 parameters: args, data)
|
12
|
+
assert_equal([LivetextAST::DIRECTIVE, "h1", "My Title"],
|
13
|
+
@ast.parse_directives([".h1 My Title"]))
|
14
|
+
|
15
|
+
assert_equal([LivetextAST::DIRECTIVE, "set", "name=value"],
|
16
|
+
@ast.parse_directives([".set name=value"]))
|
17
|
+
|
18
|
+
assert_equal([LivetextAST::DIRECTIVE, "comment", "This is a comment"],
|
19
|
+
@ast.parse_directives([". This is a comment"]))
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_multi_line_comment_directive
|
23
|
+
# Multi-line .comment directive
|
24
|
+
input = [
|
25
|
+
".comment",
|
26
|
+
" This is a multi-line comment",
|
27
|
+
" It can span multiple lines",
|
28
|
+
".end"
|
29
|
+
]
|
30
|
+
expected = [
|
31
|
+
LivetextAST::DIRECTIVE, "comment", "",
|
32
|
+
[LivetextAST::BODY, [" This is a multi-line comment", " It can span multiple lines"]]
|
33
|
+
]
|
34
|
+
assert_equal(expected, @ast.parse_directives(input))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_multi_line_directives
|
38
|
+
# Multi line directives (3 parameters: args, data, body)
|
39
|
+
input = [
|
40
|
+
".list",
|
41
|
+
" * item 1",
|
42
|
+
" * item 2",
|
43
|
+
" * item 3",
|
44
|
+
".end"
|
45
|
+
]
|
46
|
+
expected = [
|
47
|
+
LivetextAST::DIRECTIVE, "list", "",
|
48
|
+
[LivetextAST::BODY, [" * item 1", " * item 2", " * item 3"]]
|
49
|
+
]
|
50
|
+
assert_equal(expected, @ast.parse_directives(input))
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_directive_with_args_and_body
|
54
|
+
input = [
|
55
|
+
".func myfunc",
|
56
|
+
" return 'Hello, World!'",
|
57
|
+
".end"
|
58
|
+
]
|
59
|
+
expected = [
|
60
|
+
LivetextAST::DIRECTIVE, "func", "myfunc",
|
61
|
+
[LivetextAST::BODY, [" return 'Hello, World!'"]]
|
62
|
+
]
|
63
|
+
assert_equal(expected, @ast.parse_directives(input))
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_missing_end_error
|
67
|
+
input = [
|
68
|
+
".list",
|
69
|
+
" * item 1",
|
70
|
+
" * item 2"
|
71
|
+
# Missing .end
|
72
|
+
]
|
73
|
+
expected = [
|
74
|
+
LivetextAST::ERROR, "Missing .end", 1, "list"
|
75
|
+
]
|
76
|
+
assert_equal(expected, @ast.parse_directives(input))
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_unknown_directive
|
80
|
+
input = [".unknown_directive some args"]
|
81
|
+
expected = [
|
82
|
+
LivetextAST::ERROR, "Unknown directive", 1, "unknown_directive"
|
83
|
+
]
|
84
|
+
assert_equal(expected, @ast.parse_directives(input))
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_empty_input
|
88
|
+
assert_equal([], @ast.parse_directives([]))
|
89
|
+
assert_equal([], @ast.parse_directives(nil))
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_non_directive_lines
|
93
|
+
input = [
|
94
|
+
"Just some text",
|
95
|
+
"More text here",
|
96
|
+
".h1 A Title",
|
97
|
+
"More text"
|
98
|
+
]
|
99
|
+
expected = [
|
100
|
+
LivetextAST::DIRECTIVE, "h1", "A Title"
|
101
|
+
]
|
102
|
+
assert_equal(expected, @ast.parse_directives(input))
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
require_relative '../../lib/livetext/ast'
|
4
|
+
|
5
|
+
class TestingLivetextASTVariables < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@ast = LivetextAST.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_variable_parsing
|
11
|
+
# Basic variables
|
12
|
+
assert_equal([LivetextAST::VAR, "name"], @ast.parse_variables("$name"))
|
13
|
+
assert_equal([LivetextAST::VAR, "my_var"], @ast.parse_variables("$my_var"))
|
14
|
+
assert_equal([LivetextAST::VAR, "font.title"], @ast.parse_variables("$font.title"))
|
15
|
+
|
16
|
+
# Invalid names should be left as literal text
|
17
|
+
assert_equal("$_invalid", @ast.parse_variables("$_invalid"))
|
18
|
+
assert_equal("$3invalid", @ast.parse_variables("$3invalid"))
|
19
|
+
|
20
|
+
# Edge cases - Livetext behavior:
|
21
|
+
# $foo. -> parses $foo as variable, . as literal (matches Livetext)
|
22
|
+
assert_equal([LivetextAST::TEXT, [LivetextAST::VAR, "foo"], "."], @ast.parse_variables("$foo."))
|
23
|
+
# $a..b -> parses $a as variable, ..b as literal (matches Livetext)
|
24
|
+
assert_equal([LivetextAST::TEXT, [LivetextAST::VAR, "a"], "..b"], @ast.parse_variables("$a..b"))
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_function_parsing
|
28
|
+
# No parameter
|
29
|
+
assert_equal([LivetextAST::FUNC, "myfunc", LivetextAST::SPACE, nil], @ast.parse_functions("$$myfunc "))
|
30
|
+
assert_equal([LivetextAST::FUNC, "myfunc", LivetextAST::EOL, nil], @ast.parse_functions("$$myfunc"))
|
31
|
+
|
32
|
+
# Colon parameter
|
33
|
+
assert_equal([LivetextAST::FUNC, "greet", LivetextAST::COLON, "world"], @ast.parse_functions("$$greet:world"))
|
34
|
+
|
35
|
+
# Bracket parameter
|
36
|
+
assert_equal([LivetextAST::FUNC, "mean", LivetextAST::LBRACK, "1,2,3"], @ast.parse_functions("$$mean[1,2,3]"))
|
37
|
+
assert_equal([LivetextAST::FUNC, "title", LivetextAST::LBRACK, "My Title"], @ast.parse_functions("$$title[My Title]"))
|
38
|
+
|
39
|
+
# Note: Function parameter delimiters are tracked as requested:
|
40
|
+
# SPACE, EOL, COLON, LBRACK for debugging/future use
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_mixed_content
|
44
|
+
# Variables in text
|
45
|
+
input = "Hello $name, welcome to $nation!"
|
46
|
+
expected = [LivetextAST::TEXT, "Hello ", [LivetextAST::VAR, "name"], ", welcome to ", [LivetextAST::VAR, "nation"], "!"]
|
47
|
+
assert_equal(expected, @ast.parse_variables(input))
|
48
|
+
|
49
|
+
# Functions in text
|
50
|
+
input = "The result is $$mean[1,2,3] as expected."
|
51
|
+
expected = [LivetextAST::TEXT, "The result is ", [LivetextAST::FUNC, "mean", LivetextAST::LBRACK, "1,2,3"], " as expected."]
|
52
|
+
assert_equal(expected, @ast.parse_functions(input))
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_escaped_dollars
|
56
|
+
# Escaped variables and functions
|
57
|
+
# Note: Backslash escapes the entire $ or $$ sequence
|
58
|
+
assert_equal("\\$literal", @ast.parse_variables("\\$literal"))
|
59
|
+
assert_equal("\\$\\$literal", @ast.parse_functions("\\$\\$literal"))
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_edge_cases
|
63
|
+
# Empty strings
|
64
|
+
assert_equal([], @ast.parse_variables(""))
|
65
|
+
assert_equal([], @ast.parse_functions(""))
|
66
|
+
|
67
|
+
# No variables/functions
|
68
|
+
assert_equal("plain text", @ast.parse_variables("plain text"))
|
69
|
+
assert_equal("plain text", @ast.parse_functions("plain text"))
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require_relative '../../lib/livetext'
|
3
|
+
|
4
|
+
class TestingLivetextCoreMethods < Minitest::Test
|
5
|
+
def setup
|
6
|
+
@live = Livetext.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_customize_class_method
|
10
|
+
# Test the class-level customize method
|
11
|
+
obj = Livetext.customize(
|
12
|
+
mix: [],
|
13
|
+
call: ['.nopara'],
|
14
|
+
vars: { 'test_var' => 'test_value' }
|
15
|
+
)
|
16
|
+
|
17
|
+
assert_instance_of(Livetext, obj)
|
18
|
+
# The customize method should set up the instance with mixins, commands, and vars
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_customize_instance_method
|
22
|
+
# Test the instance-level customize method
|
23
|
+
result = @live.customize(
|
24
|
+
mix: [],
|
25
|
+
call: ['.nopara'],
|
26
|
+
vars: { 'test_var' => 'test_value' }
|
27
|
+
)
|
28
|
+
|
29
|
+
assert_equal(@live, result) # Should return self
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_customize_with_plugin
|
33
|
+
# Test customize with a real plugin
|
34
|
+
obj = Livetext.customize(
|
35
|
+
mix: ['tutorial'],
|
36
|
+
call: [],
|
37
|
+
vars: {}
|
38
|
+
)
|
39
|
+
|
40
|
+
assert_instance_of(Livetext, obj)
|
41
|
+
# Should have loaded the tutorial plugin
|
42
|
+
assert_includes(obj.methods, :title)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_customize_with_commands
|
46
|
+
# Test customize with dot commands
|
47
|
+
obj = Livetext.customize(
|
48
|
+
mix: [],
|
49
|
+
call: ['.set VAR="test_value"'],
|
50
|
+
vars: {}
|
51
|
+
)
|
52
|
+
|
53
|
+
assert_instance_of(Livetext, obj)
|
54
|
+
# Process some text to see if the variable was set
|
55
|
+
body, vars = obj.process(text: "Variable: $VAR")
|
56
|
+
assert_includes(body, "Variable: test_value")
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_customize_with_variables
|
60
|
+
# Test customize with variables
|
61
|
+
obj = Livetext.customize(
|
62
|
+
mix: [],
|
63
|
+
call: [],
|
64
|
+
vars: { 'name' => 'World', 'title' => 'Test' }
|
65
|
+
)
|
66
|
+
|
67
|
+
assert_instance_of(Livetext, obj)
|
68
|
+
# Process some text to see if variables were set
|
69
|
+
body, vars = obj.process(text: "Hello $name\n.h1 $title")
|
70
|
+
assert_includes(body, "Hello World")
|
71
|
+
assert_includes(body, "Test")
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_customize_comprehensive
|
75
|
+
# Test all features together
|
76
|
+
obj = Livetext.customize(
|
77
|
+
mix: ['tutorial'],
|
78
|
+
call: ['.set PLUGIN_VAR="plugin_value"'],
|
79
|
+
vars: { 'custom_var' => 'custom_value' }
|
80
|
+
)
|
81
|
+
|
82
|
+
assert_instance_of(Livetext, obj)
|
83
|
+
|
84
|
+
# Test that plugin was loaded
|
85
|
+
assert_includes(obj.methods, :title)
|
86
|
+
|
87
|
+
# Test that variables were set
|
88
|
+
body, vars = obj.process(text: "Plugin: $PLUGIN_VAR\nCustom: $custom_var")
|
89
|
+
assert_includes(body, "Plugin: plugin_value")
|
90
|
+
assert_includes(body, "Custom: custom_value")
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_customize_error_handling
|
94
|
+
# Test customize with invalid plugin
|
95
|
+
assert_raises(FileNotFound) do
|
96
|
+
Livetext.customize(mix: ['nonexistent_plugin'])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_customize_empty_parameters
|
101
|
+
# Test customize with empty parameters
|
102
|
+
obj = Livetext.customize()
|
103
|
+
assert_instance_of(Livetext, obj)
|
104
|
+
|
105
|
+
# Should still work for basic processing
|
106
|
+
body, vars = obj.process(text: "Hello world")
|
107
|
+
assert_includes(body, "Hello world")
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_customize_string_vs_array
|
111
|
+
# Test that string parameters are converted to arrays
|
112
|
+
obj = Livetext.customize(
|
113
|
+
mix: 'tutorial',
|
114
|
+
call: '.nopara',
|
115
|
+
vars: { 'test' => 'value' }
|
116
|
+
)
|
117
|
+
|
118
|
+
assert_instance_of(Livetext, obj)
|
119
|
+
assert_includes(obj.methods, :title)
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_customize_variables_accessible
|
123
|
+
# Test that variables passed to customize are actually accessible afterward
|
124
|
+
obj = Livetext.customize(
|
125
|
+
mix: [],
|
126
|
+
call: [],
|
127
|
+
vars: { 'name' => 'World', 'title' => 'Test Title', 'count' => '42' }
|
128
|
+
)
|
129
|
+
|
130
|
+
assert_instance_of(Livetext, obj)
|
131
|
+
|
132
|
+
# Test that variables are accessible via vars.to_h
|
133
|
+
vars_hash = obj.vars.to_h
|
134
|
+
assert_equal('World', vars_hash[:name])
|
135
|
+
assert_equal('Test Title', vars_hash[:title])
|
136
|
+
assert_equal('42', vars_hash[:count])
|
137
|
+
|
138
|
+
# Test that variables are accessible via variables.to_h
|
139
|
+
variables_hash = obj.variables.to_h
|
140
|
+
assert_equal('World', variables_hash[:name])
|
141
|
+
assert_equal('Test Title', variables_hash[:title])
|
142
|
+
assert_equal('42', variables_hash[:count])
|
143
|
+
|
144
|
+
# Test that variables work in processing
|
145
|
+
body, vars = obj.process(text: "Hello $name\n.h1 $title\nCount: $count")
|
146
|
+
assert_includes(body, "Hello World")
|
147
|
+
assert_includes(body, "Test Title")
|
148
|
+
assert_includes(body, "Count: 42")
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_customize_variables_global_access
|
152
|
+
# Test that variables passed to customize are accessible via Livetext::Vars
|
153
|
+
obj = Livetext.customize(
|
154
|
+
mix: [],
|
155
|
+
call: [],
|
156
|
+
vars: { 'name' => 'World', 'title' => 'Test Title', 'count' => '42' }
|
157
|
+
)
|
158
|
+
|
159
|
+
assert_instance_of(Livetext, obj)
|
160
|
+
|
161
|
+
# Test that variables are accessible via Livetext::Vars (global access)
|
162
|
+
assert_equal('World', Livetext::Vars[:name])
|
163
|
+
assert_equal('Test Title', Livetext::Vars[:title])
|
164
|
+
assert_equal('42', Livetext::Vars[:count])
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_variable_dot_access
|
168
|
+
# Test that variables can be accessed via live.vars.myvar syntax
|
169
|
+
obj = Livetext.customize(
|
170
|
+
mix: [],
|
171
|
+
call: [],
|
172
|
+
vars: { 'name' => 'World', 'title' => 'Test Title', 'count' => '42' }
|
173
|
+
)
|
174
|
+
|
175
|
+
assert_instance_of(Livetext, obj)
|
176
|
+
|
177
|
+
# Test dot access syntax
|
178
|
+
assert_equal('World', obj.vars.name)
|
179
|
+
assert_equal('Test Title', obj.vars.title)
|
180
|
+
assert_equal('42', obj.vars.count)
|
181
|
+
|
182
|
+
# Test that built-in variables also work
|
183
|
+
assert_equal(Livetext::VERSION, obj.vars.Version)
|
184
|
+
assert_equal(`hostname`.chomp, obj.vars.Hostname)
|
185
|
+
|
186
|
+
# Test that respond_to? works correctly
|
187
|
+
assert(obj.vars.respond_to?(:name))
|
188
|
+
assert(obj.vars.respond_to?(:title))
|
189
|
+
assert(obj.vars.respond_to?(:Version))
|
190
|
+
assert(obj.vars.respond_to?(:nonexistent)) # Now returns true since method_missing always returns a value
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_variable_dot_access_nonexistent
|
194
|
+
# Test what happens when accessing a nonexistent variable with dot syntax
|
195
|
+
obj = Livetext.customize(
|
196
|
+
mix: [],
|
197
|
+
call: [],
|
198
|
+
vars: { 'name' => 'World' }
|
199
|
+
)
|
200
|
+
|
201
|
+
assert_instance_of(Livetext, obj)
|
202
|
+
|
203
|
+
# Test that all access methods return the same fallback message
|
204
|
+
assert_equal('[nonexistent is undefined]', obj.vars.nonexistent)
|
205
|
+
assert_equal('[nonexistent is undefined]', obj.vars[:nonexistent])
|
206
|
+
assert_equal('[nonexistent is undefined]', obj.vars.get(:nonexistent))
|
207
|
+
|
208
|
+
# Test global access also returns fallback message
|
209
|
+
assert_equal('[nonexistent is undefined]', Livetext::Vars[:nonexistent])
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_process_text
|
213
|
+
# Test processing text directly
|
214
|
+
text = "Hello world\nThis is a test\n.h1 Title"
|
215
|
+
body, vars = @live.process(text: text)
|
216
|
+
|
217
|
+
assert_includes(body, "Hello world")
|
218
|
+
assert_includes(body, "This is a test")
|
219
|
+
# Should process the .h1 command
|
220
|
+
assert_instance_of(Hash, vars)
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_process_file
|
224
|
+
# Test processing a file
|
225
|
+
# Create a temporary test file
|
226
|
+
require 'tempfile'
|
227
|
+
temp_file = Tempfile.new(['test', '.lt3'])
|
228
|
+
temp_file.write("Hello from file\n.h1 File Title")
|
229
|
+
temp_file.close
|
230
|
+
|
231
|
+
body, vars = @live.process(file: temp_file.path)
|
232
|
+
|
233
|
+
assert_includes(body, "Hello from file")
|
234
|
+
# Should process the .h1 command
|
235
|
+
assert_instance_of(Hash, vars)
|
236
|
+
|
237
|
+
temp_file.unlink
|
238
|
+
end
|
239
|
+
|
240
|
+
def test_process_with_file
|
241
|
+
# Test process method with file parameter
|
242
|
+
require 'tempfile'
|
243
|
+
temp_file = Tempfile.new(['test', '.lt3'])
|
244
|
+
temp_file.write("Hello from process file\n.h1 Process Title")
|
245
|
+
temp_file.close
|
246
|
+
|
247
|
+
body, vars = @live.process(file: temp_file.path)
|
248
|
+
|
249
|
+
assert_includes(body, "Hello from process file")
|
250
|
+
# Should process the .h1 command
|
251
|
+
assert_instance_of(Hash, vars)
|
252
|
+
|
253
|
+
temp_file.unlink
|
254
|
+
end
|
255
|
+
|
256
|
+
def test_process_with_text
|
257
|
+
# Test process method with text parameter
|
258
|
+
text = "Hello from process text\n.h1 Process Text Title"
|
259
|
+
body, vars = @live.process(text: text)
|
260
|
+
|
261
|
+
assert_includes(body, "Hello from process text")
|
262
|
+
# Should process the .h1 command
|
263
|
+
assert_instance_of(Hash, vars)
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_process_with_vars
|
267
|
+
# Test process method with variables
|
268
|
+
text = "Hello $name\n.h1 $title"
|
269
|
+
body, vars = @live.process(text: text, vars: { 'name' => 'World', 'title' => 'Test Title' })
|
270
|
+
|
271
|
+
assert_includes(body, "Hello World")
|
272
|
+
assert_includes(body, "Test Title")
|
273
|
+
assert_equal('World', vars[:name])
|
274
|
+
assert_equal('Test Title', vars[:title])
|
275
|
+
end
|
276
|
+
|
277
|
+
def test_process_error_handling
|
278
|
+
# Test process method error cases
|
279
|
+
assert_raises(RuntimeError) { @live.process } # No file or text
|
280
|
+
assert_raises(RuntimeError) { @live.process(file: 'nonexistent.lt3', text: 'some text') } # Both file and text
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_backward_compatibility
|
284
|
+
# Test that old methods still work
|
285
|
+
text = "Hello from old method\n.h1 Old Title"
|
286
|
+
|
287
|
+
# Test transform
|
288
|
+
result1 = @live.transform(text)
|
289
|
+
assert_includes(result1, "Hello from old method")
|
290
|
+
|
291
|
+
# Test xform with text
|
292
|
+
result2 = @live.xform(text: text)
|
293
|
+
assert_includes(result2, "Hello from old method")
|
294
|
+
|
295
|
+
# Test xform_file
|
296
|
+
require 'tempfile'
|
297
|
+
temp_file = Tempfile.new(['test', '.lt3'])
|
298
|
+
temp_file.write("Hello from old file method\n.h1 Old File Title")
|
299
|
+
temp_file.close
|
300
|
+
|
301
|
+
result3 = @live.xform_file(temp_file.path)
|
302
|
+
assert_includes(result3, "Hello from old file method")
|
303
|
+
|
304
|
+
temp_file.unlink
|
305
|
+
end
|
306
|
+
|
307
|
+
def test_process_returns_array
|
308
|
+
# Test that process returns [body, vars] array
|
309
|
+
text = "Hello $name\n.set title=\"Test Title\"\n.h1 $title"
|
310
|
+
body, vars = @live.process(text: text, vars: { 'name' => 'World' })
|
311
|
+
|
312
|
+
assert_includes(body, "Hello World")
|
313
|
+
assert_includes(body, "Test Title")
|
314
|
+
assert_equal('World', vars[:name])
|
315
|
+
assert_equal('Test Title', vars[:title])
|
316
|
+
end
|
317
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
require_relative '../../lib/livetext'
|
4
|
+
|
5
|
+
class TestingLivetextFormatter < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@live = Livetext.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_formatter_component_initialization
|
11
|
+
# Test that Formatter is properly initialized
|
12
|
+
assert(@live.formatter, "Formatter should be initialized")
|
13
|
+
assert_instance_of(Livetext::Formatter, @live.formatter)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_basic_formatting
|
17
|
+
# Test basic text formatting
|
18
|
+
assert_equal("<b>bold</b>", @live.formatter.format("*bold"))
|
19
|
+
assert_equal("<i>italic</i>", @live.formatter.format("_italic"))
|
20
|
+
assert_equal("<tt>code</tt>", @live.formatter.format("`code"))
|
21
|
+
assert_equal("<strike>strike</strike>", @live.formatter.format("~strike"))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_double_markers
|
25
|
+
# Test double markers
|
26
|
+
assert_equal("<b>bold</b>", @live.formatter.format("**bold"))
|
27
|
+
assert_equal("**", @live.formatter.format("**")) # standalone
|
28
|
+
assert_equal(" ** ", @live.formatter.format(" ** ")) # surrounded by spaces
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_bracketed_markers
|
32
|
+
# Test bracketed markers
|
33
|
+
assert_equal("<b>content</b>", @live.formatter.format("*[content]"))
|
34
|
+
assert_equal("<i>content</i>", @live.formatter.format("_[content]"))
|
35
|
+
assert_equal("<tt>content</tt>", @live.formatter.format("`[content]"))
|
36
|
+
assert_equal("", @live.formatter.format("*[]")) # empty brackets disappear
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_escaped_markers
|
40
|
+
# Test escaped markers
|
41
|
+
assert_equal("*literal", @live.formatter.format("\\*literal"))
|
42
|
+
assert_equal("_literal", @live.formatter.format("\\_literal"))
|
43
|
+
assert_equal("`literal", @live.formatter.format("\\`literal"))
|
44
|
+
assert_equal("~literal", @live.formatter.format("\\~literal"))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_format_line
|
48
|
+
# Test format_line method
|
49
|
+
assert_equal("<b>bold</b>", @live.formatter.format_line("*bold\n"))
|
50
|
+
assert_equal("", @live.formatter.format_line(nil))
|
51
|
+
assert_equal("", @live.formatter.format_line(""))
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_format_multiple
|
55
|
+
# Test format_multiple method
|
56
|
+
lines = ["*bold\n", "_italic\n", "`code\n"]
|
57
|
+
expected = ["<b>bold</b>", "<i>italic</i>", "<tt>code</tt>"]
|
58
|
+
assert_equal(expected, @live.formatter.format_multiple(lines))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_convenience_methods
|
62
|
+
# Test convenience methods
|
63
|
+
assert_equal("<b>text</b>", @live.formatter.bold("text"))
|
64
|
+
assert_equal("<i>text</i>", @live.formatter.italic("text"))
|
65
|
+
assert_equal("<tt>text</tt>", @live.formatter.code("text"))
|
66
|
+
assert_equal("<strike>text</strike>", @live.formatter.strike("text"))
|
67
|
+
assert_equal("<a href='url'>text</a>", @live.formatter.link("text", "url"))
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_escape_html
|
71
|
+
# Test HTML escaping
|
72
|
+
assert_equal("<tag>", @live.formatter.escape_html("<tag>"))
|
73
|
+
assert_equal("&", @live.formatter.escape_html("&"))
|
74
|
+
assert_equal(""text"", @live.formatter.escape_html('"text"'))
|
75
|
+
assert_equal("'text'", @live.formatter.escape_html("'text'"))
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_edge_cases
|
79
|
+
# Test edge cases
|
80
|
+
assert_equal("", @live.formatter.format(nil))
|
81
|
+
assert_equal("", @live.formatter.format(""))
|
82
|
+
assert_equal("plain text", @live.formatter.format("plain text"))
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
|
3
|
+
require_relative '../../lib/livetext'
|
4
|
+
|
5
|
+
class TestingLivetextFormatter < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@live = Livetext.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_formatter_component_initialization
|
11
|
+
# Test that FormatterComponent is properly initialized
|
12
|
+
assert(@live.formatter, "FormatterComponent should be initialized")
|
13
|
+
assert_instance_of(Livetext::Formatter, @live.formatter)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_basic_formatting
|
17
|
+
# Test basic text formatting
|
18
|
+
assert_equal("<b>bold</b>", @live.formatter.format("*bold"))
|
19
|
+
assert_equal("<i>italic</i>", @live.formatter.format("_italic"))
|
20
|
+
assert_equal("<tt>code</tt>", @live.formatter.format("`code"))
|
21
|
+
assert_equal("<strike>strike</strike>", @live.formatter.format("~strike"))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_double_markers
|
25
|
+
# Test double markers
|
26
|
+
assert_equal("<b>bold</b>", @live.formatter.format("**bold"))
|
27
|
+
assert_equal("**", @live.formatter.format("**")) # standalone
|
28
|
+
assert_equal(" ** ", @live.formatter.format(" ** ")) # surrounded by spaces
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_bracketed_markers
|
32
|
+
# Test bracketed markers
|
33
|
+
assert_equal("<b>content</b>", @live.formatter.format("*[content]"))
|
34
|
+
assert_equal("<i>content</i>", @live.formatter.format("_[content]"))
|
35
|
+
assert_equal("<tt>content</tt>", @live.formatter.format("`[content]"))
|
36
|
+
assert_equal("", @live.formatter.format("*[]")) # empty brackets disappear
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_escaped_markers
|
40
|
+
# Test escaped markers
|
41
|
+
assert_equal("*literal", @live.formatter.format("\\*literal"))
|
42
|
+
assert_equal("_literal", @live.formatter.format("\\_literal"))
|
43
|
+
assert_equal("`literal", @live.formatter.format("\\`literal"))
|
44
|
+
assert_equal("~literal", @live.formatter.format("\\~literal"))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_format_line
|
48
|
+
# Test format_line method
|
49
|
+
assert_equal("<b>bold</b>", @live.formatter.format_line("*bold\n"))
|
50
|
+
assert_equal("", @live.formatter.format_line(nil))
|
51
|
+
assert_equal("", @live.formatter.format_line(""))
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_format_multiple
|
55
|
+
# Test format_multiple method
|
56
|
+
lines = ["*bold\n", "_italic\n", "`code\n"]
|
57
|
+
expected = ["<b>bold</b>", "<i>italic</i>", "<tt>code</tt>"]
|
58
|
+
assert_equal(expected, @live.formatter.format_multiple(lines))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_convenience_methods
|
62
|
+
# Test convenience methods
|
63
|
+
assert_equal("<b>text</b>", @live.formatter.bold("text"))
|
64
|
+
assert_equal("<i>text</i>", @live.formatter.italic("text"))
|
65
|
+
assert_equal("<tt>text</tt>", @live.formatter.code("text"))
|
66
|
+
assert_equal("<strike>text</strike>", @live.formatter.strike("text"))
|
67
|
+
assert_equal("<a href='url'>text</a>", @live.formatter.link("text", "url"))
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_escape_html
|
71
|
+
# Test HTML escaping
|
72
|
+
assert_equal("<tag>", @live.formatter.escape_html("<tag>"))
|
73
|
+
assert_equal("&", @live.formatter.escape_html("&"))
|
74
|
+
assert_equal(""text"", @live.formatter.escape_html('"text"'))
|
75
|
+
assert_equal("'text'", @live.formatter.escape_html("'text'"))
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_edge_cases
|
79
|
+
# Test edge cases
|
80
|
+
assert_equal("", @live.formatter.format(nil))
|
81
|
+
assert_equal("", @live.formatter.format(""))
|
82
|
+
assert_equal("plain text", @live.formatter.format("plain text"))
|
83
|
+
end
|
84
|
+
end
|