| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- // @ts-check
- const { expect } = require('chai')
- const {
- RetainOp,
- ScanOp,
- InsertOp,
- RemoveOp,
- } = require('../lib/operation/scan_op')
- const { UnprocessableError, ApplyError } = require('../lib/errors')
- describe('ScanOp', function () {
- describe('fromJSON', function () {
- it('constructs a RetainOp from object', function () {
- const op = ScanOp.fromJSON({ r: 1 })
- expect(op).to.be.instanceOf(RetainOp)
- expect(/** @type {RetainOp} */ (op).length).to.equal(1)
- })
- it('constructs a RetainOp from number', function () {
- const op = ScanOp.fromJSON(2)
- expect(op).to.be.instanceOf(RetainOp)
- expect(/** @type {RetainOp} */ (op).length).to.equal(2)
- })
- it('constructs an InsertOp from string', function () {
- const op = ScanOp.fromJSON('abc')
- expect(op).to.be.instanceOf(InsertOp)
- expect(/** @type {InsertOp} */ (op).insertion).to.equal('abc')
- })
- it('constructs an InsertOp from object', function () {
- const op = ScanOp.fromJSON({ i: 'abc' })
- expect(op).to.be.instanceOf(InsertOp)
- expect(/** @type {InsertOp} */ (op).insertion).to.equal('abc')
- })
- it('constructs a RemoveOp from number', function () {
- const op = ScanOp.fromJSON(-2)
- expect(op).to.be.instanceOf(RemoveOp)
- expect(/** @type {RemoveOp} */ (op).length).to.equal(2)
- })
- it('throws an error for invalid input', function () {
- expect(() => ScanOp.fromJSON({})).to.throw(UnprocessableError)
- })
- it('throws an error for zero', function () {
- expect(() => ScanOp.fromJSON(0)).to.throw(UnprocessableError)
- })
- })
- })
- describe('RetainOp', function () {
- it('is equal to another RetainOp with the same length', function () {
- const op1 = new RetainOp(1)
- const op2 = new RetainOp(1)
- expect(op1.equals(op2)).to.be.true
- })
- it('is not equal to another RetainOp with a different length', function () {
- const op1 = new RetainOp(1)
- const op2 = new RetainOp(2)
- expect(op1.equals(op2)).to.be.false
- })
- it('is not equal to an InsertOp', function () {
- const op1 = new RetainOp(1)
- const op2 = new InsertOp('a')
- expect(op1.equals(op2)).to.be.false
- })
- it('is not equal to a RemoveOp', function () {
- const op1 = new RetainOp(1)
- const op2 = new RemoveOp(1)
- expect(op1.equals(op2)).to.be.false
- })
- it('can merge with another RetainOp', function () {
- const op1 = new RetainOp(1)
- const op2 = new RetainOp(2)
- expect(op1.canMergeWith(op2)).to.be.true
- op1.mergeWith(op2)
- expect(op1.equals(new RetainOp(3))).to.be.true
- })
- it('cannot merge with an InsertOp', function () {
- const op1 = new RetainOp(1)
- const op2 = new InsertOp('a')
- expect(op1.canMergeWith(op2)).to.be.false
- expect(() => op1.mergeWith(op2)).to.throw(Error)
- })
- it('cannot merge with a RemoveOp', function () {
- const op1 = new RetainOp(1)
- const op2 = new RemoveOp(1)
- expect(op1.canMergeWith(op2)).to.be.false
- expect(() => op1.mergeWith(op2)).to.throw(Error)
- })
- it('can be converted to JSON', function () {
- const op = new RetainOp(3)
- expect(op.toJSON()).to.equal(3)
- })
- it('adds to the length and cursor when applied to length', function () {
- const op = new RetainOp(3)
- const { length, inputCursor } = op.applyToLength({
- length: 10,
- inputCursor: 10,
- inputLength: 30,
- })
- expect(length).to.equal(13)
- expect(inputCursor).to.equal(13)
- })
- it('adds from the input to the result when applied', function () {
- const op = new RetainOp(3)
- const { result, inputCursor } = op.apply('abcdefghi', {
- result: 'xyz',
- inputCursor: 3,
- })
- expect(result).to.equal('xyzdef')
- expect(inputCursor).to.equal(6)
- })
- })
- describe('InsertOp', function () {
- it('is equal to another InsertOp with the same insertion', function () {
- const op1 = new InsertOp('a')
- const op2 = new InsertOp('a')
- expect(op1.equals(op2)).to.be.true
- })
- it('is not equal to another InsertOp with a different insertion', function () {
- const op1 = new InsertOp('a')
- const op2 = new InsertOp('b')
- expect(op1.equals(op2)).to.be.false
- })
- it('is not equal to a RetainOp', function () {
- const op1 = new InsertOp('a')
- const op2 = new RetainOp(1)
- expect(op1.equals(op2)).to.be.false
- })
- it('is not equal to a RemoveOp', function () {
- const op1 = new InsertOp('a')
- const op2 = new RemoveOp(1)
- expect(op1.equals(op2)).to.be.false
- })
- it('can merge with another InsertOp', function () {
- const op1 = new InsertOp('a')
- const op2 = new InsertOp('b')
- expect(op1.canMergeWith(op2)).to.be.true
- op1.mergeWith(op2)
- expect(op1.equals(new InsertOp('ab'))).to.be.true
- })
- it('cannot merge with a RetainOp', function () {
- const op1 = new InsertOp('a')
- const op2 = new RetainOp(1)
- expect(op1.canMergeWith(op2)).to.be.false
- expect(() => op1.mergeWith(op2)).to.throw(Error)
- })
- it('cannot merge with a RemoveOp', function () {
- const op1 = new InsertOp('a')
- const op2 = new RemoveOp(1)
- expect(op1.canMergeWith(op2)).to.be.false
- expect(() => op1.mergeWith(op2)).to.throw(Error)
- })
- it('can be converted to JSON', function () {
- const op = new InsertOp('a')
- expect(op.toJSON()).to.equal('a')
- })
- it('adds to the length when applied to length', function () {
- const op = new InsertOp('abc')
- const { length, inputCursor } = op.applyToLength({
- length: 10,
- inputCursor: 20,
- inputLength: 40,
- })
- expect(length).to.equal(13)
- expect(inputCursor).to.equal(20)
- })
- it('adds from the insertion to the result when applied', function () {
- const op = new InsertOp('ghi')
- const { result, inputCursor } = op.apply('abcdef', {
- result: 'xyz',
- inputCursor: 3,
- })
- expect(result).to.equal('xyzghi')
- expect(inputCursor).to.equal(3)
- })
- it('can apply a retain of the rest of the input', function () {
- const op = new RetainOp(10)
- const { length, inputCursor } = op.applyToLength({
- length: 10,
- inputCursor: 5,
- inputLength: 15,
- })
- expect(length).to.equal(20)
- expect(inputCursor).to.equal(15)
- })
- it('cannot apply to length if the input cursor is at the end', function () {
- const op = new RetainOp(10)
- expect(() =>
- op.applyToLength({
- length: 10,
- inputCursor: 10,
- inputLength: 10,
- })
- ).to.throw(ApplyError)
- })
- })
- describe('RemoveOp', function () {
- it('is equal to another RemoveOp with the same length', function () {
- const op1 = new RemoveOp(1)
- const op2 = new RemoveOp(1)
- expect(op1.equals(op2)).to.be.true
- })
- it('is not equal to another RemoveOp with a different length', function () {
- const op1 = new RemoveOp(1)
- const op2 = new RemoveOp(2)
- expect(op1.equals(op2)).to.be.false
- })
- it('is not equal to a RetainOp', function () {
- const op1 = new RemoveOp(1)
- const op2 = new RetainOp(1)
- expect(op1.equals(op2)).to.be.false
- })
- it('is not equal to an InsertOp', function () {
- const op1 = new RemoveOp(1)
- const op2 = new InsertOp('a')
- expect(op1.equals(op2)).to.be.false
- })
- it('can merge with another RemoveOp', function () {
- const op1 = new RemoveOp(1)
- const op2 = new RemoveOp(2)
- expect(op1.canMergeWith(op2)).to.be.true
- op1.mergeWith(op2)
- expect(op1.equals(new RemoveOp(3))).to.be.true
- })
- it('cannot merge with a RetainOp', function () {
- const op1 = new RemoveOp(1)
- const op2 = new RetainOp(1)
- expect(op1.canMergeWith(op2)).to.be.false
- expect(() => op1.mergeWith(op2)).to.throw(Error)
- })
- it('cannot merge with an InsertOp', function () {
- const op1 = new RemoveOp(1)
- const op2 = new InsertOp('a')
- expect(op1.canMergeWith(op2)).to.be.false
- expect(() => op1.mergeWith(op2)).to.throw(Error)
- })
- it('can be converted to JSON', function () {
- const op = new RemoveOp(3)
- expect(op.toJSON()).to.equal(-3)
- })
- it('adds to the input cursor when applied to length', function () {
- const op = new RemoveOp(3)
- const { length, inputCursor } = op.applyToLength({
- length: 10,
- inputCursor: 10,
- inputLength: 30,
- })
- expect(length).to.equal(10)
- expect(inputCursor).to.equal(13)
- })
- it('does not change the result and adds to the cursor when applied', function () {
- const op = new RemoveOp(3)
- const { result, inputCursor } = op.apply('abcdefghi', {
- result: 'xyz',
- inputCursor: 3,
- })
- expect(result).to.equal('xyz')
- expect(inputCursor).to.equal(6)
- })
- })
|