def test_boolean_negation(self):
        doc0 = Document()
        doc0.snapshot.set_snapshot(False)
        doc1 = self.doc1
        doc2 = self.doc2

        # whole document is a boolean. Just change that
        op1 = Op('bn', [])
        doc0.apply_op(op1)
        assert doc0.get_snapshot() is True
        doc0.apply_op(op1)
        assert doc0.get_snapshot() is False

        # boolean at some key/index
        op2 = Op('bn', [4])
        doc2.apply_op(op2)
        assert doc2.get_value([4]) == False
        doc2.apply_op(op2)
        assert doc2.get_value([4]) == True

        # boolean along some path
        path3 = ['fifth',2,'sixth']
        doc1.apply_op(Op('set', path3, val=True))
        op3 = Op('bn', path3)
        doc1.apply_op(op3)
        assert doc1.get_value(path3) == False
        doc1.apply_op(op3)
        assert doc1.get_value(path3) == True
    def test_array_delete(self):
        doc0 =  Document()
        doc0.snapshot.set_snapshot([])
        doc1 = self.doc1
        doc2 = self.doc2

        # can technically delete nothing from empty list. why not
        op1 = Op('ad', [], offset=0, val=0)
        doc0.apply_op(op1)
        assert doc0.get_snapshot() == []

        # remove one from list
        op2 = Op('ad', [], offset=1, val=1)
        doc2.apply_op(op2)
        assert doc2.get_value([1]) == 'normal, ol string'

        # from nested lists
        op3 = Op('ad', [2], offset=1, val=1)
        doc2.apply_op(op3)
        assert doc2.get_value([2]) == [['multi'],['array']]

        # delete multiple elements
        op4 = Op('ad', [], offset=0, val=4)
        doc2.apply_op(op4)
        assert doc2.get_snapshot() == [None, 42]

        # delete last in list:
        op5 = Op('ad', [], offset=1, val=1)
        doc2.apply_op(op5)
        assert doc2.get_snapshot() == [None]

        # in dicts
        op6 = Op('ad', ['fifth'], offset=2, val=2)
        doc1.apply_op(op6)
        assert doc1.get_value(['fifth']) == [55,66]
    def test_array_insert(self):
        doc0 = Document()
        doc0.snapshot.set_snapshot([])
        doc1 = self.doc1
        doc2 = self.doc2

        # whole doc is just an empty array. alter it
        op1 = Op('ai', [], val=['c'], offset=0)
        doc0.apply_op(op1)
        assert doc0.get_snapshot() == ['c']
        # insert at start
        op2 = Op('ai', [], val=['a'], offset=0)
        doc0.apply_op(op2)
        assert doc0.get_snapshot() == ['a', 'c']
        # insert at end
        op3 = Op('ai', [], val=['d'], offset=2)
        doc0.apply_op(op3)
        assert doc0.get_snapshot() == ['a', 'c', 'd']
        # insert several in the middle
        op4 = Op('ai', [], val=['b0', 'b1', 'b2'], offset=1)
        doc0.apply_op(op4)
        assert doc0.get_snapshot() == ['a', 'b0', 'b1', 'b2', 'c', 'd']

        # insert into some array deep in doc
        op5 = Op('ai', [3, 1], val=['a'], offset=1)
        doc2.apply_op(op5)
        assert doc2.get_value([3, 1]) == ['dimen', 'a']

        # again
        op6 = Op('ai', ['fifth'], val=['a'], offset=1)
        doc1.apply_op(op6)
        result6 = [55, 'a', 66, {'sixth': 'deep string'}, 'rw']
        assert doc1.get_value(['fifth']) == result6
    def test_number_add(self):
        doc0 =  Document()
        doc0.snapshot.set_snapshot(0)
        doc1 = self.doc1
        doc2 = self.doc2

        # whole document is just a number. Alter it.
        op1 = Op('na', [], val=5)
        doc0.apply_op(op1)
        assert doc0.get_snapshot() == 5

        # number deeper in doc
        op2 = Op('na', ['fifth',1], val=-100)
        doc1.apply_op(op2)
        assert doc1.get_value(['fifth',1]) == -34

        # funkier numbers accepted by JSON
        # int frac
        op3 = Op('na', ['fifth',1], val=34.5)
        doc1.apply_op(op3)
        assert doc1.get_value(['fifth',1]) == 0.5
    def test_move_in_root(self):
        doc = Document()
        doc.snapshot.set_snapshot('ABCDEFGHIJKLMNOPQRS')

        # move from higher index to lower
        op1 = Op('sm', [], offset=10, val=4, dest_path=[], dest_offset=2)
        doc.apply_op(op1)
        assert doc.get_snapshot() == 'ABKLMNCDEFGHIJOPQRS'

        # move from lower index to higher
        op2 = Op('sm', [], offset=2, val=4, dest_path=[], dest_offset=10)
        doc.apply_op(op2)
        assert doc.get_snapshot() == 'ABCDEFGHIJKLMNOPQRS'  # original value

        # move by one index
        op3 = Op('sm', [], offset=0, val=6, dest_path=[], dest_offset=1)
        doc.apply_op(op3)
        assert doc.get_snapshot() == 'GABCDEFHIJKLMNOPQRS'

        op4 = Op('sm', [], offset=10, val=9, dest_path=[], dest_offset=0)
        doc.apply_op(op4)
        assert doc.get_snapshot() == 'KLMNOPQRSGABCDEFHIJ'