this repo has no description
at main 294 lines 11 kB view raw
1import assert from 'node:assert' 2import { describe, test } from 'node:test' 3import { TaggedStringParser } from '../../src/TaggedStringParser.ts' 4 5// Helper to access private method for testing 6type ParserWithExtractQuotedString = { 7 extractQuotedString: ( 8 message: string, 9 startPos: number, 10 ) => { content: string; endPosition: number } | null 11} 12 13describe('Quoted String Extraction', () => { 14 describe('basic extraction', () => { 15 test('should extract basic quoted string', () => { 16 const parser = new TaggedStringParser() 17 const extract = ( 18 parser as unknown as ParserWithExtractQuotedString 19 ).extractQuotedString.bind(parser) 20 21 const result = extract('"hello world"', 0) 22 assert.notStrictEqual(result, null) 23 assert.strictEqual(result?.content, 'hello world') 24 assert.strictEqual(result?.endPosition, 13) 25 }) 26 27 test('should extract quoted string with spaces', () => { 28 const parser = new TaggedStringParser() 29 const extract = ( 30 parser as unknown as ParserWithExtractQuotedString 31 ).extractQuotedString.bind(parser) 32 33 const result = extract('"store order"', 0) 34 assert.notStrictEqual(result, null) 35 assert.strictEqual(result?.content, 'store order') 36 assert.strictEqual(result?.endPosition, 13) 37 }) 38 39 test('should extract quoted string with special characters', () => { 40 const parser = new TaggedStringParser() 41 const extract = ( 42 parser as unknown as ParserWithExtractQuotedString 43 ).extractQuotedString.bind(parser) 44 45 const result = extract('"hello:world=test"', 0) 46 assert.notStrictEqual(result, null) 47 assert.strictEqual(result?.content, 'hello:world=test') 48 assert.strictEqual(result?.endPosition, 18) 49 }) 50 51 test('should extract quoted string from middle of larger string', () => { 52 const parser = new TaggedStringParser() 53 const extract = ( 54 parser as unknown as ParserWithExtractQuotedString 55 ).extractQuotedString.bind(parser) 56 57 const result = extract('key="quoted value" rest', 4) 58 assert.notStrictEqual(result, null) 59 assert.strictEqual(result?.content, 'quoted value') 60 assert.strictEqual(result?.endPosition, 18) 61 }) 62 63 test('should handle empty quoted string', () => { 64 const parser = new TaggedStringParser() 65 const extract = ( 66 parser as unknown as ParserWithExtractQuotedString 67 ).extractQuotedString.bind(parser) 68 69 const result = extract('""', 0) 70 assert.notStrictEqual(result, null) 71 assert.strictEqual(result?.content, '') 72 assert.strictEqual(result?.endPosition, 2) 73 }) 74 }) 75 76 describe('escape sequences', () => { 77 test('should process escaped quote (\\") as literal quote', () => { 78 const parser = new TaggedStringParser() 79 const extract = ( 80 parser as unknown as ParserWithExtractQuotedString 81 ).extractQuotedString.bind(parser) 82 83 const result = extract('"say \\"hello\\""', 0) 84 assert.notStrictEqual(result, null) 85 assert.strictEqual(result?.content, 'say "hello"') 86 }) 87 88 test('should process escaped backslash (\\\\) as literal backslash', () => { 89 const parser = new TaggedStringParser() 90 const extract = ( 91 parser as unknown as ParserWithExtractQuotedString 92 ).extractQuotedString.bind(parser) 93 94 const result = extract('"path\\\\to\\\\file"', 0) 95 assert.notStrictEqual(result, null) 96 assert.strictEqual(result?.content, 'path\\to\\file') 97 }) 98 99 test('should process mixed escape sequences', () => { 100 const parser = new TaggedStringParser() 101 const extract = ( 102 parser as unknown as ParserWithExtractQuotedString 103 ).extractQuotedString.bind(parser) 104 105 const result = extract('"test\\\\\\"mixed\\""', 0) 106 assert.notStrictEqual(result, null) 107 assert.strictEqual(result?.content, 'test\\"mixed"') 108 }) 109 110 test('should handle backslash before non-escapable character', () => { 111 const parser = new TaggedStringParser() 112 const extract = ( 113 parser as unknown as ParserWithExtractQuotedString 114 ).extractQuotedString.bind(parser) 115 116 const result = extract('"test\\nvalue"', 0) 117 assert.notStrictEqual(result, null) 118 assert.strictEqual(result?.content, 'test\\nvalue') 119 }) 120 }) 121 122 describe('error cases', () => { 123 test('should return null for unclosed quote', () => { 124 const parser = new TaggedStringParser() 125 const extract = ( 126 parser as unknown as ParserWithExtractQuotedString 127 ).extractQuotedString.bind(parser) 128 129 const result = extract('"unclosed string', 0) 130 assert.strictEqual(result, null) 131 }) 132 133 test('should return null for unclosed quote at end of string', () => { 134 const parser = new TaggedStringParser() 135 const extract = ( 136 parser as unknown as ParserWithExtractQuotedString 137 ).extractQuotedString.bind(parser) 138 139 const result = extract('"no closing', 0) 140 assert.strictEqual(result, null) 141 }) 142 143 test('should handle backslash at end of quoted string', () => { 144 const parser = new TaggedStringParser() 145 const extract = ( 146 parser as unknown as ParserWithExtractQuotedString 147 ).extractQuotedString.bind(parser) 148 149 const result = extract('"ends with\\"', 0) 150 assert.strictEqual(result, null) 151 }) 152 153 test('should return null when not starting at a quote', () => { 154 const parser = new TaggedStringParser() 155 const extract = ( 156 parser as unknown as ParserWithExtractQuotedString 157 ).extractQuotedString.bind(parser) 158 159 const result = extract('not a quote', 0) 160 assert.strictEqual(result, null) 161 }) 162 }) 163 164 describe('quoted strings in delimited mode', () => { 165 test('should extract quoted key: ["linux server"=home]', () => { 166 const parser = new TaggedStringParser({ typeSeparator: '=' }) 167 const result = parser.parse('["linux server"=home]') 168 169 assert.strictEqual(result.entities.length, 1) 170 assert.strictEqual(result.entities[0].type, 'linux server') 171 assert.strictEqual(result.entities[0].value, 'home') 172 assert.strictEqual(result.entities[0].parsedValue, 'home') 173 }) 174 175 test('should extract quoted value: [server="web server"]', () => { 176 const parser = new TaggedStringParser({ typeSeparator: '=' }) 177 const result = parser.parse('[server="web server"]') 178 179 assert.strictEqual(result.entities.length, 1) 180 assert.strictEqual(result.entities[0].type, 'server') 181 assert.strictEqual(result.entities[0].value, 'web server') 182 assert.strictEqual(result.entities[0].parsedValue, 'web server') 183 }) 184 185 test('should extract both quoted key and quoted value', () => { 186 const parser = new TaggedStringParser({ typeSeparator: '=' }) 187 const result = parser.parse('["linux server"="web server"]') 188 189 assert.strictEqual(result.entities.length, 1) 190 assert.strictEqual(result.entities[0].type, 'linux server') 191 assert.strictEqual(result.entities[0].value, 'web server') 192 assert.strictEqual(result.entities[0].parsedValue, 'web server') 193 }) 194 195 test('should handle escape sequences in quoted key: ["key\\"name"=value]', () => { 196 const parser = new TaggedStringParser({ typeSeparator: '=' }) 197 const result = parser.parse('["key\\"name"=value]') 198 199 assert.strictEqual(result.entities.length, 1) 200 assert.strictEqual(result.entities[0].type, 'key"name') 201 assert.strictEqual(result.entities[0].value, 'value') 202 }) 203 204 test('should handle escape sequences in quoted value: [key="say \\"hello\\""]', () => { 205 const parser = new TaggedStringParser({ typeSeparator: '=' }) 206 const result = parser.parse('[key="say \\"hello\\""]') 207 208 assert.strictEqual(result.entities.length, 1) 209 assert.strictEqual(result.entities[0].type, 'key') 210 assert.strictEqual(result.entities[0].value, 'say "hello"') 211 }) 212 213 test('should handle backslash escape sequences: [path="C:\\\\Users\\\\file"]', () => { 214 const parser = new TaggedStringParser({ typeSeparator: '=' }) 215 const result = parser.parse('[path="C:\\\\Users\\\\file"]') 216 217 assert.strictEqual(result.entities.length, 1) 218 assert.strictEqual(result.entities[0].type, 'path') 219 assert.strictEqual(result.entities[0].value, 'C:\\Users\\file') 220 }) 221 222 test('should handle mixed escape sequences in delimited mode', () => { 223 const parser = new TaggedStringParser({ typeSeparator: '=' }) 224 const result = parser.parse('[msg="test\\\\\\"mixed\\""]') 225 226 assert.strictEqual(result.entities.length, 1) 227 assert.strictEqual(result.entities[0].type, 'msg') 228 assert.strictEqual(result.entities[0].value, 'test\\"mixed"') 229 }) 230 231 test('should skip malformed tag with unclosed quoted key', () => { 232 const parser = new TaggedStringParser({ typeSeparator: '=' }) 233 const result = parser.parse('["unclosed key=value] [valid=123]') 234 235 assert.strictEqual(result.entities.length, 1) 236 assert.strictEqual(result.entities[0].type, 'valid') 237 assert.strictEqual(result.entities[0].value, '123') 238 }) 239 240 test('should skip malformed tag with unclosed quoted value', () => { 241 const parser = new TaggedStringParser({ typeSeparator: '=' }) 242 const result = parser.parse('[key="unclosed value] [valid=123]') 243 244 assert.strictEqual(result.entities.length, 1) 245 assert.strictEqual(result.entities[0].type, 'valid') 246 assert.strictEqual(result.entities[0].value, '123') 247 }) 248 249 test('should handle quoted keys with spaces and special characters', () => { 250 const parser = new TaggedStringParser({ typeSeparator: ':' }) 251 const result = parser.parse('["store order":"number 42"]') 252 253 assert.strictEqual(result.entities.length, 1) 254 assert.strictEqual(result.entities[0].type, 'store order') 255 assert.strictEqual(result.entities[0].value, 'number 42') 256 }) 257 258 test('should handle quoted values with separator character', () => { 259 const parser = new TaggedStringParser({ typeSeparator: '=' }) 260 const result = parser.parse('[formula="a=b+c"]') 261 262 assert.strictEqual(result.entities.length, 1) 263 assert.strictEqual(result.entities[0].type, 'formula') 264 assert.strictEqual(result.entities[0].value, 'a=b+c') 265 }) 266 267 test('should work with custom delimiters and quoted strings', () => { 268 const parser = new TaggedStringParser({ 269 delimiters: ['{{', '}}'], 270 typeSeparator: '=', 271 }) 272 const result = parser.parse('{{"linux server"="web server"}}') 273 274 assert.strictEqual(result.entities.length, 1) 275 assert.strictEqual(result.entities[0].type, 'linux server') 276 assert.strictEqual(result.entities[0].value, 'web server') 277 }) 278 279 test('should handle multiple entities with quoted strings', () => { 280 const parser = new TaggedStringParser({ typeSeparator: '=' }) 281 const result = parser.parse( 282 '["server name"="web server"] [count=5] ["status"="active"]', 283 ) 284 285 assert.strictEqual(result.entities.length, 3) 286 assert.strictEqual(result.entities[0].type, 'server name') 287 assert.strictEqual(result.entities[0].value, 'web server') 288 assert.strictEqual(result.entities[1].type, 'count') 289 assert.strictEqual(result.entities[1].value, '5') 290 assert.strictEqual(result.entities[2].type, 'status') 291 assert.strictEqual(result.entities[2].value, 'active') 292 }) 293 }) 294})