1// Copyright (c) Jupyter Development Team. 2// Distributed under the terms of the Modified BSD License. 3 4import { 5 patch, patchStringified 6} from '../../../src/patch'; 7 8import { 9 IDiffEntry, IDiffAdd, IDiffRemove, IDiffReplace, 10 IDiffPatch, IDiffAddRange, IDiffRemoveRange 11} from '../../../src/diff/diffentries'; 12 13import { 14 JSON_INDENT 15} from '../../../src/diff/util'; 16import { JSONObject, JSONValue } from '@lumino/coreutils'; 17 18 19function makeAddRange(key: number, values: string | any[]) : IDiffAddRange { 20 return {key: key, op: 'addrange', valuelist: values}; 21} 22 23function makeRemoveRange(key: number, length: number) : IDiffRemoveRange { 24 return {key: key, op: 'removerange', length: length}; 25} 26 27function makeAdd(key: string, value: any) : IDiffAdd { 28 return {key: key, op: 'add', value: value}; 29} 30 31function makeRemove(key: string) : IDiffRemove { 32 return {key: key, op: 'remove'}; 33} 34 35function makeReplace(key: string, value: any) : IDiffReplace { 36 return {key: key, op: 'replace', value: value}; 37} 38 39function makePatch(key: number | string, diff: IDiffEntry[] | null) : IDiffPatch { 40 return {key: key, op: 'patch', diff: diff}; 41} 42 43 44describe('patch', () => { 45 46 describe('patchStringified', () => { 47 48 it('should patch a simple string addition', () => { 49 let base = 'abcdef'; 50 let diff = makePatch(0, [makeAddRange(3, 'ghi')]); 51 let value = patchStringified(base, [diff]); 52 expect(value.remote).toBe('abcghidef'); 53 expect(value.additions).toEqual([{from: 3, to: 6, source: undefined}]); 54 expect(value.deletions).toHaveLength(0); 55 }); 56 57 it('should patch a simple string deletion', () => { 58 let base = 'abcdef'; 59 let diff = makePatch(0, [makeRemoveRange(2, 2)]); 60 let value = patchStringified(base, [diff]); 61 expect(value.remote).toBe('abef'); 62 expect(value.additions).toHaveLength(0); 63 expect(value.deletions).toEqual([{from: 2, to: 4, source: undefined}]); 64 }); 65 66 it('should patch a string with null diff', () => { 67 let base = 'abcdef'; 68 let diff = null; 69 let value = patchStringified(base, diff); 70 expect(value.remote).toBe('abcdef'); 71 expect(value.additions).toHaveLength(0); 72 expect(value.deletions).toHaveLength(0); 73 }); 74 75 it('should patch a nested string with null diff', () => { 76 let base = {a: 'abcdef'}; 77 let diff = [makePatch('a', null)]; 78 let value = patchStringified(base, diff); 79 expect(value.remote).toBe( 80 '{\n' + 81 JSON_INDENT + '\"a\": \"abcdef\"\n' + 82 '}' 83 ); 84 expect(value.additions).toHaveLength(0); 85 expect(value.deletions).toHaveLength(0); 86 }); 87 88 it('should patch a simple string with simple escapes', () => { 89 let base = 'a \"string\" with\nsome\tescapable characters'; 90 let diff = [ 91 makePatch(1, [ 92 makeAddRange('some'.length, '\n'), 93 makeRemoveRange('some'.length, '\tescapable characters'.length) 94 ]), 95 makeAddRange(2, ['\tadded escapable characters']), 96 ]; 97 // Here, level is passed as > 0, which indicates that JSON stringification should be used 98 let value = patchStringified(base, diff, 1); 99 expect(value.remote).toBe( 100 JSON_INDENT + '\"a \\\"string\\\" with\\nsome\\n\\tadded escapable characters\"' 101 ); 102 }); 103 104 it('should patch a list addition', () => { 105 let base = [1, 2, 3]; 106 let diff = makeAddRange(2, [-1, -2]); 107 let value = patchStringified(base, [diff]); 108 expect(value.remote).toBe( 109 '[\n' + 110 JSON_INDENT + '1,\n' + 111 JSON_INDENT + '2,\n' + 112 JSON_INDENT + '-1,\n' + 113 JSON_INDENT + '-2,\n' + 114 JSON_INDENT + '3\n' + 115 ']' 116 ); 117 let f = '[\n1,\n2,\n'.length + JSON_INDENT.length * 2; 118 let t = f + '-1,\n-2,\n'.length + JSON_INDENT.length * 2; 119 expect(value.additions).toEqual([{from: f, to: t, source: undefined}]); 120 expect(value.deletions).toHaveLength(0); 121 }); 122 123 it('should patch a list addition at start', () => { 124 let base = [1, 2, 3]; 125 let diff = makeAddRange(0, [-1, -2]); 126 let value = patchStringified(base, [diff]); 127 expect(value.remote).toBe( 128 '[\n' + 129 JSON_INDENT + '-1,\n' + 130 JSON_INDENT + '-2,\n' + 131 JSON_INDENT + '1,\n' + 132 JSON_INDENT + '2,\n' + 133 JSON_INDENT + '3\n' + 134 ']' 135 ); 136 let f = '[\n'.length; 137 let t = f + '-1,\n-2,\n'.length + JSON_INDENT.length * 2; 138 expect(value.additions).toEqual([{from: f, to: t, source: undefined}]); 139 expect(value.deletions).toHaveLength(0); 140 }); 141 142 it('should patch a list addition at end', () => { 143 let base = [1, 2, 3]; 144 let diff = makeAddRange(3, [-1, -2]); 145 let value = patchStringified(base, [diff]); 146 expect(value.remote).toBe( 147 '[\n' + 148 JSON_INDENT + '1,\n' + 149 JSON_INDENT + '2,\n' + 150 JSON_INDENT + '3,\n' + 151 JSON_INDENT + '-1,\n' + 152 JSON_INDENT + '-2\n' + 153 ']' 154 ); 155 let f = '[\n1,\n2,\n3,\n'.length + JSON_INDENT.length * 3; 156 let t = f + '-1,\n-2\n'.length + JSON_INDENT.length * 2; 157 expect(value.additions).toEqual([{from: f, to: t, source: undefined}]); 158 expect(value.deletions).toHaveLength(0); 159 }); 160 161 it('should patch a list deletion', () => { 162 let base = [1, 2, 3, 4, 5]; 163 let diff = makeRemoveRange(2, 2); 164 let value = patchStringified(base, [diff]); 165 expect(value.remote).toBe( 166 '[\n' + 167 JSON_INDENT + '1,\n' + 168 JSON_INDENT + '2,\n' + 169 JSON_INDENT + '5\n' + 170 ']' 171 ); 172 let f = '[\n1,\n2,\n'.length + JSON_INDENT.length * 2; 173 let t = f + '3,\n4,\n'.length + JSON_INDENT.length * 2; 174 expect(value.additions).toHaveLength(0); 175 expect(value.deletions).toEqual([{from: f, to: t, source: undefined}]); 176 }); 177 178 it('should patch a list deletion at start', () => { 179 let base = [1, 2, 3, 4, 5]; 180 let diff = makeRemoveRange(0, 2); 181 let value = patchStringified(base, [diff]); 182 expect(value.remote).toBe( 183 '[\n' + 184 JSON_INDENT + '3,\n' + 185 JSON_INDENT + '4,\n' + 186 JSON_INDENT + '5\n' + 187 ']' 188 ); 189 let f = '[\n'.length; 190 let t = f + '1,\n2,\n'.length + JSON_INDENT.length * 2; 191 expect(value.additions).toHaveLength(0); 192 expect(value.deletions).toEqual([{from: f, to: t, source: undefined}]); 193 }); 194 195 it('should patch a list deletion at end', () => { 196 let base = [1, 2, 3, 4, 5]; 197 let diff = makeRemoveRange(3, 2); 198 let value = patchStringified(base, [diff]); 199 expect(value.remote).toBe( 200 '[\n' + 201 JSON_INDENT + '1,\n' + 202 JSON_INDENT + '2,\n' + 203 JSON_INDENT + '3\n' + 204 ']' 205 ); 206 let f = '[\n1,\n2,\n3\n,'.length + JSON_INDENT.length * 3; 207 let t = f + '4,\n5\n'.length + JSON_INDENT.length * 2; 208 expect(value.additions).toHaveLength(0); 209 expect(value.deletions).toEqual([{from: f, to: t, source: undefined}]); 210 }); 211 212 it('should patch a list with null diff', () => { 213 let base = [1, 2, 3]; 214 let diff = null; 215 let value = patchStringified(base, diff); 216 expect(value.remote).toBe( 217 '[\n' + 218 JSON_INDENT + '1,\n' + 219 JSON_INDENT + '2,\n' + 220 JSON_INDENT + '3\n' + 221 ']' 222 ); 223 expect(value.additions).toHaveLength(0); 224 expect(value.deletions).toHaveLength(0); 225 }); 226 227 it('should patch an object addition', () => { 228 let base = {a: 1, d: 'test', c: true}; 229 let diff = makeAdd('b', 42); 230 let value = patchStringified(base, [diff]); 231 expect(value.remote).toBe( 232 '{\n' + 233 JSON_INDENT + '\"a\": 1,\n' + 234 JSON_INDENT + '\"b\": 42,\n' + 235 JSON_INDENT + '\"c\": true,\n' + 236 JSON_INDENT + '\"d\": \"test\"\n' + 237 '}' 238 ); 239 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 240 let t = f + '\"b\": 42,\n'.length + JSON_INDENT.length; 241 expect(value.additions).toEqual([{from: f, to: t, source: undefined}]); 242 expect(value.deletions).toHaveLength(0); 243 }); 244 245 it('should patch an object addition at start', () => { 246 let base = {b: 1, d: 'test', c: true}; 247 let diff = makeAdd('a', 42); 248 let value = patchStringified(base, [diff]); 249 expect(value.remote).toBe( 250 '{\n' + 251 JSON_INDENT + '\"a\": 42,\n' + 252 JSON_INDENT + '\"b\": 1,\n' + 253 JSON_INDENT + '\"c\": true,\n' + 254 JSON_INDENT + '\"d\": \"test\"\n' + 255 '}' 256 ); 257 let f = '{\n'.length; 258 let t = f + '\"a\": 42,\n'.length + JSON_INDENT.length; 259 expect(value.additions).toEqual([{from: f, to: t, source: undefined}]); 260 expect(value.deletions).toHaveLength(0); 261 }); 262 263 it('should patch an object addition at end', () => { 264 let base = {a: 1, b: 'test', c: true}; 265 let diff = makeAdd('d', 42); 266 let value = patchStringified(base, [diff]); 267 expect(value.remote).toBe( 268 '{\n' + 269 JSON_INDENT + '\"a\": 1,\n' + 270 JSON_INDENT + '\"b\": \"test\",\n' + 271 JSON_INDENT + '\"c\": true,\n' + 272 JSON_INDENT + '\"d\": 42\n' + 273 '}' 274 ); 275 let f = '{\n\"a\": 1,\n\"b\": \"test\",\n\"c\": true,\n'.length + 276 JSON_INDENT.length * 3; 277 let t = f + '\"d\": 42\n'.length + JSON_INDENT.length; 278 expect(value.additions).toEqual([{from: f, to: t, source: undefined}]); 279 expect(value.deletions).toHaveLength(0); 280 }); 281 282 it('should patch an object removal', () => { 283 let base = {a: 1, d: 'test', c: true}; 284 let diff = makeRemove('c'); 285 let value = patchStringified(base, [diff]); 286 expect(value.remote).toBe( 287 '{\n' + 288 JSON_INDENT + '\"a\": 1,\n' + 289 JSON_INDENT + '\"d\": \"test\"\n' + 290 '}' 291 ); 292 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 293 let t = f + '\"c\": true,\n'.length + JSON_INDENT.length; 294 expect(value.additions).toHaveLength(0); 295 expect(value.deletions).toEqual([{from: f, to: t, source: undefined}]); 296 }); 297 298 it('should patch an object removal at start', () => { 299 let base = {a: 1, d: 'test', c: true}; 300 let diff = makeRemove('a'); 301 let value = patchStringified(base, [diff]); 302 expect(value.remote).toBe( 303 '{\n' + 304 JSON_INDENT + '\"c\": true,\n' + 305 JSON_INDENT + '\"d\": \"test\"\n' + 306 '}' 307 ); 308 let f = '{\n'.length; 309 let t = f + '\"a\": 1,\n'.length + JSON_INDENT.length; 310 expect(value.additions).toHaveLength(0); 311 expect(value.deletions).toEqual([{from: f, to: t, source: undefined}]); 312 }); 313 314 it('should patch an object removal at end', () => { 315 let base = {a: 1, d: 'test', c: true}; 316 let diff = makeRemove('d'); 317 let value = patchStringified(base, [diff]); 318 expect(value.remote).toBe( 319 '{\n' + 320 JSON_INDENT + '\"a\": 1,\n' + 321 JSON_INDENT + '\"c\": true\n' + 322 '}' 323 ); 324 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 325 f += '\"c\": true,\n'.length + JSON_INDENT.length; 326 let t = f + '\"d\": \"test\"\n'.length + JSON_INDENT.length; 327 expect(value.additions).toHaveLength(0); 328 expect(value.deletions).toEqual([{from: f, to: t, source: undefined}]); 329 }); 330 331 it('should patch an object replacement', () => { 332 let base = {a: 1, d: 'test', c: true}; 333 let diff = makeReplace('c', false); 334 let value = patchStringified(base, [diff]); 335 expect(value.remote).toBe( 336 '{\n' + 337 JSON_INDENT + '\"a\": 1,\n' + 338 JSON_INDENT + '\"c\": false,\n' + 339 JSON_INDENT + '\"d\": \"test\"\n' + 340 '}' 341 ); 342 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 343 f += '\"c\": '.length + JSON_INDENT.length; 344 let tAdd = f + 'false'.length; 345 let tDel = f + 'true'.length; 346 expect(value.additions).toEqual([{from: f, to: tAdd, source: undefined}]); 347 expect(value.deletions).toEqual([{from: f, to: tDel, source: undefined}]); 348 }); 349 350 it('should patch an object replacement at start', () => { 351 let base = {a: 1, d: 'test', c: true}; 352 let diff = makeReplace('a', 1234); 353 let value = patchStringified(base, [diff]); 354 expect(value.remote).toBe( 355 '{\n' + 356 JSON_INDENT + '\"a\": 1234,\n' + 357 JSON_INDENT + '\"c\": true,\n' + 358 JSON_INDENT + '\"d\": \"test\"\n' + 359 '}' 360 ); 361 let f = '{\n\"a\": '.length + JSON_INDENT.length; 362 let tAdd = f + '1234'.length; 363 let tDel = f + '1'.length; 364 expect(value.additions).toEqual([{from: f, to: tAdd, source: undefined}]); 365 expect(value.deletions).toEqual([{from: f, to: tDel, source: undefined}]); 366 }); 367 368 it('should patch an object replacement at end', () => { 369 let base = {a: 1, d: 'test', c: true}; 370 let diff = makeReplace('d', 'foobar'); 371 let value = patchStringified(base, [diff]); 372 expect(value.remote).toBe( 373 '{\n' + 374 JSON_INDENT + '\"a\": 1,\n' + 375 JSON_INDENT + '\"c\": true,\n' + 376 JSON_INDENT + '\"d\": \"foobar\"\n' + 377 '}' 378 ); 379 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 380 f += '\"c\": true,\n'.length + JSON_INDENT.length; 381 f += '\"d\": '.length + JSON_INDENT.length; 382 let tAdd = f + '\"foobar\"'.length; 383 let tDel = f + '\"test\"'.length; 384 expect(value.additions).toEqual([{from: f, to: tAdd, source: undefined}]); 385 expect(value.deletions).toEqual([{from: f, to: tDel, source: undefined}]); 386 }); 387 388 it('should patch an object replacement with changing type', () => { 389 let base = {a: 1, d: 'test', c: true}; 390 let diff = makeReplace('c', ['foo', 'bar']); 391 let value = patchStringified(base, [diff]); 392 expect(value.remote).toBe( 393 '{\n' + 394 JSON_INDENT + '\"a\": 1,\n' + 395 JSON_INDENT + '\"c\": [\n' + 396 JSON_INDENT + JSON_INDENT + '\"foo\",\n' + 397 JSON_INDENT + JSON_INDENT + '\"bar\"\n' + 398 JSON_INDENT + '],\n' + 399 JSON_INDENT + '\"d\": \"test\"\n' + 400 '}' 401 ); 402 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 403 f += '\"c\": '.length + JSON_INDENT.length; 404 let tAdd = f + '[\n\"foo\",\n\"bar\"\n]'.length + 5 * JSON_INDENT.length; 405 let tDel = f + 'true'.length; 406 expect(value.additions).toEqual([{from: f, to: tAdd, source: undefined}]); 407 expect(value.deletions).toEqual([{from: f, to: tDel, source: undefined}]); 408 }); 409 410 it('should patch an object with combined addition and removal at end', () => { 411 let base = {a: 1, d: 'test', b: true}; 412 // For this diff, a naive stringifier might get confused 413 // whether there should be a comma at the end of 'c' entry. 414 let diff = [makeAdd('c', 42), makeRemove('d')]; 415 let value = patchStringified(base, diff); 416 expect(value.remote).toBe( 417 '{\n' + 418 JSON_INDENT + '\"a\": 1,\n' + 419 JSON_INDENT + '\"b\": true,\n' + 420 JSON_INDENT + '\"c\": 42\n' + 421 '}' 422 ); 423 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 424 f += '\"b\": true,\n'.length + JSON_INDENT.length; 425 let tAdd = f + '\"c\": 42\n'.length + JSON_INDENT.length; 426 let tDel = f + '\"d\": \"test\"\n'.length + JSON_INDENT.length; 427 expect(value.additions).toEqual([{from: f, to: tAdd, source: undefined}]); 428 expect(value.deletions).toEqual([{from: f, to: tDel, source: undefined}]); 429 }); 430 431 it('should patch an object with combined addition and patch at end', () => { 432 let base = {a: 1, d: 'test', b: true}; 433 // For this diff, a naive stringifier might get confused 434 // whether there should be a comma at the end of 'c' entry. 435 let diff = [makeAdd('c', 42), makePatch('d', [makePatch(0, [makeAddRange(0, 'a ')])])]; 436 let value = patchStringified(base, diff); 437 expect(value.remote).toBe( 438 '{\n' + 439 JSON_INDENT + '\"a\": 1,\n' + 440 JSON_INDENT + '\"b\": true,\n' + 441 JSON_INDENT + '\"c\": 42,\n' + 442 JSON_INDENT + '\"d\": \"a test\"\n' + 443 '}' 444 ); 445 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 446 f += '\"b\": true,\n'.length + JSON_INDENT.length; 447 let tAdd = f + '\"c\": 42,\n'.length + JSON_INDENT.length; 448 expect(value.additions[0]).toEqual({from: f, to: tAdd, source: undefined}); 449 }); 450 451 it('should patch an object with combined removal and addition at end', () => { 452 let base = {a: 1, c: 'test', b: true}; 453 // For this diff, a naive stringifier might get confused 454 // whether there should be a comma at the end of 'c' entry. 455 let diff = [makeRemove('b'), makePatch('c', [makePatch(0, [makeAddRange(0, 'a ')])])]; 456 let value = patchStringified(base, diff); 457 expect(value.remote).toBe( 458 '{\n' + 459 JSON_INDENT + '\"a\": 1,\n' + 460 JSON_INDENT + '\"c\": \"a test\"\n' + 461 '}' 462 ); 463 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 464 let tDel = f + '\"b\": true,\n'.length + JSON_INDENT.length; 465 expect(value.deletions[0]).toEqual({from: f, to: tDel, source: undefined}); 466 }); 467 468 it('should patch an object with combined removal and patch at end', () => { 469 let base = {a: 1, c: 'test', b: true}; 470 // For this diff, a naive stringifier might get confused 471 // whether there should be a comma at the end of 'c' entry. 472 let diff = [makeAdd('d', 42), makeRemove('c')]; 473 let value = patchStringified(base, diff); 474 expect(value.remote).toBe( 475 '{\n' + 476 JSON_INDENT + '\"a\": 1,\n' + 477 JSON_INDENT + '\"b\": true,\n' + 478 JSON_INDENT + '\"d\": 42\n' + 479 '}' 480 ); 481 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 482 f += '\"b\": true,\n'.length + JSON_INDENT.length; 483 let tAdd = f + '\"d\": 42\n'.length + JSON_INDENT.length; 484 let tDel = f + '\"c\": \"test\"\n'.length + JSON_INDENT.length; 485 expect(value.additions).toEqual([{from: f, to: tAdd, source: undefined}]); 486 expect(value.deletions).toEqual([{from: f, to: tDel, source: undefined}]); 487 }); 488 489 it('should patch an object with double addition at end', () => { 490 let base = {a: 1, b: true}; 491 // For this diff, a naive stringifier might get confused 492 // whether there should be a comma at the end of 'c' entry. 493 let diff = [makeAdd('c', 42), makeAdd('d', 'test')]; 494 let value = patchStringified(base, diff); 495 expect(value.remote).toBe( 496 '{\n' + 497 JSON_INDENT + '\"a\": 1,\n' + 498 JSON_INDENT + '\"b\": true,\n' + 499 JSON_INDENT + '\"c\": 42,\n' + 500 JSON_INDENT + '\"d\": \"test\"\n' + 501 '}' 502 ); 503 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 504 f += '\"b\": true,\n'.length + JSON_INDENT.length; 505 let tAdd1 = f + '\"c\": 42,\n'.length + JSON_INDENT.length; 506 let tAdd2 = tAdd1 + '\"d\": \"test\"\n'.length + JSON_INDENT.length; 507 expect(value.additions[0]).toEqual({from: f, to: tAdd1, source: undefined}); 508 expect(value.additions[1]).toEqual({from: tAdd1, to: tAdd2, source: undefined}); 509 }); 510 511 it('should patch an object with double removal at end', () => { 512 let base = {a: 1, b: true, c: 42, d: 'test'}; 513 // For this diff, a naive stringifier might get confused 514 // whether there should be a comma at the end of 'c' entry. 515 let diff = [makeRemove('c'), makeRemove('d')]; 516 let value = patchStringified(base, diff); 517 expect(value.remote).toBe( 518 '{\n' + 519 JSON_INDENT + '\"a\": 1,\n' + 520 JSON_INDENT + '\"b\": true\n' + 521 '}' 522 ); 523 let f = '{\n\"a\": 1,\n'.length + JSON_INDENT.length; 524 f += '\"b\": true,\n'.length + JSON_INDENT.length; 525 let tDel1 = f + '\"c\": 42,\n'.length + JSON_INDENT.length; 526 let tDel2 = tDel1 + '\"d\": \"test\"\n'.length + JSON_INDENT.length; 527 expect(value.deletions[0]).toEqual({from: f, to: tDel1, source: undefined}); 528 expect(value.deletions[1]).toEqual({from: tDel1, to: tDel2, source: undefined}); 529 }); 530 531 it('should patch an object with null diff', () => { 532 let base = {a: 1, d: 'test', c: true}; 533 let diff = null; 534 let value = patchStringified(base, diff); 535 expect(value.remote).toBe( 536 '{\n' + 537 JSON_INDENT + '\"a\": 1,\n' + 538 JSON_INDENT + '\"c\": true,\n' + 539 JSON_INDENT + '\"d\": \"test\"\n' + 540 '}' 541 ); 542 expect(value.additions).toHaveLength(0); 543 expect(value.deletions).toHaveLength(0); 544 }); 545 546 it('should patch a nested patch', () => { 547 let base: JSONValue = [ 548 {a: 1, c: true}, 549 {b: 42, c: 'this\nis\na\nvalid\nstring'} 550 ]; 551 let diff = makePatch(1, [ 552 makePatch('c', [ 553 makePatch(3, [ 554 makeAddRange(0, 'patched'), 555 makeRemoveRange(0, 'valid'.length) 556 ])])]); 557 let value = patchStringified(base, [diff]); 558 expect(value.remote).toBe( 559 '[\n' + 560 JSON_INDENT + '{\n' + 561 JSON_INDENT + JSON_INDENT + '\"a\": 1,\n' + 562 JSON_INDENT + JSON_INDENT + '\"c\": true\n' + 563 JSON_INDENT + '},\n' + 564 JSON_INDENT + '{\n' + 565 JSON_INDENT + JSON_INDENT + '\"b\": 42,\n' + 566 JSON_INDENT + JSON_INDENT + '\"c\": ' + 567 '\"this\\nis\\na\\npatched\\nstring\"\n' + 568 JSON_INDENT + '}\n' + 569 ']' 570 ); 571 let f = ( 572 '[\n{\n\"a\": 1,\n' + 573 '\"c\": true\n},\n' + 574 '{\n\"b\": 42,\n' + 575 '\"c\": \"this\\nis\\na\\n' 576 ).length + JSON_INDENT.length * 11; 577 let t = f + 'patched'.length; 578 console.log(value.remote.slice(value.additions[0].from, value.additions[0].to)); 579 expect(value.additions).toEqual([{from: f, to: t, source: undefined}]); 580 t = f + 'valid'.length; 581 expect(value.deletions).toEqual([{from: f, to: t, source: undefined}]); 582 }); 583 584 it('should fail to patch atomic types', () => { 585 let diff = makeReplace('toString', () => {/* */}); 586 587 // Number 588 let base: any = 5; 589 expect(() => {patchStringified(base, diff as any)}).toThrow( 590 /Cannot patch an atomic type: / 591 ); 592 593 // Boolean 594 base = true; 595 expect(() => {patchStringified(base, diff as any)}).toThrow( 596 /Cannot patch an atomic type: / 597 ); 598 }); 599 600 }); 601 602 describe('patch', () => { 603 604 describe('patch object', () => { 605 606 it('should patch an object addition', () => { 607 let base = {a: 55, b: 43}; 608 let diff = [makeAdd('c', 22)]; 609 let expected = {a: 55, b: 43, c: 22}; 610 let value = patch(base, diff); 611 expect(value).toEqual(expected); 612 }); 613 614 it('should patch an object removal', () => { 615 let base = {a: 55, b: 43}; 616 let diff = [makeRemove('b')]; 617 let expected = {a: 55}; 618 let value = patch(base, diff); 619 expect(value).toEqual(expected); 620 }); 621 622 it('should patch an object replace', () => { 623 let base = {a: 55, b: 43}; 624 let diff = [makeReplace('b', 22)]; 625 let expected = {a: 55, b: 22}; 626 let value = patch(base, diff); 627 expect(value).toEqual(expected); 628 }); 629 630 it('should patch an object list-patch', () => { 631 let base = {a: 55, b: [43]}; 632 let diff = [makePatch('b', [makeAddRange(0, [22])])]; 633 let expected = {a: 55, b: [22, 43]}; 634 let value = patch(base, diff); 635 expect(value).toEqual(expected); 636 }); 637 638 it('should patch an object object-patch', () => { 639 let base = {a: 55, b: {c : 43}}; 640 let diff = [makePatch('b', [makeReplace('c', 22)])]; 641 let expected = {a: 55, b: {c: 22}}; 642 let value = patch(base, diff); 643 expect(value).toEqual(expected); 644 }); 645 646 it('should patch an object with a null diff', () => { 647 let base = {a: 55, b: 43}; 648 let diff = null; 649 let patched = patch(base, diff); 650 expect(patched).toEqual(base); 651 // Should return a copy 652 expect(patched).not.toBe(base); 653 }); 654 655 it('should fail to patch an object with a non-string key', () => { 656 let base = {a: 55, b: 43}; 657 let diff = [makeRemove(32 as any)]; 658 expect(() => {patch(base, diff)}).toThrow( 659 /Invalid patch object op: Key is not a string: 32/); 660 }); 661 662 it('should fail to patch an object with an add on existing key', () => { 663 let base = {a: 55, b: 43}; 664 let diff = [makeAdd('a', 22)]; 665 expect(() => {patch(base, diff)}).toThrow( 666 /Invalid add key diff op: Key already present: a/); 667 }); 668 669 it('should fail to patch an object with a remove on invalid key', () => { 670 let base = {a: 55, b: 43}; 671 let diff = [makeRemove('c')]; 672 expect(() => {patch(base, diff)}).toThrow( 673 /Invalid remove key diff op: Missing key: c/); 674 }); 675 676 it('should fail to patch an object with a replace on invalid key', () => { 677 let base = {a: 55, b: 43}; 678 let diff = [makeReplace('c', 22)]; 679 expect(() => {patch(base, diff)}).toThrow( 680 /Invalid replace key diff op: Missing key: c/); 681 }); 682 683 it('should fail to patch an object with a patch of an atomic value', () => { 684 let base = {a: 55, b: 43}; 685 let diff = [makePatch('b', [makeAdd('b', 22)])]; 686 expect(() => {patch(base, diff)}).toThrow( 687 /Cannot patch an atomic type: number/); 688 }); 689 690 it('should fail to patch an object with a patch of an invalid key', () => { 691 let base = {a: 55, b: 43}; 692 let diff = [makePatch('c', [makeReplace('b', 22)])]; 693 expect(() => {patch(base, diff)}).toThrow( 694 /Invalid patch key diff op: Missing key: c/); 695 }); 696 697 it('should fail to patch an object with an invalid diff op', () => { 698 let base = {a: 55, b: 43}; 699 let diff = [{op: 'typo', value: 22, key: 'c'}]; 700 expect(() => {patch(base, diff as any)}).toThrow(/Invalid op: typo/); 701 }); 702 703 }); 704 705 describe('patch sequence', () => { 706 707 describe('patch sequence addition', () => { 708 709 it('should patch a sequence addition at start', () => { 710 let base = [55, 43]; 711 let diff = [makeAddRange(0, [22, 33])]; 712 let expected = [22, 33, 55, 43]; 713 let value = patch(base, diff); 714 expect(value).toEqual(expected); 715 }); 716 717 it('should patch a sequence addition in middle', () => { 718 let base = [55, 43]; 719 let diff = [makeAddRange(1, [22, 33])]; 720 let expected = [55, 22, 33, 43]; 721 let value = patch(base, diff); 722 expect(value).toEqual(expected); 723 }); 724 725 it('should patch a sequence addition at end', () => { 726 let base = [55, 43]; 727 let diff = [makeAddRange(2, [22, 33])]; 728 let expected = [55, 43, 22, 33]; 729 let value = patch(base, diff); 730 expect(value).toEqual(expected); 731 }); 732 }); 733 734 describe('patch sequence removal', () => { 735 736 it('should patch a sequence removal at start', () => { 737 let base = [55, 43, 22]; 738 let diff = [makeRemoveRange(0, 2)]; 739 let expected = [22]; 740 let value = patch(base, diff); 741 expect(value).toEqual(expected); 742 }); 743 744 it('should patch a sequence removal in middle', () => { 745 let base = [55, 43, 22, 32]; 746 let diff = [makeRemoveRange(1, 2)]; 747 let expected = [55, 32]; 748 let value = patch(base, diff); 749 expect(value).toEqual(expected); 750 }); 751 752 it('should patch a sequence removal at end', () => { 753 let base = [55, 43, 22, 32]; 754 let diff = [makeRemoveRange(2, 2)]; 755 let expected = [55, 43]; 756 let value = patch(base, diff); 757 expect(value).toEqual(expected); 758 759 diff = [makeRemoveRange(3, 1)]; 760 expected = [55, 43, 22]; 761 value = patch(base, diff); 762 expect(value).toEqual(expected); 763 }); 764 765 }); 766 767 describe('patch sequence list-patch', () => { 768 769 it('should patch a sequence list-patch at start', () => { 770 let base = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; 771 let diff = [makePatch(0, [makeAddRange(0, [22])])]; 772 let expected = [[22, 1, 2, 3], [4, 5, 6], [7, 8, 9]]; 773 let value = patch(base, diff); 774 expect(value).toEqual(expected); 775 }); 776 777 it('should patch a sequence list-patch in middle', () => { 778 let base = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; 779 let diff = [makePatch(1, [makeAddRange(0, [22])])]; 780 let expected = [[1, 2, 3], [22, 4, 5, 6], [7, 8, 9]]; 781 let value = patch(base, diff); 782 expect(value).toEqual(expected); 783 }); 784 785 it('should patch a sequence list-patch at end', () => { 786 let base = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]; 787 let diff = [makePatch(2, [makeAddRange(0, [22])])]; 788 let expected = [[1, 2, 3], [4, 5, 6], [22, 7, 8, 9]]; 789 let value = patch(base, diff); 790 expect(value).toEqual(expected); 791 }); 792 793 }); 794 795 describe('patch sequence object-patch', () => { 796 797 it('should patch a sequence object-patch at start', () => { 798 let base = [{a: 32, '15': 33}, {a: 32, '15': 33}, {a: 32, '15': 33}]; 799 let diff = [makePatch(0, [makeReplace('15', 22)])]; 800 let expected = [{a: 32, '15': 22}, {a: 32, '15': 33}, {a: 32, '15': 33}]; 801 let value = patch(base, diff); 802 expect(value).toEqual(expected); 803 }); 804 805 it('should patch a sequence object-patch in middle', () => { 806 let base = [{a: 32, '15': 33}, {a: 32, '15': 33}, {a: 32, '15': 33}]; 807 let diff = [makePatch(1, [makeReplace('15', 22)])]; 808 let expected = [{a: 32, '15': 33}, {a: 32, '15': 22}, {a: 32, '15': 33}]; 809 let value = patch(base, diff); 810 expect(value).toEqual(expected); 811 }); 812 813 it('should patch a sequence object-patch at end', () => { 814 let base = [{a: 32, '15': 33}, {a: 32, '15': 33}, {a: 32, '15': 33}]; 815 let diff = [makePatch(2, [makeReplace('15', 22)])]; 816 let expected = [{a: 32, '15': 33}, {a: 32, '15': 33}, {a: 32, '15': 22}]; 817 let value = patch(base, diff); 818 expect(value).toEqual(expected); 819 }); 820 821 }); 822 823 it('should patch a sequence with a null diff', () => { 824 let base = [55, 43]; 825 let diff = null; 826 let patched = patch(base, diff); 827 expect(patched).toEqual(base); 828 // Should return a copy 829 expect(patched).not.toBe(base); 830 }); 831 832 it('should fail to patch a sequence with a non-number key', () => { 833 let base = [55, 43]; 834 // Obvious case 835 let diff = [makeRemove('text')]; 836 expect(() => {patch(base, diff)}).toThrow( 837 /Invalid patch sequence op: Key is not a number: text/); 838 839 // Not so obvious case (pure type error, which could be cast correctly) 840 diff = [makeRemove('32')]; 841 expect(() => {patch(base, diff)}).toThrow( 842 /Invalid patch sequence op: Key is not a number: 32/); 843 }); 844 845 it('should fail to patch a sequence with an add on invalid key', () => { 846 let base = [55, 43]; 847 let diff = [makeAddRange(-1, [22])]; 848 expect(() => {patch(base, diff)}).toThrow( 849 /Invalid add range diff op: Key out of range: -1/); 850 851 diff = [makeAddRange(3, [22])]; 852 expect(() => {patch(base, diff)}).toThrow( 853 /Invalid add range diff op: Key out of range: 3/); 854 855 diff = [makeAddRange(Infinity, [22])]; 856 expect(() => {patch(base, diff)}).toThrow( 857 /Invalid add range diff op: Key out of range: Infinity/); 858 859 diff = [makeAddRange(NaN, [22])]; 860 expect(() => {patch(base, diff)}).toThrow( 861 /Invalid add range diff op: Key out of range: NaN/); 862 }); 863 864 it('should fail to patch a sequence with a remove on invalid key', () => { 865 let base = [55, 43]; 866 let diff = [makeRemoveRange(-1, 1)]; 867 expect(() => {patch(base, diff)}).toThrow( 868 /Invalid remove range diff op: Key out of range: -1/); 869 870 diff = [makeRemoveRange(2, 1)]; 871 expect(() => {patch(base, diff)}).toThrow( 872 /Invalid remove range diff op: Key out of range: 2/); 873 874 diff = [makeRemoveRange(Infinity, 1)]; 875 expect(() => {patch(base, diff)}).toThrow( 876 /Invalid remove range diff op: Key out of range: Infinity/); 877 878 diff = [makeRemoveRange(NaN, 1)]; 879 expect(() => {patch(base, diff)}).toThrow( 880 /Invalid remove range diff op: Key out of range: NaN/); 881 }); 882 883 it('should fail to patch a sequence with a too long remove', () => { 884 let base = [55, 43]; 885 let diff = [makeRemoveRange(0, 3)]; 886 expect(() => {patch(base, diff)}).toThrow( 887 /Invalid remove range diff op: Range too long!/); 888 889 diff = [makeRemoveRange(1, 2)]; 890 expect(() => {patch(base, diff)}).toThrow( 891 /Invalid remove range diff op: Range too long!/); 892 }); 893 894 it('should fail to patch a sequence with a patch of an atomic value', () => { 895 let base = [55, 43]; 896 let diff = [makePatch(0, [makeAdd('b', 22)])]; 897 expect(() => {patch(base, diff)}).toThrow( 898 /Cannot patch an atomic type: number/); 899 }); 900 901 it('should fail to patch a sequence with a patch of an invalid key', () => { 902 let base = [55, 43]; 903 let diff = [makePatch(-1, [makeReplace('b', 22)])]; 904 expect(() => {patch(base, diff)}).toThrow( 905 /Invalid patch diff op: Key out of range: -1/); 906 907 diff = [makePatch(2, [makeReplace('b', 22)])]; 908 expect(() => {patch(base, diff)}).toThrow( 909 /Invalid patch diff op: Key out of range: 2/); 910 911 diff = [makePatch(Infinity, [makeReplace('b', 22)])]; 912 expect(() => {patch(base, diff)}).toThrow( 913 /Invalid patch diff op: Key out of range: Infinity/); 914 915 diff = [makePatch(NaN, [makeReplace('b', 22)])]; 916 expect(() => {patch(base, diff)}).toThrow( 917 /Invalid patch diff op: Key out of range: NaN/); 918 }); 919 920 it('should fail to patch a sequence with an invalid diff op', () => { 921 let base = [55, 43]; 922 let diff = [{op: 'typo', value: 22, key: 0}]; 923 expect(() => {patch(base, diff as any)}).toThrow(/Invalid op: typo/); 924 }); 925 926 }); 927 928 describe('patch string', () => { 929 930 931 describe('patch string line addition', () => { 932 933 it('should patch a string line addition at start', () => { 934 let base = 'abc\ndef\ngh\n'; 935 let diff = [makeAddRange(0, ['ij\n'])]; 936 let expected = 'ij\nabc\ndef\ngh\n'; 937 let value = patch(base, diff); 938 expect(value).toEqual(expected); 939 }); 940 941 it('should patch a string line addition in middle', () => { 942 let base = 'abc\ndef\ngh\n'; 943 let diff = [makeAddRange(1, ['ij\n'])]; 944 let expected = 'abc\nij\ndef\ngh\n'; 945 let value = patch(base, diff); 946 expect(value).toEqual(expected); 947 }); 948 949 it('should patch a string addition at end', () => { 950 let base = 'abc\ndef\ngh\n'; 951 let diff = [makeAddRange(3, ['ij\n'])]; 952 let expected = 'abc\ndef\ngh\nij\n'; 953 let value = patch(base, diff); 954 expect(value).toEqual(expected); 955 956 diff = [makeAddRange(3, ['ij'])]; 957 expected = 'abc\ndef\ngh\nij'; 958 value = patch(base, diff); 959 expect(value).toEqual(expected); 960 }); 961 }); 962 963 describe('patch string character addition', () => { 964 965 it('should patch a string character addition at start of first line', () => { 966 let base = 'abc\ndef\ngh\n'; 967 let diff = [makePatch(0, [makeAddRange(0, ['ij'])])]; 968 let expected = 'ijabc\ndef\ngh\n'; 969 let value = patch(base, diff); 970 expect(value).toEqual(expected); 971 }); 972 973 it('should patch a string character addition at end of first line', () => { 974 let base = 'abc\ndef\ngh\n'; 975 let diff = [makePatch(0, [makeAddRange('abc'.length, ['ij'])])]; 976 let expected = 'abcij\ndef\ngh\n'; 977 let value = patch(base, diff); 978 expect(value).toEqual(expected); 979 }); 980 981 it('should patch a string character addition at start of middle line', () => { 982 let base = 'abc\ndef\ngh\n'; 983 let diff = [makePatch(1, [makeAddRange(0, ['ij'])])]; 984 let expected = 'abc\nijdef\ngh\n'; 985 let value = patch(base, diff); 986 expect(value).toEqual(expected); 987 }); 988 989 it('should patch a string character addition at end of middle line', () => { 990 let base = 'abc\ndef\ngh\n'; 991 let diff = [makePatch(1, [makeAddRange('def'.length, ['ij'])])]; 992 let expected = 'abc\ndefij\ngh\n'; 993 let value = patch(base, diff); 994 expect(value).toEqual(expected); 995 }); 996 997 it('should patch a string character addition in last line', () => { 998 let base = 'abc\ndef\ngh\n'; 999 let diff = [makePatch(3, [makeAddRange(0, ['ij'])])]; 1000 let expected = 'abc\ndef\ngh\nij'; 1001 let value = patch(base, diff); 1002 expect(value).toEqual(expected); 1003 }); 1004 1005 }); 1006 1007 describe('patch string line removal', () => { 1008 1009 it('should patch a string line removal at start', () => { 1010 let base = 'abc\ndef\ngh\n'; 1011 let diff = [makeRemoveRange(0, 1)]; 1012 let expected = 'def\ngh\n'; 1013 let value = patch(base, diff); 1014 expect(value).toEqual(expected); 1015 }); 1016 1017 it('should patch a string line removal in middle', () => { 1018 let base = 'abc\ndef\ngh\n'; 1019 let diff = [makeRemoveRange(1, 1)]; 1020 let expected = 'abc\ngh\n'; 1021 let value = patch(base, diff); 1022 expect(value).toEqual(expected); 1023 }); 1024 1025 it('should patch a string removal at end', () => { 1026 let base = 'abc\ndef\ngh\n'; 1027 let diff = [makeRemoveRange(2, 1)]; 1028 let expected = 'abc\ndef\n'; 1029 let value = patch(base, diff); 1030 expect(value).toEqual(expected); 1031 1032 // Removing line 3 is for now a valid no-op 1033 // Instead, the diff should say that the newline at end of line 2 1034 // should be removed! Possibly we could make this explicit by an 1035 // exception / warning? 1036 }); 1037 }); 1038 1039 describe('patch string character removal', () => { 1040 1041 it('should patch a string character removal at start of first line', () => { 1042 let base = 'abc\ndef\ngh\n'; 1043 let diff = [makePatch(0, [makeRemoveRange(1, 2)])]; 1044 let expected = 'a\ndef\ngh\n'; 1045 let value = patch(base, diff); 1046 expect(value).toEqual(expected); 1047 }); 1048 1049 it('should patch a string character removal at end of first line', () => { 1050 let base = 'abc\ndef\ngh\n'; 1051 let diff = [makePatch(0, [makeRemoveRange(1, 2)])]; 1052 let expected = 'a\ndef\ngh\n'; 1053 let value = patch(base, diff); 1054 expect(value).toEqual(expected); 1055 1056 // TODO: Is this really wanted behavior? 1057 diff = [makePatch(0, [makeRemoveRange(2, 2)])]; 1058 expected = 'abdef\ngh\n'; 1059 value = patch(base, diff); 1060 expect(value).toEqual(expected); 1061 }); 1062 1063 it('should patch a string character removal at start of middle line', () => { 1064 let base = 'abc\ndef\ngh\n'; 1065 let diff = [makePatch(1, [makeRemoveRange(0, 2)])]; 1066 let expected = 'abc\nf\ngh\n'; 1067 let value = patch(base, diff); 1068 expect(value).toEqual(expected); 1069 }); 1070 1071 it('should patch a string character removal at end of middle line', () => { 1072 let base = 'abc\ndef\ngh\n'; 1073 let diff = [makePatch(1, [makeRemoveRange(1, 2)])]; 1074 let expected = 'abc\nd\ngh\n'; 1075 let value = patch(base, diff); 1076 expect(value).toEqual(expected); 1077 }); 1078 1079 it('should patch a string character removal in last line', () => { 1080 let base = 'abc\ndef\ngh\nij'; 1081 let diff = [makePatch(3, [makeRemoveRange(0, 2)])]; 1082 let expected = 'abc\ndef\ngh\n'; 1083 let value = patch(base, diff); 1084 expect(value).toEqual(expected); 1085 }); 1086 1087 }); 1088 1089 it('should fail to patch a string with an add on invalid line key', () => { 1090 let base = 'abc\ndef\ngh\n'; 1091 let diff = [makeAddRange(-1, ['ij\n'])]; 1092 expect(() => {patch(base, diff)}).toThrow( 1093 /Invalid add range diff op: Key out of range: -1/); 1094 1095 diff = [makeAddRange(5, ['ij\n'])]; 1096 expect(() => {patch(base, diff)}).toThrow( 1097 /Invalid add range diff op: Key out of range: 5/); 1098 1099 diff = [makeAddRange(Infinity, ['ij\n'])]; 1100 expect(() => {patch(base, diff)}).toThrow( 1101 /Invalid add range diff op: Key out of range: Infinity/); 1102 1103 diff = [makeAddRange(NaN, ['ij\n'])]; 1104 expect(() => {patch(base, diff)}).toThrow( 1105 /Invalid add range diff op: Key out of range: NaN/); 1106 }); 1107 1108 it('should fail to patch a string with an add on invalid character key', () => { 1109 let base = 'abc\ndef\ngh\n'; 1110 let diff = [makePatch(0, [makeAddRange(-1, ['ij'])])]; 1111 expect(() => {patch(base, diff)}).toThrow( 1112 /Invalid add range diff op: Key out of range: -1/); 1113 1114 diff = [makePatch(0, [makeAddRange(5, ['ij'])])]; 1115 expect(() => {patch(base, diff)}).toThrow( 1116 /Invalid add range diff op: Key out of range: 5/); 1117 1118 diff = [makePatch(0, [makeAddRange(Infinity, ['ij'])])]; 1119 expect(() => {patch(base, diff)}).toThrow( 1120 /Invalid add range diff op: Key out of range: Infinity/); 1121 1122 diff = [makePatch(0, [makeAddRange(NaN, ['ij'])])]; 1123 expect(() => {patch(base, diff)}).toThrow( 1124 /Invalid add range diff op: Key out of range: NaN/); 1125 }); 1126 1127 it('should fail to patch a string with a remove on invalid line key', () => { 1128 let base = 'abc\ndef\ngh\n'; 1129 let diff = [makeRemoveRange(-1, 1)]; 1130 expect(() => {patch(base, diff)}).toThrow( 1131 /Invalid remove range diff op: Key out of range: -1/); 1132 1133 diff = [makeRemoveRange(4, 1)]; 1134 expect(() => {patch(base, diff)}).toThrow( 1135 /Invalid remove range diff op: Key out of range: 4/); 1136 1137 diff = [makeRemoveRange(Infinity, 1)]; 1138 expect(() => {patch(base, diff)}).toThrow( 1139 /Invalid remove range diff op: Key out of range: Infinity/); 1140 1141 diff = [makeRemoveRange(NaN, 1)]; 1142 expect(() => {patch(base, diff)}).toThrow( 1143 /Invalid remove range diff op: Key out of range: NaN/); 1144 }); 1145 1146 it('should fail to patch a string with a remove on invalid character key', () => { 1147 let base = 'abc\ndef\ngh\n'; 1148 let diff = [makePatch(0, [makeRemoveRange(-1, 1)])]; 1149 expect(() => {patch(base, diff)}).toThrow( 1150 /Invalid remove range diff op: Key out of range: -1/); 1151 1152 diff = [makePatch(0, [makeRemoveRange(4, 1)])]; 1153 expect(() => {patch(base, diff)}).toThrow( 1154 /Invalid remove range diff op: Key out of range: 4/); 1155 1156 diff = [makePatch(0, [makeRemoveRange(Infinity, 1)])]; 1157 expect(() => {patch(base, diff)}).toThrow( 1158 /Invalid remove range diff op: Key out of range: Infinity/); 1159 1160 diff = [makePatch(0, [makeRemoveRange(NaN, 1)])]; 1161 expect(() => {patch(base, diff)}).toThrow( 1162 /Invalid remove range diff op: Key out of range: NaN/); 1163 }); 1164 1165 it('should fail to patch a string with a too long line remove', () => { 1166 let base = 'abc\ndef\ngh\n'; 1167 let diff = [makeRemoveRange(0, 5)]; 1168 expect(() => {patch(base, diff)}).toThrow( 1169 /Invalid remove range diff op: Range too long!/); 1170 1171 diff = [makeRemoveRange(3, 2)]; 1172 expect(() => {patch(base, diff)}).toThrow( 1173 /Invalid remove range diff op: Range too long!/); 1174 }); 1175 1176 it('should fail to patch a string with a too long character remove', () => { 1177 let base = 'abc\ndef\ngh\n'; 1178 let diff = [makePatch(0, [makeRemoveRange(0, 5)])]; 1179 expect(() => {patch(base, diff)}).toThrow( 1180 /Invalid remove range diff op: Range too long!/); 1181 1182 // TODO: Should this exclude new-line? 1183 diff = [makePatch(0, [makeRemoveRange(3, 2)])]; 1184 expect(() => {patch(base, diff)}).toThrow( 1185 /Invalid remove range diff op: Range too long!/); 1186 }); 1187 1188 it('should fail to patch a string with a patch of an invalid line key', () => { 1189 let base = 'abc\ndef\ngh\n'; 1190 let diff = [makePatch(-1, [makeAddRange(0, ['ij\n'])])]; 1191 expect(() => {patch(base, diff)}).toThrow( 1192 /Invalid patch diff op: Key out of range: -1/); 1193 1194 diff = [makePatch(4, [makeAddRange(0, ['ij\n'])])]; 1195 expect(() => {patch(base, diff)}).toThrow( 1196 /Invalid patch diff op: Key out of range: 4/); 1197 1198 diff = [makePatch(Infinity, [makeAddRange(0, ['ij\n'])])]; 1199 expect(() => {patch(base, diff)}).toThrow( 1200 /Invalid patch diff op: Key out of range: Infinity/); 1201 1202 diff = [makePatch(NaN, [makeAddRange(0, ['ij\n'])])]; 1203 expect(() => {patch(base, diff)}).toThrow( 1204 /Invalid patch diff op: Key out of range: NaN/); 1205 }); 1206 1207 it('should fail to patch a string with an invalid line diff op', () => { 1208 let base = 'abc\ndef\ngh\n'; 1209 let diff = [{op: 'typo', value: 22, key: 0}]; 1210 expect(() => {patch(base, diff as any)}).toThrow(/Invalid op: typo/); 1211 }); 1212 1213 it('should fail to patch a string with an invalid character diff op', () => { 1214 let base = 'abc\ndef\ngh\n'; 1215 let diff = [makePatch(0, [{op: 'typo', value: 22, key: 0}] as any)]; 1216 expect(() => {patch(base, diff)}).toThrow(/Invalid op: typo/); 1217 }); 1218 1219 }); 1220 1221 }); 1222 1223}); 1224