howzit 2.1.27 → 2.1.29

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.
@@ -0,0 +1,261 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Howzit::ConditionEvaluator do
6
+ describe '.evaluate' do
7
+ context 'with string comparisons' do
8
+ it 'evaluates == correctly' do
9
+ expect(described_class.evaluate('"test" == "test"', {})).to be true
10
+ expect(described_class.evaluate('"test" == "other"', {})).to be false
11
+ end
12
+
13
+ it 'evaluates =~ regex correctly' do
14
+ expect(described_class.evaluate('"test" =~ /es/', {})).to be true
15
+ expect(described_class.evaluate('"test" =~ /xyz/', {})).to be false
16
+ end
17
+
18
+ it 'evaluates *= (contains) correctly' do
19
+ expect(described_class.evaluate('"testing" *= "est"', {})).to be true
20
+ expect(described_class.evaluate('"testing" *= "xyz"', {})).to be false
21
+ end
22
+
23
+ it 'evaluates ^= (starts with) correctly' do
24
+ expect(described_class.evaluate('"testing" ^= "test"', {})).to be true
25
+ expect(described_class.evaluate('"testing" ^= "ing"', {})).to be false
26
+ end
27
+
28
+ it 'evaluates $= (ends with) correctly' do
29
+ expect(described_class.evaluate('"testing" $= "ing"', {})).to be true
30
+ expect(described_class.evaluate('"testing" $= "test"', {})).to be false
31
+ end
32
+
33
+ it 'evaluates **= (fuzzy match) correctly' do
34
+ expect(described_class.evaluate('"fluffy" **= "ffy"', {})).to be true
35
+ expect(described_class.evaluate('"fluffy" **= "fly"', {})).to be true
36
+ expect(described_class.evaluate('"fluffy" **= "fuf"', {})).to be true
37
+ expect(described_class.evaluate('"fluffy" **= "xyz"', {})).to be false
38
+ expect(described_class.evaluate('"fluffy" **= "fxy"', {})).to be false
39
+ end
40
+ end
41
+
42
+ context 'with numeric comparisons' do
43
+ it 'evaluates == correctly' do
44
+ expect(described_class.evaluate('5 == 5', {})).to be true
45
+ expect(described_class.evaluate('5 == 3', {})).to be false
46
+ end
47
+
48
+ it 'evaluates != correctly' do
49
+ expect(described_class.evaluate('5 != 3', {})).to be true
50
+ expect(described_class.evaluate('5 != 5', {})).to be false
51
+ end
52
+
53
+ it 'evaluates > correctly' do
54
+ expect(described_class.evaluate('5 > 3', {})).to be true
55
+ expect(described_class.evaluate('3 > 5', {})).to be false
56
+ end
57
+
58
+ it 'evaluates >= correctly' do
59
+ expect(described_class.evaluate('5 >= 5', {})).to be true
60
+ expect(described_class.evaluate('5 >= 3', {})).to be true
61
+ expect(described_class.evaluate('3 >= 5', {})).to be false
62
+ end
63
+
64
+ it 'evaluates < correctly' do
65
+ expect(described_class.evaluate('3 < 5', {})).to be true
66
+ expect(described_class.evaluate('5 < 3', {})).to be false
67
+ end
68
+
69
+ it 'evaluates <= correctly' do
70
+ expect(described_class.evaluate('3 <= 3', {})).to be true
71
+ expect(described_class.evaluate('3 <= 5', {})).to be true
72
+ expect(described_class.evaluate('5 <= 3', {})).to be false
73
+ end
74
+ end
75
+
76
+ context 'with negation' do
77
+ it 'handles not prefix' do
78
+ expect(described_class.evaluate('not "test" == "other"', {})).to be true
79
+ expect(described_class.evaluate('not "test" == "test"', {})).to be false
80
+ end
81
+
82
+ it 'handles ! prefix' do
83
+ expect(described_class.evaluate('! "test" == "other"', {})).to be true
84
+ expect(described_class.evaluate('! "test" == "test"', {})).to be false
85
+ end
86
+ end
87
+
88
+ context 'with positional arguments' do
89
+ before do
90
+ Howzit.arguments = %w[arg1 arg2 arg3]
91
+ end
92
+
93
+ after do
94
+ Howzit.arguments = nil
95
+ end
96
+
97
+ it 'evaluates $1, $2, etc.' do
98
+ expect(described_class.evaluate('$1 == "arg1"', {})).to be true
99
+ expect(described_class.evaluate('$2 == "arg2"', {})).to be true
100
+ expect(described_class.evaluate('$1 == "other"', {})).to be false
101
+ end
102
+ end
103
+
104
+ context 'with named arguments' do
105
+ before do
106
+ Howzit.named_arguments = { test: 'value', other: 'thing' }
107
+ end
108
+
109
+ after do
110
+ Howzit.named_arguments = nil
111
+ end
112
+
113
+ it 'evaluates named arguments' do
114
+ expect(described_class.evaluate('test == "value"', {})).to be true
115
+ expect(described_class.evaluate('other == "thing"', {})).to be true
116
+ expect(described_class.evaluate('test == "other"', {})).to be false
117
+ end
118
+
119
+ it 'evaluates named arguments with ${} syntax' do
120
+ Howzit.named_arguments = { var: 'val', env: 'production' }
121
+ expect(described_class.evaluate('${var} == "val"', {})).to be true
122
+ expect(described_class.evaluate('${env} == "production"', {})).to be true
123
+ expect(described_class.evaluate('${var} == "other"', {})).to be false
124
+ end
125
+ end
126
+
127
+ context 'with metadata' do
128
+ it 'evaluates metadata keys' do
129
+ context = { metadata: { 'key1' => 'value1', 'key2' => 'value2' } }
130
+ expect(described_class.evaluate('key1 == "value1"', context)).to be true
131
+ expect(described_class.evaluate('key2 == "value2"', context)).to be true
132
+ expect(described_class.evaluate('key1 == "other"', context)).to be false
133
+ end
134
+ end
135
+
136
+ context 'with environment variables' do
137
+ it 'evaluates environment variables' do
138
+ ENV['TEST_VAR'] = 'test_value'
139
+ expect(described_class.evaluate('TEST_VAR == "test_value"', {})).to be true
140
+ ENV.delete('TEST_VAR')
141
+ end
142
+ end
143
+
144
+ context 'with special conditions' do
145
+ it 'evaluates git dirty' do
146
+ # Just test that it doesn't crash
147
+ result = described_class.evaluate('git dirty', {})
148
+ expect([true, false]).to include(result)
149
+ end
150
+
151
+ it 'evaluates git clean' do
152
+ result = described_class.evaluate('git clean', {})
153
+ expect([true, false]).to include(result)
154
+ end
155
+
156
+ it 'evaluates file exists' do
157
+ expect(described_class.evaluate('file exists /dev/null', {})).to be true
158
+ expect(described_class.evaluate('file exists /nonexistent/file', {})).to be false
159
+ end
160
+
161
+ it 'evaluates dir exists' do
162
+ expect(described_class.evaluate('dir exists /tmp', {})).to be true
163
+ expect(described_class.evaluate('dir exists /nonexistent/dir', {})).to be false
164
+ end
165
+
166
+ it 'evaluates cwd' do
167
+ result = described_class.evaluate('cwd', {})
168
+ expect(result).to be true
169
+ end
170
+
171
+ it 'evaluates working directory' do
172
+ result = described_class.evaluate('working directory', {})
173
+ expect(result).to be true
174
+ end
175
+
176
+ it 'evaluates cwd with string comparisons' do
177
+ cwd = Dir.pwd
178
+ expect(described_class.evaluate("cwd == \"#{cwd}\"", {})).to be true
179
+ expect(described_class.evaluate("cwd =~ /#{Regexp.escape(File.basename(cwd))}/", {})).to be true
180
+ expect(described_class.evaluate("cwd *= \"#{File.basename(cwd)}\"", {})).to be true
181
+ expect(described_class.evaluate("cwd ^= \"#{cwd[0..10]}\"", {})).to be true
182
+ expect(described_class.evaluate("cwd $= \"#{cwd[-10..-1]}\"", {})).to be true
183
+ end
184
+ end
185
+
186
+ context 'with file contents conditions' do
187
+ let(:test_file) { 'test_version.txt' }
188
+
189
+ before do
190
+ File.write(test_file, '0.1.2')
191
+ end
192
+
193
+ after do
194
+ File.delete(test_file) if File.exist?(test_file)
195
+ end
196
+
197
+ it 'evaluates file contents ^= (starts with) correctly' do
198
+ expect(described_class.evaluate("file contents #{test_file} ^= 0.", {})).to be true
199
+ expect(described_class.evaluate("file contents #{test_file} ^= 1.", {})).to be false
200
+ end
201
+
202
+ it 'evaluates file contents *= (contains) correctly' do
203
+ expect(described_class.evaluate("file contents #{test_file} *= 1.2", {})).to be true
204
+ expect(described_class.evaluate("file contents #{test_file} *= 2.3", {})).to be false
205
+ end
206
+
207
+ it 'evaluates file contents $= (ends with) correctly' do
208
+ expect(described_class.evaluate("file contents #{test_file} $= .2", {})).to be true
209
+ expect(described_class.evaluate("file contents #{test_file} $= .3", {})).to be false
210
+ end
211
+
212
+ it 'evaluates file contents == correctly' do
213
+ expect(described_class.evaluate("file contents #{test_file} == 0.1.2", {})).to be true
214
+ expect(described_class.evaluate("file contents #{test_file} == 1.0.0", {})).to be false
215
+ end
216
+
217
+ it 'evaluates file contents != correctly' do
218
+ expect(described_class.evaluate("file contents #{test_file} != 1.0.0", {})).to be true
219
+ expect(described_class.evaluate("file contents #{test_file} != 0.1.2", {})).to be false
220
+ end
221
+
222
+ it 'evaluates file contents **= (fuzzy match) correctly' do
223
+ expect(described_class.evaluate("file contents #{test_file} **= 012", {})).to be true
224
+ expect(described_class.evaluate("file contents #{test_file} **= 021", {})).to be false
225
+ end
226
+
227
+ it 'evaluates file contents =~ (regex) correctly' do
228
+ expect(described_class.evaluate("file contents #{test_file} =~ /0\\.\\d+\\.\\d+/", {})).to be true
229
+ expect(described_class.evaluate("file contents #{test_file} =~ /1\\.\\d+\\.\\d+/", {})).to be false
230
+ end
231
+
232
+ it 'returns false for non-existent file' do
233
+ expect(described_class.evaluate('file contents nonexistent.txt ^= 0.', {})).to be false
234
+ end
235
+
236
+ it 'handles file path as variable' do
237
+ context = { metadata: { 'version_file' => test_file } }
238
+ expect(described_class.evaluate('file contents version_file ^= 0.', context)).to be true
239
+ end
240
+ end
241
+
242
+ context 'with simple existence checks' do
243
+ before do
244
+ Howzit.named_arguments = { defined_var: 'value' }
245
+ end
246
+
247
+ after do
248
+ Howzit.named_arguments = nil
249
+ end
250
+
251
+ it 'returns true for defined variables' do
252
+ expect(described_class.evaluate('defined_var', {})).to be true
253
+ end
254
+
255
+ it 'returns false for undefined variables' do
256
+ expect(described_class.evaluate('undefined_var', {})).to be false
257
+ end
258
+ end
259
+ end
260
+ end
261
+
@@ -0,0 +1,159 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'Conditional Blocks Integration' do
6
+ before do
7
+ Howzit.options[:include_upstream] = false
8
+ Howzit.options[:default] = true
9
+ Howzit.options[:matching] = 'partial'
10
+ Howzit.options[:multiple_matches] = 'choose'
11
+ end
12
+
13
+ after do
14
+ FileUtils.rm_f('builda.md')
15
+ end
16
+
17
+ describe 'with conditional blocks in topics' do
18
+ it 'includes content when @if condition is true' do
19
+ note = <<~EONOTE
20
+ # Test
21
+
22
+ ## Test Topic
23
+
24
+ @if "test" == "test"
25
+ This should be included
26
+ @end
27
+ EONOTE
28
+ File.open('builda.md', 'w') { |f| f.puts note }
29
+ Howzit.instance_variable_set(:@buildnote, nil) # Force reload
30
+ topic = Howzit.buildnote.find_topic('Test Topic')[0]
31
+ expect(topic).not_to be_nil
32
+ output = topic.print_out
33
+ expect(output.join("\n")).to include('This should be included')
34
+ expect(output.join("\n")).not_to include('@if')
35
+ expect(output.join("\n")).not_to include('@end')
36
+ end
37
+
38
+ it 'excludes content when @if condition is false' do
39
+ note = <<~EONOTE
40
+ # Test
41
+
42
+ ## Test Topic
43
+
44
+ @if "test" == "other"
45
+ This should NOT be included
46
+ @end
47
+ EONOTE
48
+ File.open('builda.md', 'w') { |f| f.puts note }
49
+ Howzit.instance_variable_set(:@buildnote, nil) # Force reload
50
+ topic = Howzit.buildnote.find_topic('Test Topic')[0]
51
+ expect(topic).not_to be_nil
52
+ output = topic.print_out
53
+ expect(output.join("\n")).not_to include('This should NOT be included')
54
+ end
55
+
56
+ it 'includes tasks when condition is true' do
57
+ note = <<~EONOTE
58
+ # Test
59
+
60
+ ## Test Topic
61
+
62
+ @if 1 == 1
63
+ @run(echo "test") Test Command
64
+ @end
65
+ EONOTE
66
+ File.open('builda.md', 'w') { |f| f.puts note }
67
+ Howzit.instance_variable_set(:@buildnote, nil) # Force reload
68
+ topic = Howzit.buildnote.find_topic('Test Topic')[0]
69
+ expect(topic).not_to be_nil
70
+ expect(topic.tasks.count).to eq(1)
71
+ expect(topic.tasks[0].action).to include('echo "test"')
72
+ end
73
+
74
+ it 'excludes tasks when condition is false' do
75
+ note = <<~EONOTE
76
+ # Test
77
+
78
+ ## Test Topic
79
+
80
+ @if 1 == 2
81
+ @run(echo "hidden") Hidden Command
82
+ @end
83
+ EONOTE
84
+ File.open('builda.md', 'w') { |f| f.puts note }
85
+ Howzit.instance_variable_set(:@buildnote, nil) # Force reload
86
+ topic = Howzit.buildnote.find_topic('Test Topic')[0]
87
+ expect(topic).not_to be_nil
88
+ expect(topic.tasks.count).to eq(0)
89
+ end
90
+
91
+ it 'handles nested conditional blocks' do
92
+ note = <<~EONOTE
93
+ # Test
94
+
95
+ ## Test Topic
96
+
97
+ @if "outer" == "outer"
98
+ Outer content
99
+ @if "inner" == "inner"
100
+ Inner content
101
+ @end
102
+ More outer content
103
+ @end
104
+ EONOTE
105
+ File.open('builda.md', 'w') { |f| f.puts note }
106
+ Howzit.instance_variable_set(:@buildnote, nil) # Force reload
107
+ topic = Howzit.buildnote.find_topic('Test Topic')[0]
108
+ expect(topic).not_to be_nil
109
+ output = topic.print_out
110
+ expect(output.join("\n")).to include('Outer content')
111
+ expect(output.join("\n")).to include('Inner content')
112
+ expect(output.join("\n")).to include('More outer content')
113
+ end
114
+
115
+ it 'handles metadata in conditions' do
116
+ note = <<~EONOTE
117
+ env: production
118
+
119
+ # Test
120
+
121
+ ## Test Topic
122
+
123
+ @if env == "production"
124
+ Production content
125
+ @end
126
+ EONOTE
127
+ File.open('builda.md', 'w') { |f| f.puts note }
128
+ Howzit.instance_variable_set(:@buildnote, nil) # Force reload
129
+ topic = Howzit.buildnote.find_topic('Test Topic')[0]
130
+ expect(topic).not_to be_nil
131
+ output = topic.print_out
132
+ expect(output.join("\n")).to include('Production content')
133
+ end
134
+
135
+ it 'handles @unless blocks correctly' do
136
+ note = <<~EONOTE
137
+ # Test
138
+
139
+ ## Test Topic
140
+
141
+ @unless "test" == "other"
142
+ This should be included
143
+ @end
144
+
145
+ @unless "test" == "test"
146
+ This should NOT be included
147
+ @end
148
+ EONOTE
149
+ File.open('builda.md', 'w') { |f| f.puts note }
150
+ Howzit.instance_variable_set(:@buildnote, nil) # Force reload
151
+ topic = Howzit.buildnote.find_topic('Test Topic')[0]
152
+ expect(topic).not_to be_nil
153
+ output = topic.print_out
154
+ expect(output.join("\n")).to include('This should be included')
155
+ expect(output.join("\n")).not_to include('This should NOT be included')
156
+ end
157
+ end
158
+ end
159
+