blob: 79db1d8b50e2e849bc3d7f31164b0f9d1190385a [file]
'use strict';
const should = require('chai').should();
const { findPathToLeaf, removeLeafFromTree } = require('../../packages/node_modules/pouchdb-merge');
/*
1-a - 2-a -- 3-a - 4-a - 5-a - 6-a
\ \
\ 5-c - 6-c
3-b - 4-b
1-a = 1-9692d401ed2d3434827608278bdc36e3
2-a = 2-37aa033df08c21b4f56f1da2081e9e00
3-a = 3-df226cb9a2e5bdd3e6be009fd51f47c1
4-a = 4-6e94d345514a08620c3176eea080d3ec
5-a = 5-df4a81cd21c75c71974d96e88a68fc2f
6-a = 6-3f7f6c55c27bf54c009b661607a9fe05 leaf
5-c = 5-0b84bfea5508e2020feb07384714a987
6-c = 6-2d0ab4f4089a57c95d52bfd2d66b823d leaf
3-b = 3-43f6d5557d6de39488c64bb2c684ae7c
4-b = 4-a3b44168027079c2692a7d8eb35e9643 leaf
*/
const shortConflictedTree = [{
"pos": 1,
"ids": ["9692d401ed2d3434827608278bdc36e3", {}, [
["37aa033df08c21b4f56f1da2081e9e00", {}, [
["43f6d5557d6de39488c64bb2c684ae7c", {}, [
["a3b44168027079c2692a7d8eb35e9643", {}, []]
]],
["df226cb9a2e5bdd3e6be009fd51f47c1", {}, [
["6e94d345514a08620c3176eea080d3ec", {}, [
["0b84bfea5508e2020feb07384714a987", {}, [
["2d0ab4f4089a57c95d52bfd2d66b823d", {}, []]
]],
["df4a81cd21c75c71974d96e88a68fc2f", {}, [
["3f7f6c55c27bf54c009b661607a9fe05", {}, []]
]]
]]
]]
]]
]]
}];
// the same as the above shortConflictedTree, but without the 6-a leaf
const shortConflictedTreeWithout6a = [{
"pos": 1,
"ids": ["9692d401ed2d3434827608278bdc36e3", {}, [
["37aa033df08c21b4f56f1da2081e9e00", {}, [
["43f6d5557d6de39488c64bb2c684ae7c", {}, [
["a3b44168027079c2692a7d8eb35e9643", {}, []]
]],
["df226cb9a2e5bdd3e6be009fd51f47c1", {}, [
["6e94d345514a08620c3176eea080d3ec", {}, [
["0b84bfea5508e2020feb07384714a987", {}, [
["2d0ab4f4089a57c95d52bfd2d66b823d", {}, []]
]],
["df4a81cd21c75c71974d96e88a68fc2f", {}, []]
]]
]]
]]
]]
}];
// the same as the above shortConflictedTree, but without the 6-a & 5-a leaves
const shortConflictedTreeWithout6a5a = [{
"pos": 1,
"ids": ["9692d401ed2d3434827608278bdc36e3", {}, [
["37aa033df08c21b4f56f1da2081e9e00", {}, [
["43f6d5557d6de39488c64bb2c684ae7c", {}, [
["a3b44168027079c2692a7d8eb35e9643", {}, []]
]],
["df226cb9a2e5bdd3e6be009fd51f47c1", {}, [
["6e94d345514a08620c3176eea080d3ec", {}, [
["0b84bfea5508e2020feb07384714a987", {}, [
["2d0ab4f4089a57c95d52bfd2d66b823d", {}, []]
]]
]]
]]
]]
]]
}];
// the same as the above shortConflictedTree, but without the 6-a, 5-a, and 6-c leaves
const shortConflictedTreeWithout6a5a6c = [{
"pos": 1,
"ids": ["9692d401ed2d3434827608278bdc36e3", {}, [
["37aa033df08c21b4f56f1da2081e9e00", {}, [
["43f6d5557d6de39488c64bb2c684ae7c", {}, [
["a3b44168027079c2692a7d8eb35e9643", {}, []]
]],
["df226cb9a2e5bdd3e6be009fd51f47c1", {}, [
["6e94d345514a08620c3176eea080d3ec", {}, [
["0b84bfea5508e2020feb07384714a987", {}, []]
]]
]]
]]
]]
}];
// the same as the above shortConflictedTree, but without the 6-a, 5-a, 6-c, and 5-c leaves
const shortConflictedTreeWithout6a5a6c5c = [{
"pos": 1,
"ids": ["9692d401ed2d3434827608278bdc36e3", {}, [
["37aa033df08c21b4f56f1da2081e9e00", {}, [
["43f6d5557d6de39488c64bb2c684ae7c", {}, [
["a3b44168027079c2692a7d8eb35e9643", {}, []]
]],
["df226cb9a2e5bdd3e6be009fd51f47c1", {}, [
["6e94d345514a08620c3176eea080d3ec", {}, []]
]]
]]
]]
}];
/*
With revs_limit: 4, the shortConflictedTree from above becomes:
3-a - 4-a - 5-a - 6-a
\
5-c - 6-c
1-a - 2-a - 3-b - 4-b
1-a = 1-9692d401ed2d3434827608278bdc36e3
2-a = 2-37aa033df08c21b4f56f1da2081e9e00
3-a = 3-df226cb9a2e5bdd3e6be009fd51f47c1
4-a = 4-6e94d345514a08620c3176eea080d3ec
5-a = 5-df4a81cd21c75c71974d96e88a68fc2f
6-a = 6-3f7f6c55c27bf54c009b661607a9fe05 leaf
5-c = 5-0b84bfea5508e2020feb07384714a987
6-c = 6-2d0ab4f4089a57c95d52bfd2d66b823d leaf
3-b = 3-43f6d5557d6de39488c64bb2c684ae7c
4-b = 4-a3b44168027079c2692a7d8eb35e9643 leaf
*/
const shortConflictedTreeWithTwoRoots = [{
"pos": 1,
"ids": ["9692d401ed2d3434827608278bdc36e3", {}, [
["37aa033df08c21b4f56f1da2081e9e00", {}, [
["43f6d5557d6de39488c64bb2c684ae7c", {}, [
["a3b44168027079c2692a7d8eb35e9643", {}, []]
]]
]]
]]
}, {
"pos": 3,
"ids": ["df226cb9a2e5bdd3e6be009fd51f47c1", {}, [
["6e94d345514a08620c3176eea080d3ec", {}, [
["0b84bfea5508e2020feb07384714a987", {}, [
["2d0ab4f4089a57c95d52bfd2d66b823d", {}, []]
]],
["df4a81cd21c75c71974d96e88a68fc2f", {}, [
["3f7f6c55c27bf54c009b661607a9fe05", {}, []]
]]
]]
]]
}];
/*
With revs_limit: 4, just the main branch
(a doc without conflicts):
1-a - 2-a | 3-a - 4-a - 5-a - 6-a
truncated ^ here, 1-a - 2-a are missing. This
is functionally the same as traversing a
single-branch tree that hasn’t had a revs_limit
applied, so no need to test that separately.
3-a = 3-df226cb9a2e5bdd3e6be009fd51f47c1
4-a = 4-6e94d345514a08620c3176eea080d3ec
5-a = 5-df4a81cd21c75c71974d96e88a68fc2f
6-a = 6-3f7f6c55c27bf54c009b661607a9fe05 leaf
*/
const revsLimitedSingleBranchTree = [{
"pos": 3,
"ids": ["df226cb9a2e5bdd3e6be009fd51f47c1", {}, [
["6e94d345514a08620c3176eea080d3ec", {}, [
["df4a81cd21c75c71974d96e88a68fc2f", {}, [
["3f7f6c55c27bf54c009b661607a9fe05", {}, []]
]]
]]
]]
}];
describe('the findPathToLeaf util', function () {
it('finds the first branch in a conflicted tree', function () {
const path = findPathToLeaf(shortConflictedTree, '6-3f7f6c55c27bf54c009b661607a9fe05');
path.should.be.eql([
'6-3f7f6c55c27bf54c009b661607a9fe05',
'5-df4a81cd21c75c71974d96e88a68fc2f'
]);
});
it('finds the second branch in a conflicted tree', function () {
const path = findPathToLeaf(shortConflictedTree, '6-2d0ab4f4089a57c95d52bfd2d66b823d');
path.should.be.eql([
'6-2d0ab4f4089a57c95d52bfd2d66b823d',
'5-0b84bfea5508e2020feb07384714a987'
]);
});
it('finds the third branch in a conflicted tree', function () {
const path = findPathToLeaf(shortConflictedTree, '4-a3b44168027079c2692a7d8eb35e9643');
path.should.be.eql([
'4-a3b44168027079c2692a7d8eb35e9643',
'3-43f6d5557d6de39488c64bb2c684ae7c'
]);
});
it('finds the first branch in a multi-root conflicted tree', function () {
const path = findPathToLeaf(shortConflictedTreeWithTwoRoots, '6-3f7f6c55c27bf54c009b661607a9fe05');
path.should.be.eql([
'6-3f7f6c55c27bf54c009b661607a9fe05',
'5-df4a81cd21c75c71974d96e88a68fc2f'
]);
});
it('finds the second branch in a multi-root conflicted tree', function () {
const path = findPathToLeaf(shortConflictedTreeWithTwoRoots, '6-2d0ab4f4089a57c95d52bfd2d66b823d');
path.should.be.eql([
'6-2d0ab4f4089a57c95d52bfd2d66b823d',
'5-0b84bfea5508e2020feb07384714a987'
]);
});
it('finds the third branch in a multi-root conflicted tree and returns the entire subtree', function () {
const path = findPathToLeaf(shortConflictedTreeWithTwoRoots, '4-a3b44168027079c2692a7d8eb35e9643');
path.should.be.eql([
'4-a3b44168027079c2692a7d8eb35e9643',
'3-43f6d5557d6de39488c64bb2c684ae7c',
'2-37aa033df08c21b4f56f1da2081e9e00',
'1-9692d401ed2d3434827608278bdc36e3'
]);
});
it('returns the entire tree of a single-branch tree (truncated by revs_limit)', function () {
const path = findPathToLeaf(revsLimitedSingleBranchTree, '6-3f7f6c55c27bf54c009b661607a9fe05');
path.should.be.eql([
'6-3f7f6c55c27bf54c009b661607a9fe05',
'5-df4a81cd21c75c71974d96e88a68fc2f',
'4-6e94d345514a08620c3176eea080d3ec',
'3-df226cb9a2e5bdd3e6be009fd51f47c1'
]);
});
it('throws if the requested rev doesn’t exist', function () {
try {
findPathToLeaf(shortConflictedTree, '7-009b661607a9fe053f7f6c55c27bf54c');
should.fail();
} catch (error) {
error.message.should.equal("The requested revision does not exist");
}
});
it('throws if the requested rev is not a leaf', function () {
try {
findPathToLeaf(shortConflictedTree, '3-df226cb9a2e5bdd3e6be009fd51f47c1');
should.fail();
} catch (error) {
error.message.should.equal("The requested revision is not a leaf");
}
});
});
describe('the removeLeafFromTree util', function () {
it('removes a leaf from the tree', function () {
let tree = removeLeafFromTree(shortConflictedTree, "6-3f7f6c55c27bf54c009b661607a9fe05");
tree.should.be.deep.equal(shortConflictedTreeWithout6a);
tree = removeLeafFromTree(tree, "5-df4a81cd21c75c71974d96e88a68fc2f");
tree.should.be.deep.equal(shortConflictedTreeWithout6a5a);
tree = removeLeafFromTree(tree, "6-2d0ab4f4089a57c95d52bfd2d66b823d");
tree.should.be.deep.equal(shortConflictedTreeWithout6a5a6c);
tree = removeLeafFromTree(tree, "5-0b84bfea5508e2020feb07384714a987");
tree.should.be.deep.equal(shortConflictedTreeWithout6a5a6c5c);
});
it('should return an empty array if the entire tree is being deleted', function () {
const smallTree = [
{
pos: 1,
ids: [
"df226cb9a2e5bdd3e6be009fd51f47c1",
{
"status": "available"
},
[]
]
}
];
let tree = removeLeafFromTree(smallTree, "1-df226cb9a2e5bdd3e6be009fd51f47c1");
tree.should.be.deep.equal([]);
});
it('does not remove anything from the tree if the rev is not a leaf', function () {
const tree = removeLeafFromTree(shortConflictedTree, "5-df4a81cd21c75c71974d96e88a68fc2f");
tree.should.be.deep.equal(shortConflictedTree);
});
it('does not remove anything from the tree if the rev doesn\'t exist', function () {
const tree = removeLeafFromTree(shortConflictedTree, "foobar");
tree.should.be.deep.equal(shortConflictedTree);
});
it('removes leafs that are the first child of several siblings', function () {
let tree = [{
"pos": 1,
"ids": ["abcd", {}, [
["efgh", {}, [
["ijkl", {}, [
["mnop", {}, []]
]],
["qrst", {}, []]
]]
]]
}];
let purged = removeLeafFromTree(tree, "4-mnop");
purged.should.deep.equal([{
"pos": 1,
"ids": ["abcd", {}, [
["efgh", {}, [
["ijkl", {}, []],
["qrst", {}, []]
]]
]]
}]);
});
it('should remove respective leafs from a multi-root tree with revs_limit=4', function () {
let tree = removeLeafFromTree(
removeLeafFromTree(
shortConflictedTreeWithTwoRoots,
'6-3f7f6c55c27bf54c009b661607a9fe05'
),
'6-2d0ab4f4089a57c95d52bfd2d66b823d'
);
tree.should.be.deep.equal([{
"pos": 1,
"ids": ["9692d401ed2d3434827608278bdc36e3", {}, [
["37aa033df08c21b4f56f1da2081e9e00", {}, [
["43f6d5557d6de39488c64bb2c684ae7c", {}, [
["a3b44168027079c2692a7d8eb35e9643", {}, []]
]]
]]
]]
}, {
"pos": 3,
"ids": [
"df226cb9a2e5bdd3e6be009fd51f47c1", {}, [
["6e94d345514a08620c3176eea080d3ec", {}, [
["0b84bfea5508e2020feb07384714a987", {}, []],
["df4a81cd21c75c71974d96e88a68fc2f", {}, []]
]]
]
]
}]);
});
it('should remove respective leafs from a multi-root tree with revs_limit=3', function () {
// we're creating the tree below:
// root1 4-6e94 -> 5-df4a -> 6-3f7f
// └-------> 5-8d8c -> 6-65e0
// root2 4-a3b4
const limitedTree = [{
pos: 4,
ids: ["6e94", {}, [
["df4a", {}, [
["3f7f", {}, []],
]],
["8d8c", {}, [
["65e0", {}, []],
]],
]],
}, {
pos: 4,
ids: ["a3b4", {}, []],
}];
const tree = removeLeafFromTree(
removeLeafFromTree(
limitedTree,
'6-3f7f'
),
'5-df4a'
);
// and we’re expecting this after the purge
// root1 4-6e94
// └-------> 5-8d8c -> 6-65e0
// root2 4-a3b4
tree.should.be.deep.equal([
{ pos: 4, ids: [ '6e94', {}, [
["8d8c", {}, [["65e0", {}, []]]]
] ] },
{ pos: 4, ids: [ 'a3b4', {}, [] ] }
]);
});
});