char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
92d1bb0c9
char/aliceai-t5-moe
1import { AttachmentType } from '$lib/enums' ; 2import { 3formatMessageForClipboard , 4hasClipboardAttachments , 5parseClipboardContent 6} from '$lib/utils/clipboard' ; 7import { describe , expect , it } from 'vitest' ; 8 9describe ( 'formatMessageForClipboard' , () => { 10it ( 'returns plain content when no extras' , () => { 11const result = formatMessageForClipboard ( 'Hello world' , undefined ); 12 13expect ( result ). toBe ( 'Hello world' ); 14}); 15 16it ( 'returns plain content when extras is empty array' , () => { 17const result = formatMessageForClipboard ( 'Hello world' , []); 18 19expect ( result ). toBe ( 'Hello world' ); 20}); 21 22it ( 'handles empty string content' , () => { 23const result = formatMessageForClipboard ( '' , undefined ); 24 25expect ( result ). toBe ( '' ); 26}); 27 28it ( 'returns plain content when extras has only non-text attachments' , () => { 29const extras = [ 30{ 31base64Url :'data:image/png;base64,...' , 32name :'image.png' , 33type :AttachmentType . IMAGE as const 34} 35]; 36const result = formatMessageForClipboard ( 'Hello world' , extras ); 37 38expect ( result ). toBe ( 'Hello world' ); 39}); 40 41it ( 'filters non-text attachments and keeps only text ones' , () => { 42const extras = [ 43{ 44base64Url :'data:image/png;base64,...' , 45name :'image.png' , 46type :AttachmentType . IMAGE as const 47}, 48{ 49content :'Text content' , 50name :'file.txt' , 51type :AttachmentType . TEXT as const 52}, 53{ 54base64Data :'data:application/pdf;base64,...' , 55content :'PDF content' , 56name :'doc.pdf' , 57processedAsImages :false , 58type :AttachmentType . as const 59} 60]; 61const result = formatMessageForClipboard ( 'Hello' , extras ); 62 63expect ( result ). toContain ( '"file.txt"' ); 64expect ( result ). not . toContain ( 'image.png' ); 65expect ( result ). not . toContain ( 'doc.pdf' ); 66}); 67 68it ( 'formats message with text attachments' , () => { 69const extras = [ 70{ 71content :'File 1 content' , 72name :'file1.txt' , 73type :AttachmentType . TEXT as const 74}, 75{ 76content :'File 2 content' , 77name :'file2.txt' , 78type :AttachmentType . TEXT as const 79} 80]; 81const result = formatMessageForClipboard ( 'Hello world' , extras ); 82 83expect ( result ). toContain ( '"Hello world"' ); 84expect ( result ). toContain ( '"type": "TEXT"' ); 85expect ( result ). toContain ( '"name": "file1.txt"' ); 86expect ( result ). toContain ( '"content": "File 1 content"' ); 87expect ( result ). toContain ( '"name": "file2.txt"' ); 88}); 89 90it ( 'handles content with quotes and special characters' , () => { 91const content = 'Hello "world" with\nnewline' ; 92const extras = [ 93{ 94content :'Test content' , 95name :'test.txt' , 96type :AttachmentType . TEXT as const 97} 98]; 99const result = formatMessageForClipboard ( content , extras ); 100 101// Should be valid JSON 102expect ( result . startsWith ( '"' )). toBe ( true ); 103// The content should be properly escaped 104const parsed = JSON . parse ( result . split ( '\n' )[ 0 ]); 105 106expect ( parsed ). toBe ( content ); 107}); 108 109it ( 'converts legacy context type to TEXT type' , () => { 110const extras = [ 111{ 112content :'Legacy content' , 113name :'legacy.txt' , 114type :AttachmentType . LEGACY_CONTEXT as const 115} 116]; 117const result = formatMessageForClipboard ( 'Hello' , extras ); 118 119expect ( result ). toContain ( '"type": "TEXT"' ); 120expect ( result ). not . toContain ( '"context"' ); 121}); 122 123it ( 'handles attachment content with special characters' , () => { 124const extras = [ 125{ 126content :'const x = "hello\\nworld";\nconst y = `template ${var}`;' , 127name :'code.js' , 128type :AttachmentType . TEXT as const 129} 130]; 131const formatted = formatMessageForClipboard ( 'Check this code' , extras ); 132const parsed = parseClipboardContent ( formatted ); 133 134expect ( parsed . textAttachments [ 0 ]. content ). toBe ( 135'const x = "hello\\nworld";\nconst y = `template ${var}`;' 136); 137}); 138 139it ( 'handles unicode characters in content and attachments' , () => { 140const extras = [ 141{ 142content :'日本語テスト 🎉 émojis' , 143name :'unicode.txt' , 144type :AttachmentType . TEXT as const 145} 146]; 147const formatted = formatMessageForClipboard ( 'Привет мир 👋' , extras ); 148const parsed = parseClipboardContent ( formatted ); 149 150expect ( parsed . message ). toBe ( 'Привет мир 👋' ); 151expect ( parsed . textAttachments [ 0 ]. content ). toBe ( '日本語テスト 🎉 émojis' ); 152}); 153 154it ( 'formats as plain text when asPlainText is true' , () => { 155const extras = [ 156{ 157content :'File 1 content' , 158name :'file1.txt' , 159type :AttachmentType . TEXT as const 160}, 161{ 162content :'File 2 content' , 163name :'file2.txt' , 164type :AttachmentType . TEXT as const 165} 166]; 167const result = formatMessageForClipboard ( 'Hello world' , extras , true ); 168 169expect ( result ). toBe ( 'Hello world\n\nFile 1 content\n\nFile 2 content' ); 170}); 171 172it ( 'returns plain content when asPlainText is true but no attachments' , () => { 173const result = formatMessageForClipboard ( 'Hello world' , [], true ); 174 175expect ( result ). toBe ( 'Hello world' ); 176}); 177 178it ( 'plain text mode does not use JSON format' , () => { 179const extras = [ 180{ 181content :'Test content' , 182name :'test.txt' , 183type :AttachmentType . TEXT as const 184} 185]; 186const result = formatMessageForClipboard ( 'Hello' , extras , true ); 187 188expect ( result ). not . toContain ( '"type"' ); 189expect ( result ). not . toContain ( '[' ); 190expect ( result ). toBe ( 'Hello\n\nTest content' ); 191}); 192}); 193 194describe ( 'parseClipboardContent' , () => { 195it ( 'returns plain text as message when not in special format' , () => { 196const result = parseClipboardContent ( 'Hello world' ); 197 198expect ( result . message ). toBe ( 'Hello world' ); 199expect ( result . textAttachments ). toHaveLength ( 0 ); 200}); 201 202it ( 'handles empty string input' , () => { 203const result = parseClipboardContent ( '' ); 204 205expect ( result . message ). toBe ( '' ); 206expect ( result . textAttachments ). toHaveLength ( 0 ); 207}); 208 209it ( 'handles whitespace-only input' , () => { 210const result = parseClipboardContent ( ' \n\t ' ); 211 212expect ( result . message ). toBe ( ' \n\t ' ); 213expect ( result . textAttachments ). toHaveLength ( 0 ); 214}); 215 216it ( 'returns plain text as message when starts with quote but invalid format' , () => { 217const result = parseClipboardContent ( '"Unclosed quote' ); 218 219expect ( result . message ). toBe ( '"Unclosed quote' ); 220expect ( result . textAttachments ). toHaveLength ( 0 ); 221}); 222 223it ( 'returns original text when JSON array is malformed' , () => { 224const input = '"Hello"\n[invalid json' ; 225const result = parseClipboardContent ( input ); 226 227expect ( result . message ). toBe ( '"Hello"\n[invalid json' ); 228expect ( result . textAttachments ). toHaveLength ( 0 ); 229}); 230 231it ( 'parses message with text attachments' , () => { 232const input = `"Hello world" 233[ 234{"type":"TEXT","name":"file1.txt","content":"File 1 content"}, 235{"type":"TEXT","name":"file2.txt","content":"File 2 content"} 236]` ; 237const result = parseClipboardContent ( input ); 238 239expect ( result . message ). toBe ( 'Hello world' ); 240expect ( result . textAttachments ). toHaveLength ( 2 ); 241expect ( result . textAttachments [ 0 ]. name ). toBe ( 'file1.txt' ); 242expect ( result . textAttachments [ 0 ]. content ). toBe ( 'File 1 content' ); 243expect ( result . textAttachments [ 1 ]. name ). toBe ( 'file2.txt' ); 244expect ( result . textAttachments [ 1 ]. content ). toBe ( 'File 2 content' ); 245}); 246 247it ( 'handles escaped quotes in message' , () => { 248const input = `"Hello \\"world\\" with quotes" 249[ 250{"type":"TEXT","name":"file.txt","content":"test"} 251]` ; 252const result = parseClipboardContent ( input ); 253 254expect ( result . message ). toBe ( 'Hello "world" with quotes' ); 255expect ( result . textAttachments ). toHaveLength ( 1 ); 256}); 257 258it ( 'handles newlines in message' , () => { 259const input = `"Hello\\nworld" 260[ 261{"type":"TEXT","name":"file.txt","content":"test"} 262]` ; 263const result = parseClipboardContent ( input ); 264 265expect ( result . message ). toBe ( 'Hello\nworld' ); 266expect ( result . textAttachments ). toHaveLength ( 1 ); 267}); 268 269it ( 'returns message only when no array follows' , () => { 270const input = '"Just a quoted string"' ; 271const result = parseClipboardContent ( input ); 272 273expect ( result . message ). toBe ( 'Just a quoted string' ); 274expect ( result . textAttachments ). toHaveLength ( 0 ); 275}); 276 277it ( 'filters out invalid attachment objects' , () => { 278const input = `"Hello" 279[ 280{"type":"TEXT","name":"valid.txt","content":"valid"}, 281{"type":"INVALID","name":"invalid.txt","content":"invalid"}, 282{"name":"missing-type.txt","content":"missing"}, 283{"type":"TEXT","content":"missing name"} 284]` ; 285const result = parseClipboardContent ( input ); 286 287expect ( result . message ). toBe ( 'Hello' ); 288expect ( result . textAttachments ). toHaveLength ( 1 ); 289expect ( result . textAttachments [ 0 ]. name ). toBe ( 'valid.txt' ); 290}); 291 292it ( 'handles empty attachments array' , () => { 293const input = '"Hello"\n[]' ; 294const result = parseClipboardContent ( input ); 295 296expect ( result . message ). toBe ( 'Hello' ); 297expect ( result . textAttachments ). toHaveLength ( 0 ); 298}); 299 300it ( 'roundtrips correctly with formatMessageForClipboard' , () => { 301const originalContent = 'Hello "world" with\nspecial characters' ; 302const originalExtras = [ 303{ 304content :'Content with\nnewlines and "quotes"' , 305name :'file1.txt' , 306type :AttachmentType . TEXT as const 307}, 308{ 309content :'Another file' , 310name :'file2.txt' , 311type :AttachmentType . TEXT as const 312} 313]; 314const formatted = formatMessageForClipboard ( originalContent , originalExtras ); 315const parsed = parseClipboardContent ( formatted ); 316 317expect ( parsed . message ). toBe ( originalContent ); 318expect ( parsed . textAttachments ). toHaveLength ( 2 ); 319expect ( parsed . textAttachments [ 0 ]. name ). toBe ( 'file1.txt' ); 320expect ( parsed . textAttachments [ 0 ]. content ). toBe ( 'Content with\nnewlines and "quotes"' ); 321expect ( parsed . textAttachments [ 1 ]. name ). toBe ( 'file2.txt' ); 322expect ( parsed . textAttachments [ 1 ]. content ). toBe ( 'Another file' ); 323}); 324}); 325 326describe ( 'hasClipboardAttachments' , () => { 327it ( 'returns false for plain text' , () => { 328expect ( hasClipboardAttachments ( 'Hello world' )). toBe ( false ); 329}); 330 331it ( 'returns false for empty string' , () => { 332expect ( hasClipboardAttachments ( '' )). toBe ( false ); 333}); 334 335it ( 'returns false for quoted string without attachments' , () => { 336expect ( hasClipboardAttachments ( '"Hello world"' )). toBe ( false ); 337}); 338 339it ( 'returns true for valid format with attachments' , () => { 340const input = `"Hello" 341[{"type":"TEXT","name":"file.txt","content":"test"}]` ; 342 343expect ( hasClipboardAttachments ( input )). toBe ( true ); 344}); 345 346it ( 'returns false for format with empty attachments array' , () => { 347const input = '"Hello"\n[]' ; 348 349expect ( hasClipboardAttachments ( input )). toBe ( false ); 350}); 351 352it ( 'returns false for malformed JSON' , () => { 353expect ( hasClipboardAttachments ( '"Hello"\n[broken' )). toBe ( false ); 354}); 355}); 356 357describe ( 'roundtrip edge cases' , () => { 358it ( 'preserves empty message with attachments' , () => { 359const extras = [ 360{ 361content :'Content only' , 362name :'file.txt' , 363type :AttachmentType . TEXT as const 364} 365]; 366const formatted = formatMessageForClipboard ( '' , extras ); 367const parsed = parseClipboardContent ( formatted ); 368 369expect ( parsed . message ). toBe ( '' ); 370expect ( parsed . textAttachments ). toHaveLength ( 1 ); 371expect ( parsed . textAttachments [ 0 ]. content ). toBe ( 'Content only' ); 372}); 373 374it ( 'preserves attachment with empty content' , () => { 375const extras = [ 376{ 377content :'' , 378name :'empty.txt' , 379type :AttachmentType . TEXT as const 380} 381]; 382const formatted = formatMessageForClipboard ( 'Message' , extras ); 383const parsed = parseClipboardContent ( formatted ); 384 385expect ( parsed . message ). toBe ( 'Message' ); 386expect ( parsed . textAttachments ). toHaveLength ( 1 ); 387expect ( parsed . textAttachments [ 0 ]. content ). toBe ( '' ); 388}); 389 390it ( 'preserves multiple backslashes' , () => { 391const content = 'Path: C:\\\\Users\\\\test\\\\file.txt' ; 392const extras = [ 393{ 394content :'D:\\\\Data\\\\file' , 395name :'path.txt' , 396type :AttachmentType . TEXT as const 397} 398]; 399const formatted = formatMessageForClipboard ( content , extras ); 400const parsed = parseClipboardContent ( formatted ); 401 402expect ( parsed . message ). toBe ( content ); 403expect ( parsed . textAttachments [ 0 ]. content ). toBe ( 'D:\\\\Data\\\\file' ); 404}); 405 406it ( 'preserves tabs and various whitespace' , () => { 407const content = 'Line1\t\tTabbed\n Spaced\r\nCRLF' ; 408const extras = [ 409{ 410content :'\t\t\n\n ' , 411name :'whitespace.txt' , 412type :AttachmentType . TEXT as const 413} 414]; 415const formatted = formatMessageForClipboard ( content , extras ); 416const parsed = parseClipboardContent ( formatted ); 417 418expect ( parsed . message ). toBe ( content ); 419expect ( parsed . textAttachments [ 0 ]. content ). toBe ( '\t\t\n\n ' ); 420}); 421});