r102041 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r102040‎ | r102041 | r102042 >
Date:20:27, 4 November 2011
Author:catrope
Status:deferred
Tags:
Comment:
Add a metric ton of (mostly generated) selectNodes tests, and change selectNodes a little bit to make them pass
Modified paths:
  • /trunk/extensions/VisualEditor/modules/es/bases/es.DocumentBranchNode.js (modified) (history)
  • /trunk/extensions/VisualEditor/tests/es/es.DocumentNode.test.js (modified) (history)

Diff [purge]

Index: trunk/extensions/VisualEditor/tests/es/es.DocumentNode.test.js
@@ -114,7 +114,7 @@
115115 }
116116 } );
117117
118 -test( 'es.DocumentBranchNode.selectNodes', 21, function() {
 118+test( 'es.DocumentBranchNode.selectNodes', 75, function() {
119119
120120 // selectNodes tests
121121
@@ -125,11 +125,8 @@
126126 var f = new DocumentBranchNodeStub( [], 'f', 8 ),
127127 g = new DocumentBranchNodeStub( [], 'g', 8 ),
128128 h = new DocumentBranchNodeStub( [], 'h', 8 ),
129 - root2 = new DocumentBranchNodeStub( [f, g, h], 'root2', 30 );
130 - // FIXME: QUnit thinks f == g because both are empty arrays. Rawr.
131 - // TODO make sure there is a test case for everything that is special-cased in the code
132 - // TODO also nest with a more complicated nested structure, like the one from
133 - // es.DocumentModel.test.js
 129+ root2 = new DocumentBranchNodeStub( [f, g, h], 'root2', 30 ),
 130+ big = es.DocumentModel.newFromPlainObject( esTest.obj );
134131
135132 // Tests 1 ... 22
136133 // Possible positions are:
@@ -236,59 +233,558 @@
237234 'output': [],
238235 'desc': 'Zero-length range past the end of a node'
239236 },
240 - // TODO add a complete set of combinations for cross-node ranges
241237 {
242238 'node': root2,
243 - 'input': new es.Range( 5, 25 ),
 239+ 'input': new es.Range( 20, 20 ),
 240+ 'output': [],
 241+ 'desc': 'Zero-length range between two nodes'
 242+ },
 243+ // Complete set of combinations for cross-node selections. Generated with help of a script
 244+ {
 245+ 'node': root2,
 246+ 'input': new es.Range( 0, 11 ),
244247 'output': [
245 - { 'node': f, 'range': new es.Range( 4, 8 ) },
 248+ { 'node': f },
 249+ { 'node': g, 'range': new es.Range( 0, 0 ) }
 250+ ],
 251+ 'desc': 'Range starting before the beginning of the first node and ending at the beginning of the second node'
 252+ },
 253+ {
 254+ 'node': root2,
 255+ 'input': new es.Range( 0, 14 ),
 256+ 'output': [
 257+ { 'node': f },
 258+ { 'node': g, 'range': new es.Range( 0, 3 ) }
 259+ ],
 260+ 'desc': 'Range starting before the beginning of the first node and ending in the middle of the second node'
 261+ },
 262+ {
 263+ 'node': root2,
 264+ 'input': new es.Range( 0, 19 ),
 265+ 'output': [
 266+ { 'node': f },
 267+ { 'node': g, 'range': new es.Range( 0, 8 ) }
 268+ ],
 269+ 'desc': 'Range starting before the beginning of the first node and ending at the end of the second node'
 270+ },
 271+ {
 272+ 'node': root2,
 273+ 'input': new es.Range( 0, 20 ),
 274+ 'output': [
 275+ { 'node': f },
 276+ { 'node': g }
 277+ ],
 278+ 'desc': 'Range starting before the beginning of the first node and ending between the second and the third node'
 279+ },
 280+ {
 281+ 'node': root2,
 282+ 'input': new es.Range( 0, 21 ),
 283+ 'output': [
 284+ { 'node': f },
246285 { 'node': g },
247 - { 'node': h, 'range': new es.Range( 0, 4 ) }
 286+ { 'node': h, 'range': new es.Range( 0, 0 ) }
248287 ],
249 - 'desc': 'Range from the middle of the first node to the middle of the third'
 288+ 'desc': 'Range starting before the beginning of the first node and ending at the beginning of the third node'
250289 },
251290 {
252291 'node': root2,
 292+ 'input': new es.Range( 0, 27 ),
 293+ 'output': [
 294+ { 'node': f },
 295+ { 'node': g },
 296+ { 'node': h, 'range': new es.Range( 0, 6 ) }
 297+ ],
 298+ 'desc': 'Range starting before the beginning of the first node and ending in the middle of the third node'
 299+ },
 300+ {
 301+ 'node': root2,
 302+ 'input': new es.Range( 0, 29 ),
 303+ 'output': [
 304+ { 'node': f },
 305+ { 'node': g },
 306+ { 'node': h, 'range': new es.Range( 0, 8 ) }
 307+ ],
 308+ 'desc': 'Range starting before the beginning of the first node and ending at the end of the third node'
 309+ },
 310+ {
 311+ 'node': root2,
 312+ 'input': new es.Range( 0, 30 ),
 313+ 'output': [
 314+ { 'node': f },
 315+ { 'node': g },
 316+ { 'node': h }
 317+ ],
 318+ 'desc': 'Range starting before the beginning of the first node and ending past the end of the third node'
 319+ },
 320+ {
 321+ 'node': root2,
 322+ 'input': new es.Range( 1, 11 ),
 323+ 'output': [
 324+ { 'node': f, 'range': new es.Range( 0, 8 ) },
 325+ { 'node': g, 'range': new es.Range( 0, 0 ) }
 326+ ],
 327+ 'desc': 'Range starting at the beginning of the first node and ending at the beginning of the second node'
 328+ },
 329+ {
 330+ 'node': root2,
 331+ 'input': new es.Range( 1, 14 ),
 332+ 'output': [
 333+ { 'node': f, 'range': new es.Range( 0, 8 ) },
 334+ { 'node': g, 'range': new es.Range( 0, 3 ) }
 335+ ],
 336+ 'desc': 'Range starting at the beginning of the first node and ending in the middle of the second node'
 337+ },
 338+ {
 339+ 'node': root2,
 340+ 'input': new es.Range( 1, 19 ),
 341+ 'output': [
 342+ { 'node': f, 'range': new es.Range( 0, 8 ) },
 343+ { 'node': g, 'range': new es.Range( 0, 8 ) }
 344+ ],
 345+ 'desc': 'Range starting at the beginning of the first node and ending at the end of the second node'
 346+ },
 347+ {
 348+ 'node': root2,
 349+ 'input': new es.Range( 1, 20 ),
 350+ 'output': [
 351+ { 'node': f, 'range': new es.Range( 0, 8 ) },
 352+ { 'node': g }
 353+ ],
 354+ 'desc': 'Range starting at the beginning of the first node and ending between the second and the third node'
 355+ },
 356+ {
 357+ 'node': root2,
 358+ 'input': new es.Range( 1, 21 ),
 359+ 'output': [
 360+ { 'node': f, 'range': new es.Range( 0, 8 ) },
 361+ { 'node': g },
 362+ { 'node': h, 'range': new es.Range( 0, 0 ) }
 363+ ],
 364+ 'desc': 'Range starting at the beginning of the first node and ending at the beginning of the third node'
 365+ },
 366+ {
 367+ 'node': root2,
 368+ 'input': new es.Range( 1, 27 ),
 369+ 'output': [
 370+ { 'node': f, 'range': new es.Range( 0, 8 ) },
 371+ { 'node': g },
 372+ { 'node': h, 'range': new es.Range( 0, 6 ) }
 373+ ],
 374+ 'desc': 'Range starting at the beginning of the first node and ending in the middle of the third node'
 375+ },
 376+ {
 377+ 'node': root2,
 378+ 'input': new es.Range( 1, 29 ),
 379+ 'output': [
 380+ { 'node': f, 'range': new es.Range( 0, 8 ) },
 381+ { 'node': g },
 382+ { 'node': h, 'range': new es.Range( 0, 8 ) }
 383+ ],
 384+ 'desc': 'Range starting at the beginning of the first node and ending at the end of the third node'
 385+ },
 386+ {
 387+ 'node': root2,
 388+ 'input': new es.Range( 1, 30 ),
 389+ 'output': [
 390+ { 'node': f, 'range': new es.Range( 0, 8 ) },
 391+ { 'node': g },
 392+ { 'node': h }
 393+ ],
 394+ 'desc': 'Range starting at the beginning of the first node and ending past the end of the third node'
 395+ },
 396+ {
 397+ 'node': root2,
253398 'input': new es.Range( 5, 11 ),
254399 'output': [
255400 { 'node': f, 'range': new es.Range( 4, 8 ) },
256401 { 'node': g, 'range': new es.Range( 0, 0 ) }
257402 ],
258 - 'desc': 'Range from the middle of a node to the beginning of the second'
 403+ 'desc': 'Range starting in the middle of the first node and ending at the beginning of the second node'
259404 },
260405 {
261406 'node': root2,
262 - 'input': new es.Range( 5, 12 ),
 407+ 'input': new es.Range( 5, 14 ),
263408 'output': [
264409 { 'node': f, 'range': new es.Range( 4, 8 ) },
265 - { 'node': g, 'range': new es.Range( 0, 1 ) }
 410+ { 'node': g, 'range': new es.Range( 0, 3 ) }
266411 ],
267 - 'desc': 'Range from in the middle of a node to the first character of the second'
 412+ 'desc': 'Range starting in the middle of the first node and ending in the middle of the second node'
268413 },
269414 {
270415 'node': root2,
271 - 'input': new es.Range( 8, 16 ),
 416+ 'input': new es.Range( 5, 19 ),
272417 'output': [
273 - { 'node': f, 'range': new es.Range( 7, 8 ) },
274 - { 'node': g, 'range': new es.Range( 0, 5 ) }
 418+ { 'node': f, 'range': new es.Range( 4, 8 ) },
 419+ { 'node': g, 'range': new es.Range( 0, 8 ) }
275420 ],
276 - 'desc': 'Range from before the last character of a node to the middle of the next node'
 421+ 'desc': 'Range starting in the middle of the first node and ending at the end of the second node'
277422 },
278423 {
279424 'node': root2,
280 - 'input': new es.Range( 9, 16 ),
 425+ 'input': new es.Range( 5, 20 ),
281426 'output': [
 427+ { 'node': f, 'range': new es.Range( 4, 8 ) },
 428+ { 'node': g }
 429+ ],
 430+ 'desc': 'Range starting in the middle of the first node and ending between the second and the third node'
 431+ },
 432+ {
 433+ 'node': root2,
 434+ 'input': new es.Range( 5, 21 ),
 435+ 'output': [
 436+ { 'node': f, 'range': new es.Range( 4, 8 ) },
 437+ { 'node': g },
 438+ { 'node': h, 'range': new es.Range( 0, 0 ) }
 439+ ],
 440+ 'desc': 'Range starting in the middle of the first node and ending at the beginning of the third node'
 441+ },
 442+ {
 443+ 'node': root2,
 444+ 'input': new es.Range( 5, 27 ),
 445+ 'output': [
 446+ { 'node': f, 'range': new es.Range( 4, 8 ) },
 447+ { 'node': g },
 448+ { 'node': h, 'range': new es.Range( 0, 6 ) }
 449+ ],
 450+ 'desc': 'Range starting in the middle of the first node and ending in the middle of the third node'
 451+ },
 452+ {
 453+ 'node': root2,
 454+ 'input': new es.Range( 5, 29 ),
 455+ 'output': [
 456+ { 'node': f, 'range': new es.Range( 4, 8 ) },
 457+ { 'node': g },
 458+ { 'node': h, 'range': new es.Range( 0, 8 ) }
 459+ ],
 460+ 'desc': 'Range starting in the middle of the first node and ending at the end of the third node'
 461+ },
 462+ {
 463+ 'node': root2,
 464+ 'input': new es.Range( 5, 30 ),
 465+ 'output': [
 466+ { 'node': f, 'range': new es.Range( 4, 8 ) },
 467+ { 'node': g },
 468+ { 'node': h }
 469+ ],
 470+ 'desc': 'Range starting in the middle of the first node and ending past the end of the third node'
 471+ },
 472+ {
 473+ 'node': root2,
 474+ 'input': new es.Range( 9, 11 ),
 475+ 'output': [
282476 { 'node': f, 'range': new es.Range( 8, 8 ) },
283 - { 'node': g, 'range': new es.Range( 0, 5 ) }
 477+ { 'node': g, 'range': new es.Range( 0, 0 ) }
284478 ],
285 - 'desc': 'Range from at the end of a node to the middle of the next node'
 479+ 'desc': 'Range starting at the end of the first node and ending at the beginning of the second node'
 480+ },
 481+ {
 482+ 'node': root2,
 483+ 'input': new es.Range( 9, 14 ),
 484+ 'output': [
 485+ { 'node': f, 'range': new es.Range( 8, 8 ) },
 486+ { 'node': g, 'range': new es.Range( 0, 3 ) }
 487+ ],
 488+ 'desc': 'Range starting at the end of the first node and ending in the middle of the second node'
 489+ },
 490+ {
 491+ 'node': root2,
 492+ 'input': new es.Range( 9, 19 ),
 493+ 'output': [
 494+ { 'node': f, 'range': new es.Range( 8, 8 ) },
 495+ { 'node': g, 'range': new es.Range( 0, 8 ) }
 496+ ],
 497+ 'desc': 'Range starting at the end of the first node and ending at the end of the second node'
 498+ },
 499+ {
 500+ 'node': root2,
 501+ 'input': new es.Range( 9, 20 ),
 502+ 'output': [
 503+ { 'node': f, 'range': new es.Range( 8, 8 ) },
 504+ { 'node': g }
 505+ ],
 506+ 'desc': 'Range starting at the end of the first node and ending between the second and the third node'
 507+ },
 508+ {
 509+ 'node': root2,
 510+ 'input': new es.Range( 9, 21 ),
 511+ 'output': [
 512+ { 'node': f, 'range': new es.Range( 8, 8 ) },
 513+ { 'node': g },
 514+ { 'node': h, 'range': new es.Range( 0, 0 ) }
 515+ ],
 516+ 'desc': 'Range starting at the end of the first node and ending at the beginning of the third node'
 517+ },
 518+ {
 519+ 'node': root2,
 520+ 'input': new es.Range( 9, 27 ),
 521+ 'output': [
 522+ { 'node': f, 'range': new es.Range( 8, 8 ) },
 523+ { 'node': g },
 524+ { 'node': h, 'range': new es.Range( 0, 6 ) }
 525+ ],
 526+ 'desc': 'Range starting at the end of the first node and ending in the middle of the third node'
 527+ },
 528+ {
 529+ 'node': root2,
 530+ 'input': new es.Range( 9, 29 ),
 531+ 'output': [
 532+ { 'node': f, 'range': new es.Range( 8, 8 ) },
 533+ { 'node': g },
 534+ { 'node': h, 'range': new es.Range( 0, 8 ) }
 535+ ],
 536+ 'desc': 'Range starting at the end of the first node and ending at the end of the third node'
 537+ },
 538+ {
 539+ 'node': root2,
 540+ 'input': new es.Range( 9, 30 ),
 541+ 'output': [
 542+ { 'node': f, 'range': new es.Range( 8, 8 ) },
 543+ { 'node': g },
 544+ { 'node': h }
 545+ ],
 546+ 'desc': 'Range starting at the end of the first node and ending past the end of the third node'
 547+ },
 548+ {
 549+ 'node': root2,
 550+ 'input': new es.Range( 10, 21 ),
 551+ 'output': [
 552+ { 'node': g },
 553+ { 'node': h, 'range': new es.Range( 0, 0 ) }
 554+ ],
 555+ 'desc': 'Range starting between the first and the second node and ending at the beginning of the third node'
 556+ },
 557+ {
 558+ 'node': root2,
 559+ 'input': new es.Range( 10, 27 ),
 560+ 'output': [
 561+ { 'node': g },
 562+ { 'node': h, 'range': new es.Range( 0, 6 ) }
 563+ ],
 564+ 'desc': 'Range starting between the first and the second node and ending in the middle of the third node'
 565+ },
 566+ {
 567+ 'node': root2,
 568+ 'input': new es.Range( 10, 29 ),
 569+ 'output': [
 570+ { 'node': g },
 571+ { 'node': h, 'range': new es.Range( 0, 8 ) }
 572+ ],
 573+ 'desc': 'Range starting between the first and the second node and ending at the end of the third node'
 574+ },
 575+ {
 576+ 'node': root2,
 577+ 'input': new es.Range( 10, 30 ),
 578+ 'output': [
 579+ { 'node': g },
 580+ { 'node': h }
 581+ ],
 582+ 'desc': 'Range starting between the first and the second node and ending past the end of the third node'
 583+ },
 584+ {
 585+ 'node': root2,
 586+ 'input': new es.Range( 11, 21 ),
 587+ 'output': [
 588+ { 'node': g, 'range': new es.Range( 0, 8 ) },
 589+ { 'node': h, 'range': new es.Range( 0, 0 ) }
 590+ ],
 591+ 'desc': 'Range starting at the beginning of the second node and ending at the beginning of the third node'
 592+ },
 593+ {
 594+ 'node': root2,
 595+ 'input': new es.Range( 11, 27 ),
 596+ 'output': [
 597+ { 'node': g, 'range': new es.Range( 0, 8 ) },
 598+ { 'node': h, 'range': new es.Range( 0, 6 ) }
 599+ ],
 600+ 'desc': 'Range starting at the beginning of the second node and ending in the middle of the third node'
 601+ },
 602+ {
 603+ 'node': root2,
 604+ 'input': new es.Range( 11, 29 ),
 605+ 'output': [
 606+ { 'node': g, 'range': new es.Range( 0, 8 ) },
 607+ { 'node': h, 'range': new es.Range( 0, 8 ) }
 608+ ],
 609+ 'desc': 'Range starting at the beginning of the second node and ending at the end of the third node'
 610+ },
 611+ {
 612+ 'node': root2,
 613+ 'input': new es.Range( 11, 30 ),
 614+ 'output': [
 615+ { 'node': g, 'range': new es.Range( 0, 8 ) },
 616+ { 'node': h }
 617+ ],
 618+ 'desc': 'Range starting at the beginning of the second node and ending past the end of the third node'
 619+ },
 620+ {
 621+ 'node': root2,
 622+ 'input': new es.Range( 14, 21 ),
 623+ 'output': [
 624+ { 'node': g, 'range': new es.Range( 3, 8 ) },
 625+ { 'node': h, 'range': new es.Range( 0, 0 ) }
 626+ ],
 627+ 'desc': 'Range starting in the middle of the second node and ending at the beginning of the third node'
 628+ },
 629+ {
 630+ 'node': root2,
 631+ 'input': new es.Range( 14, 27 ),
 632+ 'output': [
 633+ { 'node': g, 'range': new es.Range( 3, 8 ) },
 634+ { 'node': h, 'range': new es.Range( 0, 6 ) }
 635+ ],
 636+ 'desc': 'Range starting in the middle of the second node and ending in the middle of the third node'
 637+ },
 638+ {
 639+ 'node': root2,
 640+ 'input': new es.Range( 14, 29 ),
 641+ 'output': [
 642+ { 'node': g, 'range': new es.Range( 3, 8 ) },
 643+ { 'node': h, 'range': new es.Range( 0, 8 ) }
 644+ ],
 645+ 'desc': 'Range starting in the middle of the second node and ending at the end of the third node'
 646+ },
 647+ {
 648+ 'node': root2,
 649+ 'input': new es.Range( 14, 30 ),
 650+ 'output': [
 651+ { 'node': g, 'range': new es.Range( 3, 8 ) },
 652+ { 'node': h }
 653+ ],
 654+ 'desc': 'Range starting in the middle of the second node and ending past the end of the third node'
 655+ },
 656+ {
 657+ 'node': root2,
 658+ 'input': new es.Range( 19, 21 ),
 659+ 'output': [
 660+ { 'node': g, 'range': new es.Range( 8, 8 ) },
 661+ { 'node': h, 'range': new es.Range( 0, 0 ) }
 662+ ],
 663+ 'desc': 'Range starting at the end of the second node and ending at the beginning of the third node'
 664+ },
 665+ {
 666+ 'node': root2,
 667+ 'input': new es.Range( 19, 27 ),
 668+ 'output': [
 669+ { 'node': g, 'range': new es.Range( 8, 8 ) },
 670+ { 'node': h, 'range': new es.Range( 0, 6 ) }
 671+ ],
 672+ 'desc': 'Range starting at the end of the second node and ending in the middle of the third node'
 673+ },
 674+ {
 675+ 'node': root2,
 676+ 'input': new es.Range( 19, 29 ),
 677+ 'output': [
 678+ { 'node': g, 'range': new es.Range( 8, 8 ) },
 679+ { 'node': h, 'range': new es.Range( 0, 8 ) }
 680+ ],
 681+ 'desc': 'Range starting at the end of the second node and ending at the end of the third node'
 682+ },
 683+ {
 684+ 'node': root2,
 685+ 'input': new es.Range( 19, 30 ),
 686+ 'output': [
 687+ { 'node': g, 'range': new es.Range( 8, 8 ) },
 688+ { 'node': h }
 689+ ],
 690+ 'desc': 'Range starting at the end of the second node and ending past the end of the third node'
 691+ },
 692+ // Tests for childless nodes
 693+ {
 694+ 'node': g,
 695+ 'input': new es.Range( 1, 3 ),
 696+ 'output': [
 697+ { 'node': g, 'range': new es.Range( 1, 3 ) }
 698+ ],
 699+ 'desc': 'Childless node given, range not out of bounds'
 700+ },
 701+ {
 702+ 'node': g,
 703+ 'input': new es.Range( 0, 8 ),
 704+ 'output': [
 705+ { 'node': g, 'range': new es.Range( 0, 8 ) }
 706+ ],
 707+ 'desc': 'Childless node given, range covers entire node'
 708+ },
 709+ // Tests for out-of-bounds cases
 710+ {
 711+ 'node': g,
 712+ 'input': new es.Range( -1, 3 ),
 713+ 'exception': /^The start offset of the range is negative$/,
 714+ 'desc': 'Childless node given, range start out of bounds'
 715+ },
 716+ {
 717+ 'node': g,
 718+ 'input': new es.Range( 1, 9 ),
 719+ 'exception': /^The end offset of the range is past the end of the node$/,
 720+ 'desc': 'Childless node given, range end out of bounds'
 721+ },
 722+ {
 723+ 'node': root2,
 724+ 'input': new es.Range( 31, 35 ),
 725+ 'exception': /^The start offset of the range is past the end of the node$/,
 726+ 'desc': 'Node with children given, range start out of bounds'
 727+ },
 728+ {
 729+ 'node': root2,
 730+ 'input': new es.Range( 30, 35 ),
 731+ 'exception': /^The end offset of the range is past the end of the node$/,
 732+ 'desc': 'Node with children given, range end out of bounds'
 733+ },
 734+ // Tests for recursion cases
 735+ {
 736+ 'node': big,
 737+ 'input': new es.Range( 2, 10 ),
 738+ 'output': [
 739+ { 'node': big.children[0], 'range': new es.Range( 1, 3 ) },
 740+ { 'node': big.children[1], 'range': new es.Range( 0, 4 ) }
 741+ ],
 742+ 'desc': 'Select from before the b to after the d'
 743+ },
 744+ {
 745+ 'node': big,
 746+ 'input': new es.Range( 3, 27 ),
 747+ 'output': [
 748+ { 'node': big.children[0], 'range': new es.Range( 2, 3 ) },
 749+ { 'node': big.children[1] },
 750+ { 'node': big.children[2], 'range': new es.Range( 0, 1 ) }
 751+ ],
 752+ 'desc': 'Select from before the c to after the h'
 753+ },
 754+ {
 755+ 'node': big,
 756+ 'input': new es.Range( 9, 17 ),
 757+ 'output': [
 758+ { 'node': big.children[1].children[0].children[0].children[0], 'range': new es.Range( 0, 1 ) },
 759+ { 'node': big.children[1].children[0].children[0].children[1], 'range': new es.Range( 0, 5 ) }
 760+ ],
 761+ 'desc': 'Select from before the d to after the f, with recursion'
 762+ },
 763+ {
 764+ 'node': big,
 765+ 'input': new es.Range( 9, 17 ),
 766+ 'shallow': true,
 767+ 'output': [
 768+ { 'node': big.children[1], 'range': new es.Range( 3, 11 ) }
 769+ ],
 770+ 'desc': 'Select from before the d to after the f, without recursion'
286771 }
287772 ];
 773+
288774 for ( var i = 0; i < selectNodesTests.length; i++ ) {
289 - deepEqual(
290 - root2.selectNodes( selectNodesTests[i].input ),
291 - selectNodesTests[i].output,
292 - selectNodesTests[i].desc
293 - );
 775+ if ( 'output' in selectNodesTests[i] ) {
 776+ deepEqual(
 777+ selectNodesTests[i].node.selectNodes( selectNodesTests[i].input, selectNodesTests[i].shallow ),
 778+ selectNodesTests[i].output,
 779+ selectNodesTests[i].desc
 780+ );
 781+ } else if ( 'exception' in selectNodesTests[i] ) {
 782+ raises(
 783+ function() {
 784+ selectNodesTests[i].node.selectNodes( selectNodesTests[i].input, selectNodesTests[i].shallow );
 785+ },
 786+ selectNodesTests[i].exception,
 787+ selectNodesTests[i].desc
 788+ );
 789+ }
294790 }
295791 } );
Index: trunk/extensions/VisualEditor/modules/es/bases/es.DocumentBranchNode.js
@@ -168,24 +168,6 @@
169169 // Empty range outside of any node
170170 return [];
171171 }
172 - if ( start == left - 1 && end == right + 1 ) {
173 - // The range covers the entire node, including its opening and closing elements
174 - return [ { 'node': this.children[i] } ];
175 - }
176 - if ( start == left - 1 ) {
177 - // start is between this.children[i-1] and this.children[i], move it to left for
178 - // convenience
179 - // We don't need to check for start < end here because we already have start != end and
180 - // start <= end
181 - start = left;
182 - }
183 - if ( end == right + 1 ) {
184 - // end is between this.children[i] and this.children[i+1], move it to right for
185 - // convenience
186 - // We don't need to check for start < end here because we already have start != end and
187 - // start <= end
188 - end = right;
189 - }
190172
191173 startInside = start >= left && start <= right; // is the start inside this.children[i]?
192174 endInside = end >= left && end <= right; // is the end inside this.children[i]?
@@ -215,6 +197,18 @@
216198 nodes.push( { 'node': this.children[i], 'range': new es.Range( 0, end - left ) } );
217199 // We've found the end, so we're done
218200 return nodes;
 201+ } else if ( end == right + 1 ) {
 202+ // end is between this.children[i] and this.children[i+1]
 203+ // start is not inside this.children[i], so the selection covers
 204+ // all of this.children[i], then ends
 205+ nodes.push( { 'node': this.children[i] } );
 206+ // We've reached the end so we're done
 207+ return nodes;
 208+ } else if ( start == left - 1 ) {
 209+ // start is between this.children[i-1] and this.children[i]
 210+ // end is not inside this.children[i], so the selection covers
 211+ // all of this.children[i] and more
 212+ nodes.push( { 'node': this.children[i] } );
219213 } else if ( nodes.length > 0 ) {
220214 // Neither the start nor the end is inside this.children[i], but nodes is non-empty,
221215 // so this.children[i] must be between the start and the end
@@ -226,11 +220,15 @@
227221 // We use +2 because we need to jump over the offset between this.children[i] and
228222 // this.children[i+1]
229223 left = right + 2;
 224+ if ( end < left ) {
 225+ // We've skipped over the end, so we're done
 226+ return nodes;
 227+ }
230228 }
231229
232230 // If we got here, that means that at least some part of the range is out of bounds
233231 // This is an error
234 - if ( nodes.length === 0 ) {
 232+ if ( start > right + 1 ) {
235233 throw 'The start offset of the range is past the end of the node';
236234 } else {
237235 // Apparently the start was inside this node, but the end wasn't

Status & tagging log