2020-05-06 06:11:22 -04:00
/ * e s l i n t - d i s a b l e
camelcase ,
mocha / no - identical - title ,
no - return - assign ,
* /
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
2020-05-06 06:10:51 -04:00
/ *
* decaffeinate suggestions :
* DS101 : Remove unnecessary use of Array . from
* DS102 : Remove unnecessary code created because of implicit returns
* DS202 : Simplify dynamic range loops
* DS205 : Consider reworking code to avoid use of IIFEs
* Full docs : https : //github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
* /
const text = require ( "../../../../app/js/sharejs/types/text" ) ;
require ( "chai" ) . should ( ) ;
const RangesTracker = require ( "../../../../app/js/RangesTracker" ) ;
describe ( "ShareJS text type" , function ( ) {
beforeEach ( function ( ) {
return this . t = "mock-thread-id" ;
} ) ;
2016-12-13 10:51:47 -05:00
2020-05-06 06:10:51 -04:00
describe ( "transform" , function ( ) {
describe ( "insert / insert" , function ( ) {
it ( "with an insert before" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { i : "foo" , p : 9 } , { i : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 12 } ] ) ;
} ) ;
it ( "with an insert after" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { i : "foo" , p : 3 } , { i : "bar" , p : 9 } ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 3 } ] ) ;
} ) ;
it ( "with an insert at the same place with side == 'right'" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { i : "foo" , p : 3 } , { i : "bar" , p : 3 } , 'right' ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 6 } ] ) ;
} ) ;
return it ( "with an insert at the same place with side == 'left'" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { i : "foo" , p : 3 } , { i : "bar" , p : 3 } , 'left' ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 3 } ] ) ;
} ) ;
} ) ;
describe ( "insert / delete" , function ( ) {
it ( "with a delete before" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { i : "foo" , p : 9 } , { d : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 6 } ] ) ;
} ) ;
it ( "with a delete after" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { i : "foo" , p : 3 } , { d : "bar" , p : 9 } ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 3 } ] ) ;
} ) ;
it ( "with a delete at the same place with side == 'right'" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { i : "foo" , p : 3 } , { d : "bar" , p : 3 } , 'right' ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 3 } ] ) ;
} ) ;
return it ( "with a delete at the same place with side == 'left'" , function ( ) {
const dest = [ ] ;
2017-03-01 11:49:46 -05:00
2020-05-06 06:10:51 -04:00
text . _tc ( dest , { i : "foo" , p : 3 } , { d : "bar" , p : 3 } , 'left' ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 3 } ] ) ;
} ) ;
} ) ;
describe ( "delete / insert" , function ( ) {
it ( "with an insert before" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 9 } , { i : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { d : "foo" , p : 12 } ] ) ;
} ) ;
it ( "with an insert after" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 3 } , { i : "bar" , p : 9 } ) ;
return dest . should . deep . equal ( [ { d : "foo" , p : 3 } ] ) ;
} ) ;
it ( "with an insert at the same place with side == 'right'" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 3 } , { i : "bar" , p : 3 } , 'right' ) ;
return dest . should . deep . equal ( [ { d : "foo" , p : 6 } ] ) ;
} ) ;
it ( "with an insert at the same place with side == 'left'" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 3 } , { i : "bar" , p : 3 } , 'left' ) ;
return dest . should . deep . equal ( [ { d : "foo" , p : 6 } ] ) ;
} ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:10:51 -04:00
return it ( "with a delete that overlaps the insert location" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 3 } , { i : "bar" , p : 4 } ) ;
return dest . should . deep . equal ( [ { d : "f" , p : 3 } , { d : "oo" , p : 6 } ] ) ;
} ) ;
} ) ;
2017-03-01 11:49:46 -05:00
2016-12-12 12:53:43 -05:00
2020-05-06 06:10:51 -04:00
describe ( "delete / delete" , function ( ) {
it ( "with a delete before" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 9 } , { d : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { d : "foo" , p : 6 } ] ) ;
} ) ;
it ( "with a delete after" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 3 } , { d : "bar" , p : 9 } ) ;
return dest . should . deep . equal ( [ { d : "foo" , p : 3 } ] ) ;
} ) ;
it ( "with deleting the same content" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 3 } , { d : "foo" , p : 3 } , 'right' ) ;
return dest . should . deep . equal ( [ ] ) ;
} ) ;
it ( "with the delete overlapping before" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foobar" , p : 3 } , { d : "abcfoo" , p : 0 } , 'right' ) ;
return dest . should . deep . equal ( [ { d : "bar" , p : 0 } ] ) ;
} ) ;
it ( "with the delete overlapping after" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "abcfoo" , p : 3 } , { d : "foobar" , p : 6 } ) ;
return dest . should . deep . equal ( [ { d : "abc" , p : 3 } ] ) ;
} ) ;
it ( "with the delete overlapping the whole delete" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "abcfoo123" , p : 3 } , { d : "foo" , p : 6 } ) ;
return dest . should . deep . equal ( [ { d : "abc123" , p : 3 } ] ) ;
} ) ;
return it ( "with the delete inside the whole delete" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 6 } , { d : "abcfoo123" , p : 3 } ) ;
return dest . should . deep . equal ( [ ] ) ;
} ) ;
} ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:10:51 -04:00
describe ( "comment / insert" , function ( ) {
it ( "with an insert before" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 9 , t : this . t } , { i : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { c : "foo" , p : 12 , t : this . t } ] ) ;
} ) ;
it ( "with an insert after" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 3 , t : this . t } , { i : "bar" , p : 9 } ) ;
return dest . should . deep . equal ( [ { c : "foo" , p : 3 , t : this . t } ] ) ;
} ) ;
it ( "with an insert at the left edge" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 3 , t : this . t } , { i : "bar" , p : 3 } ) ;
// RangesTracker doesn't inject inserts into comments on edges, so neither should we
return dest . should . deep . equal ( [ { c : "foo" , p : 6 , t : this . t } ] ) ;
} ) ;
it ( "with an insert at the right edge" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 3 , t : this . t } , { i : "bar" , p : 6 } ) ;
// RangesTracker doesn't inject inserts into comments on edges, so neither should we
return dest . should . deep . equal ( [ { c : "foo" , p : 3 , t : this . t } ] ) ;
} ) ;
return it ( "with an insert in the middle" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 3 , t : this . t } , { i : "bar" , p : 5 } ) ;
return dest . should . deep . equal ( [ { c : "fobaro" , p : 3 , t : this . t } ] ) ;
} ) ;
} ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:10:51 -04:00
describe ( "comment / delete" , function ( ) {
it ( "with a delete before" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 9 , t : this . t } , { d : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { c : "foo" , p : 6 , t : this . t } ] ) ;
} ) ;
it ( "with a delete after" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 3 , t : this . t } , { i : "bar" , p : 9 } ) ;
return dest . should . deep . equal ( [ { c : "foo" , p : 3 , t : this . t } ] ) ;
} ) ;
it ( "with a delete overlapping the comment content before" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foobar" , p : 6 , t : this . t } , { d : "123foo" , p : 3 } ) ;
return dest . should . deep . equal ( [ { c : "bar" , p : 3 , t : this . t } ] ) ;
} ) ;
it ( "with a delete overlapping the comment content after" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foobar" , p : 6 , t : this . t } , { d : "bar123" , p : 9 } ) ;
return dest . should . deep . equal ( [ { c : "foo" , p : 6 , t : this . t } ] ) ;
} ) ;
it ( "with a delete overlapping the comment content in the middle" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo123bar" , p : 6 , t : this . t } , { d : "123" , p : 9 } ) ;
return dest . should . deep . equal ( [ { c : "foobar" , p : 6 , t : this . t } ] ) ;
} ) ;
return it ( "with a delete overlapping the whole comment" , function ( ) {
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 6 , t : this . t } , { d : "123foo456" , p : 3 } ) ;
return dest . should . deep . equal ( [ { c : "" , p : 3 , t : this . t } ] ) ;
} ) ;
} ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:11:22 -04:00
describe ( "comment / insert" , function ( ) { return it ( "should not do anything" , function ( ) {
2020-05-06 06:10:51 -04:00
const dest = [ ] ;
text . _tc ( dest , { i : "foo" , p : 6 } , { c : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { i : "foo" , p : 6 } ] ) ;
2020-05-06 06:11:22 -04:00
} ) ; } ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:11:22 -04:00
describe ( "comment / delete" , function ( ) { return it ( "should not do anything" , function ( ) {
2020-05-06 06:10:51 -04:00
const dest = [ ] ;
text . _tc ( dest , { d : "foo" , p : 6 } , { c : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { d : "foo" , p : 6 } ] ) ;
2020-05-06 06:11:22 -04:00
} ) ; } ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:11:22 -04:00
return describe ( "comment / comment" , function ( ) { return it ( "should not do anything" , function ( ) {
2020-05-06 06:10:51 -04:00
const dest = [ ] ;
text . _tc ( dest , { c : "foo" , p : 6 } , { c : "bar" , p : 3 } ) ;
return dest . should . deep . equal ( [ { c : "foo" , p : 6 } ] ) ;
2020-05-06 06:11:22 -04:00
} ) ; } ) ;
2020-05-06 06:10:51 -04:00
} ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:10:51 -04:00
describe ( "apply" , function ( ) {
2020-05-06 06:11:22 -04:00
it ( "should apply an insert" , function ( ) { return text . apply ( "foo" , [ { i : "bar" , p : 2 } ] ) . should . equal ( "fobaro" ) ; } ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:11:22 -04:00
it ( "should apply a delete" , function ( ) { return text . apply ( "foo123bar" , [ { d : "123" , p : 3 } ] ) . should . equal ( "foobar" ) ; } ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:11:22 -04:00
it ( "should do nothing with a comment" , function ( ) { return text . apply ( "foo123bar" , [ { c : "123" , p : 3 } ] ) . should . equal ( "foo123bar" ) ; } ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:11:22 -04:00
it ( "should throw an error when deleted content does not match" , function ( ) { return ( ( ( ) => text . apply ( "foo123bar" , [ { d : "456" , p : 3 } ] ) ) ) . should . throw ( Error ) ; } ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:11:22 -04:00
return it ( "should throw an error when comment content does not match" , function ( ) { return ( ( ( ) => text . apply ( "foo123bar" , [ { c : "456" , p : 3 } ] ) ) ) . should . throw ( Error ) ; } ) ;
2020-05-06 06:10:51 -04:00
} ) ;
2016-12-12 12:53:43 -05:00
2020-05-06 06:11:22 -04:00
return describe ( "applying ops and comments in different orders" , function ( ) { return it ( "should not matter which op or comment is applied first" , function ( ) {
2020-05-06 06:10:51 -04:00
let length , p ;
let asc , end ;
let asc1 , end1 ;
let asc3 , end3 ;
const transform = function ( op1 , op2 , side ) {
const d = [ ] ;
text . _tc ( d , op1 , op2 , side ) ;
return d ;
} ;
const applySnapshot = ( snapshot , op ) => text . apply ( snapshot , op ) ;
const applyRanges = function ( rangesTracker , ops ) {
2020-05-06 06:11:22 -04:00
for ( const op of Array . from ( ops ) ) {
2020-05-06 06:10:51 -04:00
rangesTracker . applyOp ( op , { } ) ;
}
return rangesTracker ;
} ;
const commentsEqual = function ( comments1 , comments2 ) {
if ( comments1 . length !== comments2 . length ) { return false ; }
2020-05-06 06:11:22 -04:00
comments1 . sort ( ( a , b ) => {
2020-05-06 06:10:51 -04:00
if ( ( a . offset - b . offset ) === 0 ) {
return a . length - b . length ;
} else {
return a . offset - b . offset ;
}
} ) ;
2020-05-06 06:11:22 -04:00
comments2 . sort ( ( a , b ) => {
2020-05-06 06:10:51 -04:00
if ( ( a . offset - b . offset ) === 0 ) {
return a . length - b . length ;
} else {
return a . offset - b . offset ;
}
} ) ;
for ( let i = 0 ; i < comments1 . length ; i ++ ) {
const comment1 = comments1 [ i ] ;
const comment2 = comments2 [ i ] ;
if ( ( comment1 . offset !== comment2 . offset ) || ( comment1 . length !== comment2 . length ) ) {
return false ;
}
}
return true ;
} ;
const SNAPSHOT = "123" ;
const OPS = [ ] ;
// Insert ops
2020-05-06 06:11:22 -04:00
for ( p = 0 , end = SNAPSHOT . length , asc = end >= 0 ; asc ? p <= end : p >= end ; asc ? p ++ : p -- ) {
2020-05-06 06:10:51 -04:00
OPS . push ( { i : "a" , p } ) ;
OPS . push ( { i : "bc" , p } ) ;
}
2020-05-06 06:11:22 -04:00
for ( p = 0 , end1 = SNAPSHOT . length - 1 , asc1 = end1 >= 0 ; asc1 ? p <= end1 : p >= end1 ; asc1 ? p ++ : p -- ) {
2020-05-06 06:10:51 -04:00
var asc2 , end2 ;
2020-05-06 06:11:22 -04:00
for ( length = 1 , end2 = SNAPSHOT . length - p , asc2 = end2 >= 1 ; asc2 ? length <= end2 : length >= end2 ; asc2 ? length ++ : length -- ) {
2020-05-06 06:10:51 -04:00
OPS . push ( { d : SNAPSHOT . slice ( p , p + length ) , p } ) ;
}
}
2020-05-06 06:11:22 -04:00
for ( p = 0 , end3 = SNAPSHOT . length - 1 , asc3 = end3 >= 0 ; asc3 ? p <= end3 : p >= end3 ; asc3 ? p ++ : p -- ) {
2020-05-06 06:10:51 -04:00
var asc4 , end4 ;
2020-05-06 06:11:22 -04:00
for ( length = 1 , end4 = SNAPSHOT . length - p , asc4 = end4 >= 1 ; asc4 ? length <= end4 : length >= end4 ; asc4 ? length ++ : length -- ) {
2020-05-06 06:10:51 -04:00
OPS . push ( { c : SNAPSHOT . slice ( p , p + length ) , p , t : this . t } ) ;
}
}
return ( ( ) => {
const result = [ ] ;
for ( var op1 of Array . from ( OPS ) ) {
result . push ( ( ( ) => {
const result1 = [ ] ;
2020-05-06 06:11:22 -04:00
for ( const op2 of Array . from ( OPS ) ) {
2020-05-06 06:10:51 -04:00
const op1 _t = transform ( op1 , op2 , "left" ) ;
const op2 _t = transform ( op2 , op1 , "right" ) ;
const rt12 = new RangesTracker ( ) ;
const snapshot12 = applySnapshot ( applySnapshot ( SNAPSHOT , [ op1 ] ) , op2 _t ) ;
applyRanges ( rt12 , [ op1 ] ) ;
applyRanges ( rt12 , op2 _t ) ;
const rt21 = new RangesTracker ( ) ;
const snapshot21 = applySnapshot ( applySnapshot ( SNAPSHOT , [ op2 ] ) , op1 _t ) ;
applyRanges ( rt21 , [ op2 ] ) ;
applyRanges ( rt21 , op1 _t ) ;
if ( snapshot12 !== snapshot21 ) {
console . error ( { op1 , op2 , op1 _t , op2 _t , snapshot12 , snapshot21 } , "Ops are not consistent" ) ;
throw new Error ( "OT is inconsistent" ) ;
}
if ( ! commentsEqual ( rt12 . comments , rt21 . comments ) ) {
console . log ( rt12 . comments ) ;
console . log ( rt21 . comments ) ;
console . error ( { op1 , op2 , op1 _t , op2 _t , rt12 _comments : rt12 . comments , rt21 _comments : rt21 . comments } , "Comments are not consistent" ) ;
throw new Error ( "OT is inconsistent" ) ;
} else {
result1 . push ( undefined ) ;
}
}
return result1 ;
} ) ( ) ) ;
}
return result ;
} ) ( ) ;
2020-05-06 06:11:22 -04:00
} ) ; } ) ;
2020-05-06 06:10:51 -04:00
} ) ;