-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtest.lua
More file actions
294 lines (255 loc) · 14.4 KB
/
Copy pathtest.lua
File metadata and controls
294 lines (255 loc) · 14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#!/usr/bin/env lua
-- Tests for claude-copy/clean.lua
-- Run: lua test.lua
local clean = dofile("clean.lua")
local passed, failed = 0, 0
local function test(name, fn)
local ok, err = pcall(fn)
if ok then
passed = passed + 1
else
failed = failed + 1
io.write("FAIL: " .. name .. "\n " .. tostring(err) .. "\n")
end
end
local function eq(got, expected, msg)
if got ~= expected then
error((msg or "") .. "\n expected: " .. tostring(expected) .. "\n got: " .. tostring(got))
end
end
-- Helper: simulate raw clipboard with 2-space margin on each line.
local function margin(lines)
local out = {}
for _, l in ipairs(lines) do
out[#out + 1] = " " .. l
end
return table.concat(out, "\n")
end
-- Helper: simulate raw clipboard with 2-space margin + pipe on each line.
local function piped(lines)
local out = {}
for _, l in ipairs(lines) do
out[#out + 1] = " │ " .. l
end
return table.concat(out, "\n")
end
-- ═══════════════════════════════════════════════════════════════
-- Classification
-- ═══════════════════════════════════════════════════════════════
test("classify: piped prose → full", function()
local input = piped({
"This is a long line of text that wraps at the terminal width and keeps on going until",
"it reaches the end of the paragraph and finishes here.",
})
local r = clean.classify(input)
eq(r.mode, "full")
end)
test("classify: margined prose → full (high coverage, no code)", function()
local input = margin({
"This is a long line of text that wraps at the terminal width and keeps on going until",
"it reaches the end of the paragraph and finishes here with more text added for width.",
})
local r = clean.classify(input)
eq(r.mode, "full")
end)
test("classify: no margin → none", function()
local input = "just plain text\nwith no margin at all"
local r = clean.classify(input)
eq(r.mode, "none")
end)
test("classify: single line → none", function()
local input = " │ just one line"
local r = clean.classify(input)
eq(r.mode, "none")
end)
-- ═══════════════════════════════════════════════════════════════
-- Bug fix: sentence ending at wrap point (posture corrector)
-- ═══════════════════════════════════════════════════════════════
test("classify: sentence ending at wrap point counts as wrapped pair", function()
local input = margin({
"My coworker spent $200 a month on a chiropractor for her back. I showed her this $3",
"posture corrector and she hasn't been back since. 10,000 people already figured this out.",
" Breathable, adjustable, invisible under a shirt. $45 profit per sale at 94% margin.",
"Would you sell this or wear it? Link in bio for more winning products.",
})
local r = clean.classify(input)
eq(r.mode, "full", "should be full, not " .. r.mode)
end)
test("clean: sentence ending at wrap point rejoins fully", function()
local input = margin({
"My coworker spent $200 a month on a chiropractor for her back. I showed her this $3",
"posture corrector and she hasn't been back since. 10,000 people already figured this out.",
" Breathable, adjustable, invisible under a shirt. $45 profit per sale at 94% margin.",
"Would you sell this or wear it? Link in bio for more winning products.",
})
local result = clean.clean(input)
eq(result:find("\n"), nil, "should be one paragraph with no line breaks")
assert(result:find("this %$3 posture"), "should join '$3' and 'posture' with space")
assert(result:find("out%. Breathable"), "should join 'out.' and 'Breathable' with space")
end)
-- ═══════════════════════════════════════════════════════════════
-- Bug fix: partial copy first line (protein shaker)
-- ═══════════════════════════════════════════════════════════════
test("classify: partial copy (first line no margin) → full", function()
-- Selection started mid-line after "Description: "
local input = "I used to stand there shaking my protein bottle like an idiot after every\n"
.. " workout. Then I found this cup with a 7,000 RPM motor hidden inside. Press one button and\n"
.. " it blends everything smooth in seconds. USB rechargeable so it goes in your gym bag. $12\n"
.. " to source, sell for $40, nearly $28 profit per sale. The gym crowd can't stop buying\n"
.. " these. Would you sell it or use it? Link in bio for more winning products."
local r = clean.classify(input)
eq(r.mode, "full", "should be full, not " .. r.mode)
end)
test("clean: partial copy first line joins with rest", function()
local input = "I used to stand there shaking my protein bottle like an idiot after every\n"
.. " workout. Then I found this cup with a 7,000 RPM motor hidden inside. Press one button and\n"
.. " it blends everything smooth in seconds. USB rechargeable so it goes in your gym bag. $12\n"
.. " to source, sell for $40, nearly $28 profit per sale. The gym crowd can't stop buying\n"
.. " these. Would you sell it or use it? Link in bio for more winning products."
local result = clean.clean(input)
eq(result:find("\n"), nil, "should be one paragraph")
assert(result:find("every workout"), "should join 'every' and 'workout' with space")
end)
-- ═══════════════════════════════════════════════════════════════
-- Bug fix: hard break mid-word in spaceless text (comma-separated keywords)
-- ═══════════════════════════════════════════════════════════════
test("classify: spaceless text with hard break tail → full", function()
local input = margin({
"shopify,ecommerce,saas,b2b,shopifyapps,shopifythemes,analytics,emailmarketing,reviews,loyalty,crm,leadge",
"neration",
})
local r = clean.classify(input)
eq(r.mode, "full", "should be full, not " .. r.mode)
end)
test("clean: hard break mid-word joins without space", function()
local input = margin({
"shopify,ecommerce,saas,b2b,shopifyapps,shopifythemes,analytics,emailmarketing,reviews,loyalty,crm,leadge",
"neration",
})
local result = clean.clean(input)
eq(result:find("\n"), nil, "should be one line")
assert(result:find("leadgeneration"), "should join without space, got: " .. result:sub(-30))
assert(not result:find("leadge neration"), "should NOT have space in middle of word")
end)
-- ═══════════════════════════════════════════════════════════════
-- Paragraph breaks should be preserved
-- ═══════════════════════════════════════════════════════════════
test("clean: blank line between paragraphs is preserved", function()
local input = piped({
"First paragraph that is long enough to look like a real line of prose in the terminal.",
"",
"Second paragraph that is also long enough to look like prose in a terminal window here.",
})
local result = clean.clean(input)
assert(result:find("\n\n"), "blank line between paragraphs should be preserved")
end)
-- ═══════════════════════════════════════════════════════════════
-- Structural lines should not be rejoined
-- ═══════════════════════════════════════════════════════════════
test("clean: bullet list not rejoined", function()
local input = piped({
"- First item in the list",
"- Second item in the list",
"- Third item in the list",
})
local result = clean.clean(input)
local lines = {}
for l in (result .. "\n"):gmatch("(.-)\n") do lines[#lines + 1] = l end
eq(#lines, 3, "bullet list should stay as 3 lines")
end)
test("clean: Key: value lines not rejoined", function()
local input = piped({
"Title: Something interesting here",
"Description: A longer description that has some detail about the topic at hand right now.",
})
local result = clean.clean(input)
assert(result:find("\n"), "Key: value lines should stay separate")
end)
test("clean: hashtag lines are rejoined", function()
local input = piped({
"your next product research session. #beautytok #makeuptok #eyebrows",
"#winningproducts #dropshipping",
})
local result = clean.clean(input)
assert(result:find("eyebrows #winning"), "hashtag lines should be rejoined")
end)
-- ═══════════════════════════════════════════════════════════════
-- Ambiguous keywords in prose should not break rejoin
-- ═══════════════════════════════════════════════════════════════
test("clean: line starting with 'if' in prose is rejoined", function()
local input = piped({
"profit per unit at 92% margin. 3,000 sellers already moved this product. The beauty niche prints money",
"if you pick the right products. Drop your selling price in the comments and bet nobody beats 92% margin",
})
local result = clean.clean(input)
assert(result:find("money if you"), "should rejoin 'money' and 'if you'")
end)
test("clean: line starting with 'for' in prose is rejoined", function()
local input = piped({
"3,000 sellers already moved this product. The beauty niche prints money if you pick the right products",
"for your next product research session. Save this and share it with someone who needs to hear all this.",
})
local result = clean.clean(input)
assert(result:find("products for your"), "should rejoin 'products' and 'for your'")
end)
test("clean: actual code 'if' with parens is NOT rejoined", function()
local input = piped({
"const x = 1;",
"if (x > 0) {",
" return true;",
"}",
})
local result = clean.clean(input)
assert(result:find("\n"), "code lines should stay separate")
end)
-- ═══════════════════════════════════════════════════════════════
-- Partial copy with full-width lines should be rejoined
-- ═══════════════════════════════════════════════════════════════
test("classify: partial copy prose with full-width lines is full mode", function()
-- First line has no margin (selection started mid-line), rest have 2-space margins
local input = table.concat({
"Our audience is Shopify agencies, freelancers, and e-commerce operators who use",
" StoreInspect to find and analyze Shopify stores. After identifying prospects, they need cold outreach",
" tools like lemlist. We mention lemlist in our guide on how to sell to Shopify stores.",
}, "\n")
local c = clean.classify(input)
assert(c.mode == "full", "expected full, got " .. c.mode)
end)
test("clean: partial copy with full-width wrap is rejoined", function()
local input = table.concat({
"Our audience is Shopify agencies, freelancers, and e-commerce operators who use",
" StoreInspect to find and analyze Shopify stores. After identifying prospects, they need cold outreach",
" tools like lemlist. We mention lemlist in our guide on how to sell to Shopify stores.",
}, "\n")
local result = clean.clean(input)
assert(result:find("use StoreInspect"), "partial copy prose should be rejoined")
assert(not result:find("\n"), "should be a single line")
end)
-- ═══════════════════════════════════════════════════════════════
-- Code should not be rejoined
-- ═══════════════════════════════════════════════════════════════
test("clean: code lines not rejoined", function()
local input = piped({
"const x = 1;",
"const y = 2;",
"const z = x + y;",
})
local result = clean.clean(input)
local lines = {}
for l in (result .. "\n"):gmatch("(.-)\n") do lines[#lines + 1] = l end
eq(#lines, 3, "code lines should stay as 3 lines")
end)
-- ═══════════════════════════════════════════════════════════════
-- Strip-only mode
-- ═══════════════════════════════════════════════════════════════
test("stripOnly: removes 2-space margin", function()
local input = " │ Hello world\n │ Second line"
local result = clean.stripOnly(input)
assert(not result:find("│"), "pipe should be removed")
assert(result:find("^Hello world"), "margin should be stripped")
end)
-- ═══════════════════════════════════════════════════════════════
-- Results
-- ═══════════════════════════════════════════════════════════════
io.write(string.format("\n%d passed, %d failed\n", passed, failed))
os.exit(failed > 0 and 1 or 0)