private void NodeTreeChecker(int chunkCount, int expectedNodeCount, uint expectedHeight, string expectedHash) { var r = new Random(Seed: 0); var actualChunks = Enumerable .Range(0, chunkCount) .Select(i => { unchecked { byte[] hash = new byte[32]; r.NextBytes(hash); hash[0] = (byte)i; hash[1] = (byte)(i >> 8); hash[2] = (byte)(i >> 16); hash[3] = (byte)(i >> 24); return(new ChunkInfo(0, 64 * 1024, hash)); } }) .ToList(); var node = DedupNodeTree.Create(actualChunks); Assert.Equal <string>(expectedHash, node.Hash.ToHex()); Assert.NotNull(node.Height); Assert.Equal(expectedHeight, node.Height.Value); var nodes = node.EnumerateInnerNodesDepthFirst().ToList(); var nodeChunks = node.EnumerateChunkLeafsInOrder().ToList(); var node2 = PackedDedupNodeTree.EnumerateTree(actualChunks).Last(); Assert.Equal(node.Hash.ToHex(), node2.Hash.ToHex()); foreach (var n in nodes) { var roundTrip = DedupNode.Deserialize(n.Serialize()); Assert.Equal(n.Hash, roundTrip.Hash, ByteArrayComparer.Instance); Assert.Equal(n.ChildNodes.Count, roundTrip.ChildNodes.Count); Assert.True( n.ChildNodes.Zip(roundTrip.ChildNodes, (e1, e2) => { if (e1.Type != e2.Type) { return(false); } else if (e1.TransitiveContentBytes != e2.TransitiveContentBytes) { return(false); } else if (!ByteArrayComparer.Instance.Equals(e1.Hash, e2.Hash)) { return(false); } return(true); }).All(result => result)); } Assert.Equal( actualChunks.Select(c => c.Hash.ToHex()), nodeChunks.Select(c => c.Hash.ToHex())); Assert.Equal(chunkCount, nodeChunks.Count); Assert.Equal(expectedNodeCount, nodes.Count); }
private void ChunksEnumeratedAsFileIsRead(Func <IChunker> chunkerFactory) { var chunks = new List <ChunkInfo>(); byte[] bytes = new byte[4 * Chunker.MinPushBufferSize]; var r = new Random(Seed: 0); r.NextBytes(bytes); using (var chunker = DedupNodeHashAlgorithm.CreateChunker()) using (var session = chunker.BeginChunking(chunk => { chunks.Add(chunk); })) { int pushSize = 2 * (int)Chunker.MinPushBufferSize; int lastChunkCount = 0; for (int i = 0; i < bytes.Length; i += pushSize) { session.PushBuffer(bytes, i, Math.Min(pushSize, bytes.Length - i)); Assert.True(chunks.Count > lastChunkCount); lastChunkCount = chunks.Count; } } string[] expectedChunkHashes = chunks.Select(c => c.Hash.ToHex()).ToArray(); DedupNode rootFromhash; string[] actualChunkHashes; using (var hasher = new DedupNodeHashAlgorithm()) { hasher.ComputeHash(bytes); rootFromhash = hasher.GetNode(); actualChunkHashes = rootFromhash.EnumerateChunkLeafsInOrder().Select(c => c.Hash.ToHex()).ToArray(); Assert.Equal(expectedChunkHashes, actualChunkHashes); } var seenNodes = new HashSet <byte[]>(chunks.Select(c => c.Hash), ByteArrayComparer.Instance); DedupNode?root = null; foreach (var node in PackedDedupNodeTree.EnumerateTree(chunks) .Where(n => n.Type != DedupNode.NodeType.ChunkLeaf)) { foreach (var child in node.ChildNodes) { Assert.True(seenNodes.Contains(child.Hash)); } Assert.True(seenNodes.Add(node.Hash)); root = node; } Assert.True(root.HasValue); // ReSharper disable once PossibleInvalidOperationException Assert.Equal(rootFromhash, root.Value); actualChunkHashes = root.Value.EnumerateChunkLeafsInOrder().Select(c => c.Hash.ToHex()).ToArray(); Assert.Equal(expectedChunkHashes, actualChunkHashes); }