From 71a799abdf1f3ec766c6522765210b73834cdfb5 Mon Sep 17 00:00:00 2001 From: Joshua Clark Date: Mon, 21 May 2018 00:14:46 -0400 Subject: [PATCH] 0.0.6 beta3 (#19) * beta4 * value based array class * incremental update * beta4 fix edge cases * correction this is beta3 * delete empty projs * remove unneeded using statements --- .../Analyzers/ArrayBasedTrie.cs | 169 +++++----- .../Analyzers/DictionaryBasedTrie.cs | 73 +++-- src/Mime-Detective/Analyzers/Helpers.cs | 14 + src/Mime-Detective/Analyzers/HybridTrie.cs | 292 ++++++++++++++++++ .../Analyzers/LinearCountingAnalyzer.cs | 9 +- src/Mime-Detective/FileType.cs | 2 +- src/Mime-Detective/Mime-Detective.csproj | 4 +- .../Data/Images/Thumbs.db | Bin 0 -> 43008 bytes test/Mime-Detective.Benchmarks/Program.cs | 52 +++- .../Data/Images/Thumbs.db | Bin 0 -> 43008 bytes .../Tests/Analyzers/ArrayBasedTrieTests.cs | 94 ++++++ .../Analyzers/DictionaryBasedTrieTests.cs | 95 +++++- .../Tests/Analyzers/HybridTrieTests.cs | 169 ++++++++++ .../Analyzers/LinearCountingAnalyzerTests.cs | 102 +++++- 14 files changed, 927 insertions(+), 148 deletions(-) create mode 100644 src/Mime-Detective/Analyzers/Helpers.cs create mode 100644 src/Mime-Detective/Analyzers/HybridTrie.cs create mode 100644 test/Mime-Detective.Benchmarks/Data/Images/Thumbs.db create mode 100644 test/Mime-Detective.Tests/Data/Images/Thumbs.db create mode 100644 test/Mime-Detective.Tests/Tests/Analyzers/HybridTrieTests.cs diff --git a/src/Mime-Detective/Analyzers/ArrayBasedTrie.cs b/src/Mime-Detective/Analyzers/ArrayBasedTrie.cs index d12f362..6e6722b 100644 --- a/src/Mime-Detective/Analyzers/ArrayBasedTrie.cs +++ b/src/Mime-Detective/Analyzers/ArrayBasedTrie.cs @@ -1,22 +1,22 @@ using System; using System.Collections.Generic; -using System.Text; -using System.Linq; namespace MimeDetective.Analyzers { public sealed class ArrayBasedTrie : IFileAnalyzer { - public const int NullStandInValue = 256; - public const int MaxNodeSize = 257; + private const int NullStandInValue = 256; + private const int MaxNodeSize = 257; - private List Nodes = new List(10); + private OffsetNode[] OffsetNodes = new OffsetNode[10]; + private int offsetNodesLength = 1; /// /// Constructs an empty ArrayBasedTrie, to add definitions /// public ArrayBasedTrie() { + OffsetNodes[0] = new OffsetNode(0); } /// @@ -28,67 +28,55 @@ public ArrayBasedTrie(IEnumerable types) if (types is null) throw new ArgumentNullException(nameof(types)); + OffsetNodes[0] = new OffsetNode(0); + foreach (var type in types) { if ((object)type != null) Insert(type); } - - Nodes = Nodes.OrderBy(x => x.Offset).ToList(); } + //TODO need tests for highestmatching count behavior public FileType Search(in ReadResult readResult) { FileType match = null; + int highestMatchingCount = 0; //iterate through offset nodes - for (int offsetNodeIndex = 0; offsetNodeIndex < Nodes.Count; offsetNodeIndex++) + for (int offsetNodeIndex = 0; offsetNodeIndex < offsetNodesLength; offsetNodeIndex++) { - //get offset node - var offsetNode = Nodes[offsetNodeIndex]; - + OffsetNode offsetNode = OffsetNodes[offsetNodeIndex]; int i = offsetNode.Offset; - byte value = readResult.Array[i]; - - var node = offsetNode.Children[value]; - - if (node is null) - { - node = offsetNode.Children[NullStandInValue]; - - if (node is null) - break; - } - - if ((object)node.Record != null) - match = node.Record; + Node[] prevNode = offsetNode.Children; - i++; - - //iterate through the current trie - for (; i < readResult.ReadLength; i++) + while (i < readResult.ReadLength) { - value = readResult.Array[i]; - - var prevNode = node; - node = node.Children[value]; + int currentVal = readResult.Array[i]; + Node node = prevNode[currentVal]; - if (node is null) + if (node.Children == null) { - node = prevNode.Children[NullStandInValue]; + node = prevNode[NullStandInValue]; - if (node is null) + if (node.Children is null) break; } - if ((object)node.Record != null) + //increment here + i++; + + //collect the record + if (i > highestMatchingCount && (object)node.Record != null) + { match = node.Record; - } + highestMatchingCount = i; + } - if ((object)match != null) - break; + prevNode = node.Children; + } } - + return match; } @@ -97,90 +85,83 @@ public void Insert(FileType type) if (type is null) throw new ArgumentNullException(nameof(type)); - OffsetNode match = null; + ref OffsetNode match = ref OffsetNodes[0]; + bool matchFound = false; - foreach (var offsetNode in Nodes) + for (int offsetNodeIndex = 0; offsetNodeIndex < offsetNodesLength; offsetNodeIndex++) { - if (offsetNode.Offset == type.HeaderOffset) + ref var currentNode = ref OffsetNodes[offsetNodeIndex]; + + if (currentNode.Offset == type.HeaderOffset) { - match = offsetNode; + match = ref currentNode; + matchFound = true; break; } } - if (match is null) + if (!matchFound) { - match = new OffsetNode(type.HeaderOffset); - Nodes.Add(match); - } - - match.Insert(type); - } - - private sealed class OffsetNode - { - public readonly ushort Offset; - public readonly Node[] Children; + int newNodePos = offsetNodesLength; - public OffsetNode(ushort offset) - { - if (offset > (MimeTypes.MaxHeaderSize - 1)) - throw new ArgumentException("Offset cannot be greater than MaxHeaderSize - 1"); + if (newNodePos >= OffsetNodes.Length) + { + int newOffsetNodeCount = OffsetNodes.Length * 2 + 1; + var newOffsetNodes = new OffsetNode[newOffsetNodeCount]; + Array.Copy(OffsetNodes, newOffsetNodes, offsetNodesLength); + OffsetNodes = newOffsetNodes; + } - Offset = offset; - Children = new Node[MaxNodeSize]; + match = ref OffsetNodes[newNodePos]; + match = new OffsetNode(type.HeaderOffset); + offsetNodesLength++; } - public void Insert(FileType type) + Node[] prevNode = match.Children; + + for (int i = 0; i < type.Header.Length; i++) { - int i = 0; byte? value = type.Header[i]; int arrayPos = value ?? NullStandInValue; + ref Node node = ref prevNode[arrayPos]; - var node = Children[arrayPos]; - - if (node is null) + if (node.Children is null) { - node = new Node(value); - Children[arrayPos] = node; - } + FileType record = null; - i++; + if (i == type.Header.Length - 1) + record = type; - for (; i < type.Header.Length; i++) - { - value = type.Header[i]; - arrayPos = value ?? NullStandInValue; - var prevNode = node; - node = node.Children[arrayPos]; - - if (node is null) - { - var newNode = new Node(value); + node = new Node(record); + } - if (i == type.Header.Length - 1) - newNode.Record = type; + prevNode = node.Children; + } + } + + private readonly struct OffsetNode + { + public readonly ushort Offset; + public readonly Node[] Children; - node = prevNode.Children[arrayPos] = newNode; - } - } + public OffsetNode(ushort offset) + { + Offset = offset; + Children = new Node[MaxNodeSize]; } } - private sealed class Node + private struct Node { - public readonly Node[] Children; + public Node[] Children; //if complete node then this not null public FileType Record; - public readonly byte? Value; - - public Node(byte? value) + public Node(FileType record) { - Value = value; Children = new Node[MaxNodeSize]; - Record = null; + Record = record; } } } diff --git a/src/Mime-Detective/Analyzers/DictionaryBasedTrie.cs b/src/Mime-Detective/Analyzers/DictionaryBasedTrie.cs index a37909c..884d787 100644 --- a/src/Mime-Detective/Analyzers/DictionaryBasedTrie.cs +++ b/src/Mime-Detective/Analyzers/DictionaryBasedTrie.cs @@ -38,12 +38,14 @@ public FileType Search(in ReadResult readResult) { FileType match = null; var enumerator = Nodes.GetEnumerator(); + int highestMatchingCount = 0; - while (match is null && enumerator.MoveNext()) + while (enumerator.MoveNext()) { Node node = enumerator.Current.Value; + int i = node.Value; - for (int i = node.Value; i < readResult.ReadLength; i++) + while (i < readResult.ReadLength) { Node prevNode = node; @@ -51,12 +53,14 @@ public FileType Search(in ReadResult readResult) && !prevNode.Children.TryGetValue(NullStandInValue, out node)) break; - if ((object)node.Record != null) + i++; + + if (i > highestMatchingCount && (object)node.Record != null) + { match = node.Record; + highestMatchingCount = i; + } } - - if ((object)match != null) - break; } return match; @@ -73,50 +77,45 @@ public void Insert(FileType type) Nodes.Add(type.HeaderOffset, offsetNode); } - offsetNode.Insert(type); - } - - private sealed class Node - { - public readonly Dictionary Children = new Dictionary(); + int i = 0; + ushort value = type.Header[i] ?? NullStandInValue; - //if complete node then this not null - public FileType Record; - - public readonly ushort Value; - - public Node(ushort value) + if (!offsetNode.Children.TryGetValue(value, out Node node)) { - Value = value; + node = new Node(value); + offsetNode.Children.Add(value, node); } - public void Insert(FileType type) + i++; + + for (; i < type.Header.Length; i++) { - int i = 0; - ushort value = type.Header[i] ?? NullStandInValue; + value = type.Header[i] ?? NullStandInValue; - if (!Children.TryGetValue(value, out Node node)) + if (!node.Children.ContainsKey(value)) { - node = new Node(value); - Children.Add(value, node); + Node newNode = new Node(value); + node.Children.Add(value, newNode); } - i++; + node = node.Children[value]; + } - for (; i < type.Header.Length; i++) - { - value = type.Header[i] ?? NullStandInValue; + node.Record = type; + } - if (!node.Children.ContainsKey(value)) - { - Node newNode = new Node(value); - node.Children.Add(value, newNode); - } + private sealed class Node + { + public Dictionary Children = new Dictionary(); - node = node.Children[value]; - } + //if complete node then this not null + public FileType Record; + + public ushort Value; - node.Record = type; + public Node(ushort value) + { + Value = value; } } } diff --git a/src/Mime-Detective/Analyzers/Helpers.cs b/src/Mime-Detective/Analyzers/Helpers.cs new file mode 100644 index 0000000..66dda53 --- /dev/null +++ b/src/Mime-Detective/Analyzers/Helpers.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace MimeDetective.Analyzers +{ + internal static class ThrowHelpers + { + public static void GreaterThanMaxHeaderSize() + { + throw new ArgumentException("Offset cannot be greater than MaxHeaderSize - 1"); + } + } +} diff --git a/src/Mime-Detective/Analyzers/HybridTrie.cs b/src/Mime-Detective/Analyzers/HybridTrie.cs new file mode 100644 index 0000000..c9d1b0e --- /dev/null +++ b/src/Mime-Detective/Analyzers/HybridTrie.cs @@ -0,0 +1,292 @@ +using System; +using System.Collections.Generic; + +namespace MimeDetective.Analyzers +{ + public sealed class HybridTrie : IFileAnalyzer + { + private const int DefaultSize = 7; + private const ushort NullStandInValue = 256; + private const int MaxNodeSize = 257; + + private OffsetNode[] OffsetNodes = new OffsetNode[10]; + private int offsetNodesLength = 1; + + private readonly struct OffsetNode + { + public readonly ushort Offset; + public readonly Node[] Children; + + public OffsetNode(ushort offset) + { + Offset = offset; + Children = new Node[MaxNodeSize]; + } + } + + /// + /// Constructs an empty DictionaryBasedTrie + /// + public HybridTrie() + { + OffsetNodes[0] = new OffsetNode(0); + } + + /// + /// Constructs a DictionaryBasedTrie from an Enumerable of FileTypes + /// + /// + public HybridTrie(IEnumerable types) + { + if (types is null) + throw new ArgumentNullException(nameof(types)); + + OffsetNodes[0] = new OffsetNode(0); + + foreach (var type in types) + { + Insert(type); + } + } + + public FileType Search(in ReadResult readResult) + { + FileType match = null; + int highestMatchingCount = 0; + + //iterate through offset nodes + for (int offsetNodeIndex = 0; offsetNodeIndex < offsetNodesLength; offsetNodeIndex++) + { + //get offset node + var offsetNode = OffsetNodes[offsetNodeIndex]; + int i = offsetNode.Offset; + + if (!(i < readResult.ReadLength)) + continue; + + Node node = offsetNode.Children[readResult.Array[i]]; + + if (node == null) + { + node = offsetNode.Children[NullStandInValue]; + + if (node is null) + continue; + } + + i++; + + if (i > highestMatchingCount && (object)node.Record != null) + { + match = node.Record; + highestMatchingCount = i; + } + + while (i < readResult.ReadLength) + { + Node prevNode = node; + + if (!prevNode.TryGetValue(readResult.Array[i], out node) + && !prevNode.TryGetValue(NullStandInValue, out node)) + break; + + i++; + + if (i > highestMatchingCount && (object)node.Record != null) + { + match = node.Record; + highestMatchingCount = i; + } + } + } + + return match; + } + + public void Insert(FileType type) + { + if (type is null) + throw new ArgumentNullException(nameof(type)); + + ref OffsetNode match = ref OffsetNodes[0]; + bool matchFound = false; + + for (int offsetNodeIndex = 0; offsetNodeIndex < offsetNodesLength; offsetNodeIndex++) + { + ref var currentNode = ref OffsetNodes[offsetNodeIndex]; + + if (currentNode.Offset == type.HeaderOffset) + { + match = ref currentNode; + matchFound = true; + break; + } + } + + //handle expanding collection + if (!matchFound) + { + int newNodePos = offsetNodesLength; + + if (newNodePos >= OffsetNodes.Length) + { + int newOffsetNodeCount = OffsetNodes.Length * 2 + 1; + var newOffsetNodes = new OffsetNode[newOffsetNodeCount]; + Array.Copy(OffsetNodes, newOffsetNodes, offsetNodesLength); + OffsetNodes = newOffsetNodes; + } + + match = ref OffsetNodes[newNodePos]; + match = new OffsetNode(type.HeaderOffset); + offsetNodesLength++; + } + + int i = 0; + byte? value = type.Header[i]; + int arrayPos = value ?? NullStandInValue; + + var node = match.Children[arrayPos]; + + if (node is null) + { + node = new Node((ushort)arrayPos); + match.Children[arrayPos] = node; + } + + i++; + + for (; i < type.Header.Length; i++) + { + value = type.Header[i]; + arrayPos = value ?? NullStandInValue; + var prevNode = node; + + if (!node.TryGetValue((ushort)arrayPos, out node)) + { + node = new Node((ushort)arrayPos); + + //if (i == type.Header.Length - 1) + // node.Record = type; + + prevNode.Add((ushort)arrayPos, node); + } + } + + node.Record = type; + } + + private sealed class Node + { + //if complete node then this not null + public FileType Record; + + public ushort Value; + + private sealed class Entry + { + //public ushort _key; + public Node _value; + public Entry _next; + } + + private Entry[] _buckets; + private int _numEntries; + + public Node(ushort value) + { + Value = value; + Clear(DefaultSize); + } + + public bool TryGetValue(ushort key, out Node value) + { + Entry entry = Find(key); + + if (entry != null) + { + value = entry._value; + return true; + } + + value = null; + return false; + } + + public void Add(ushort key, Node value) + { + Entry entry = Find(key); + + if (entry != null) + throw new ArgumentException("entry already added"); + + UncheckedAdd(key, value); + } + + public void Clear(int capacity = DefaultSize) + { + _buckets = new Entry[capacity]; + _numEntries = 0; + } + + private Entry Find(ushort key) + { + int bucket = GetBucket(key); + Entry entry = _buckets[bucket]; + while (entry != null) + { + if (key == entry._value.Value) + return entry; + + entry = entry._next; + } + return null; + } + + private Entry UncheckedAdd(ushort key, Node value) + { + Entry entry = new Entry + { + _value = value + }; + + int bucket = GetBucket(key); + entry._next = _buckets[bucket]; + _buckets[bucket] = entry; + + _numEntries++; + if (_numEntries > (_buckets.Length * 2)) + ExpandBuckets(); + + return entry; + } + + private void ExpandBuckets() + { + int newNumBuckets = _buckets.Length * 2 + 1; + Entry[] newBuckets = new Entry[newNumBuckets]; + for (int i = 0; i < _buckets.Length; i++) + { + Entry entry = _buckets[i]; + while (entry != null) + { + Entry nextEntry = entry._next; + + int bucket = GetBucket(entry._value.Value, newNumBuckets); + entry._next = newBuckets[bucket]; + newBuckets[bucket] = entry; + + entry = nextEntry; + } + } + _buckets = newBuckets; + } + + private int GetBucket(ushort key, int numBuckets = 0) + { + int h = key; + h &= 0x7fffffff; + return (h % (numBuckets == 0 ? _buckets.Length : numBuckets)); + } + } + } +} \ No newline at end of file diff --git a/src/Mime-Detective/Analyzers/LinearCountingAnalyzer.cs b/src/Mime-Detective/Analyzers/LinearCountingAnalyzer.cs index 7bba089..441d39e 100644 --- a/src/Mime-Detective/Analyzers/LinearCountingAnalyzer.cs +++ b/src/Mime-Detective/Analyzers/LinearCountingAnalyzer.cs @@ -57,18 +57,19 @@ public FileType Search(in ReadResult readResult) uint matchingCount = 0; int iOffset = type.HeaderOffset; - int readLength = iOffset + type.Header.Length; + int readEnd = iOffset + type.Header.Length; - if (readLength > readResult.ReadLength) + if (readEnd > readResult.ReadLength) continue; - for (int i = 0; iOffset < readLength; i++, iOffset++) + for (int i = 0; iOffset < readEnd; i++, iOffset++) { if (type.Header[i] is null || type.Header[i].Value == readResult.Array[iOffset]) matchingCount++; } - if (type.Header.Length == matchingCount && matchingCount > highestMatchingCount) + //TODO should this be default behavior + if (type.Header.Length == matchingCount && matchingCount >= highestMatchingCount) { highestMatchingType = type; highestMatchingCount = matchingCount; diff --git a/src/Mime-Detective/FileType.cs b/src/Mime-Detective/FileType.cs index bd2cdee..8c6ad80 100644 --- a/src/Mime-Detective/FileType.cs +++ b/src/Mime-Detective/FileType.cs @@ -32,7 +32,7 @@ public FileType(byte?[] header, string extension, string mime, ushort offset = 0 Header = header ?? throw new ArgumentNullException(nameof(header), $"cannot be null, {nameof(FileType)} needs file header data"); if (offset > (MimeTypes.MaxHeaderSize - 1)) - throw new ArgumentException("Header Offset cannot exceed Max Header Size - 1"); + throw new ArgumentException($"Header Offset cannot exceed Max Header Size {MimeTypes.MaxHeaderSize} - 1"); HeaderOffset = offset; Extension = extension; diff --git a/src/Mime-Detective/Mime-Detective.csproj b/src/Mime-Detective/Mime-Detective.csproj index 4b4f737..93369c9 100644 --- a/src/Mime-Detective/Mime-Detective.csproj +++ b/src/Mime-Detective/Mime-Detective.csproj @@ -18,8 +18,8 @@ 0.0.6.0 0.0.6.0 - See beta2 PR - 0.0.6.0-beta2 + See beta3 PR + 0.0.6.0-beta3 true diff --git a/test/Mime-Detective.Benchmarks/Data/Images/Thumbs.db b/test/Mime-Detective.Benchmarks/Data/Images/Thumbs.db new file mode 100644 index 0000000000000000000000000000000000000000..d41bb0c7d4fd29d100d1be4ad8cc50d2b2dcece2 GIT binary patch literal 43008 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 fileTypes = new List(); + + for (int i = 0; i < 560; i++) + { + var bytes = new byte?[1]; + FileType fileType = new FileType(bytes, "ext" + i, "app/ext" + 1, (ushort)i); + analyzer.Insert(fileType); + fileTypes.Add(fileType); + } + + for (int i = 0; i < 560; i++) + { + var bytes = new byte[i + 1]; + ReadResult readResult = new ReadResult(bytes, bytes.Length); + FileType type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileTypes[i], type); + Assert.Equal(i, type.HeaderOffset); + } + } } } diff --git a/test/Mime-Detective.Tests/Tests/Analyzers/DictionaryBasedTrieTests.cs b/test/Mime-Detective.Tests/Tests/Analyzers/DictionaryBasedTrieTests.cs index b3f90f3..56a5fee 100644 --- a/test/Mime-Detective.Tests/Tests/Analyzers/DictionaryBasedTrieTests.cs +++ b/test/Mime-Detective.Tests/Tests/Analyzers/DictionaryBasedTrieTests.cs @@ -28,7 +28,6 @@ public void EnumerableConstructor() //assertion here just to have Assert.NotNull(analyzer); - Assert.Throws(() => new DictionaryBasedTrie(null)); analyzer.Insert(MimeTypes.WORD); @@ -57,7 +56,16 @@ public void Insert() [InlineData("./Data/Zip/images.zip", "zip")] [InlineData("./Data/Zip/imagesBy7zip.zip", "zip")] [InlineData("./Data/images/test.gif", "gif")] + [InlineData("./Data/images/test.jpg", "jpg")] + [InlineData("./Data/images/test.ico", "ico")] + [InlineData("./Data/images/test.png", "png")] + [InlineData("./Data/images/test.bmp", "bmp")] [InlineData("./Data/Audio/wavVLC.wav", "wav")] + [InlineData("./Data/Audio/flacVLC.flac", "flac")] + [InlineData("./Data/Audio/mp3ID3Test1.mp3", "mp3")] + [InlineData("./Data/Audio/mp3ID3Test2.mp3", "mp3")] + [InlineData("./Data/Assemblies/ManagedExe.exe", "exe")] + [InlineData("./Data/Assemblies/ManagedDLL.dll", "dll")] public async Task Search(string path, string ext) { var analyzer = new DictionaryBasedTrie(MimeTypes.Types); @@ -72,5 +80,90 @@ public async Task Search(string path, string ext) Assert.NotNull(type); Assert.Contains(ext, type.Extension); } + + [Fact] + public void InsertZeroOffsetFirstWildCard() + { + var analyzer = new DictionaryBasedTrie(); + FileType fileType = new FileType(new byte?[1], "ext", "app/ext", 0); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[1], 1); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(0, type.HeaderOffset); + } + + [Fact] + public void InsertLastOffsetWildCard() + { + var analyzer = new DictionaryBasedTrie(); + FileType fileType = new FileType(new byte?[1], "ext", "app/ext", 559); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[560], 560); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(559, type.HeaderOffset); + } + + [Fact] + public void InsertLastOffsetWildCardFull() + { + var analyzer = new DictionaryBasedTrie(); + FileType fileType = new FileType(new byte?[560], "ext", "app/ext", 559); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[1120], 1120); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(559, type.HeaderOffset); + } + + [Fact] + public void IncrementalInsertSearchBoundries() + { + var analyzer = new DictionaryBasedTrie(); + + for (int i = 0; i < 560; i++) + { + var bytes = new byte?[1]; + FileType fileType = new FileType(bytes, "ext" + i, "app/ext" + 1, (ushort)i); + analyzer.Insert(fileType); + + var bytes1 = new byte[i + 1]; + ReadResult readResult = new ReadResult(bytes1, bytes1.Length); + FileType type = analyzer.Search(in readResult); + + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(i, type.HeaderOffset); + } + } + + [Fact] + public void InsertSearchBoundries() + { + var analyzer = new DictionaryBasedTrie(); + List fileTypes = new List(); + + for (int i = 0; i < 560; i++) + { + var bytes = new byte?[1]; + FileType fileType = new FileType(bytes, "ext" + i, "app/ext" + 1, (ushort)i); + analyzer.Insert(fileType); + fileTypes.Add(fileType); + } + + for (int i = 0; i < 560; i++) + { + var bytes = new byte[i + 1]; + ReadResult readResult = new ReadResult(bytes, bytes.Length); + FileType type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileTypes[i], type); + Assert.Equal(i, type.HeaderOffset); + } + } } } diff --git a/test/Mime-Detective.Tests/Tests/Analyzers/HybridTrieTests.cs b/test/Mime-Detective.Tests/Tests/Analyzers/HybridTrieTests.cs new file mode 100644 index 0000000..d16aa67 --- /dev/null +++ b/test/Mime-Detective.Tests/Tests/Analyzers/HybridTrieTests.cs @@ -0,0 +1,169 @@ +using MimeDetective.Analyzers; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace MimeDetective.Tests.Analyzers +{ + public class HybridTrieTests + { + [Fact] + public void DefaultConstructor() + { + var analyzer = new HybridTrie(); + + //assertion here just to have + Assert.NotNull(analyzer); + + analyzer.Insert(MimeTypes.ZIP); + } + + [Fact] + public void EnumerableConstructor() + { + var analyzer = new HybridTrie(MimeTypes.Types); + + //assertion here just to have + Assert.NotNull(analyzer); + Assert.Throws(() => new HybridTrie(null)); + + analyzer.Insert(MimeTypes.WORD); + } + + [Fact] + public void Insert() + { + var analyzer = new HybridTrie(); + Assert.Throws(() => analyzer.Insert(null)); + + foreach (var fileType in MimeTypes.Types) + { + analyzer.Insert(fileType); + } + + analyzer.Insert(MimeTypes.WORD); + } + + [Theory] + [InlineData("./Data/Documents/XlsExcel2016.xls", "xls")] + [InlineData("./Data/Documents/PptPowerpoint2016.ppt", "ppt")] + [InlineData("./Data/Documents/DocWord2016.doc", "doc")] + [InlineData("./Data/Documents/PdfWord2016.pdf", "pdf")] + [InlineData("./Data/Zip/empty.zip", "zip")] + [InlineData("./Data/Zip/images.zip", "zip")] + [InlineData("./Data/Zip/imagesBy7zip.zip", "zip")] + [InlineData("./Data/images/test.gif", "gif")] + [InlineData("./Data/images/test.jpg", "jpg")] + [InlineData("./Data/images/test.ico", "ico")] + [InlineData("./Data/images/test.png", "png")] + [InlineData("./Data/images/test.bmp", "bmp")] + [InlineData("./Data/Audio/wavVLC.wav", "wav")] + [InlineData("./Data/Audio/flacVLC.flac", "flac")] + [InlineData("./Data/Audio/mp3ID3Test1.mp3", "mp3")] + [InlineData("./Data/Audio/mp3ID3Test2.mp3", "mp3")] + [InlineData("./Data/Assemblies/ManagedExe.exe", "exe")] + [InlineData("./Data/Assemblies/ManagedDLL.dll", "dll")] + public async Task Search(string path, string ext) + { + var analyzer = new HybridTrie(MimeTypes.Types); + FileInfo file = new FileInfo(path); + FileType type = null; + + using (ReadResult result = await ReadResult.ReadFileHeaderAsync(file)) + { + type = analyzer.Search(in result); + } + + Assert.NotNull(type); + Assert.Contains(ext, type.Extension); + } + + [Fact] + public void InsertZeroOffsetFirstWildCard() + { + var analyzer = new HybridTrie(); + FileType fileType = new FileType(new byte?[1], "ext", "app/ext", 0); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[1], 1); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(0, type.HeaderOffset); + } + + [Fact] + public void InsertLastOffsetWildCard() + { + var analyzer = new HybridTrie(); + FileType fileType = new FileType(new byte?[1], "ext", "app/ext", 559); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[560], 560); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(559, type.HeaderOffset); + } + + [Fact] + public void InsertLastOffsetWildCardFull() + { + var analyzer = new HybridTrie(); + FileType fileType = new FileType(new byte?[560], "ext", "app/ext", 559); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[1120], 1120); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(559, type.HeaderOffset); + } + + [Fact] + public void IncrementalInsertSearchBoundries() + { + var analyzer = new HybridTrie(); + + for (int i = 0; i < 560; i++) + { + var bytes = new byte?[1]; + FileType fileType = new FileType(bytes, "ext" + i, "app/ext" + 1, (ushort)i); + analyzer.Insert(fileType); + + var bytes1 = new byte[i + 1]; + ReadResult readResult = new ReadResult(bytes1, bytes1.Length); + FileType type = analyzer.Search(in readResult); + + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(i, type.HeaderOffset); + } + } + + [Fact] + public void InsertSearchBoundries() + { + var analyzer = new HybridTrie(); + List fileTypes = new List(); + + for (int i = 0; i < 560; i++) + { + var bytes = new byte?[1]; + FileType fileType = new FileType(bytes, "ext" + i, "app/ext" + 1, (ushort)i); + analyzer.Insert(fileType); + fileTypes.Add(fileType); + } + + for (int i = 0; i < 560; i++) + { + var bytes = new byte[i + 1]; + ReadResult readResult = new ReadResult(bytes, bytes.Length); + FileType type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileTypes[i], type); + Assert.Equal(i, type.HeaderOffset); + } + } + } +} diff --git a/test/Mime-Detective.Tests/Tests/Analyzers/LinearCountingAnalyzerTests.cs b/test/Mime-Detective.Tests/Tests/Analyzers/LinearCountingAnalyzerTests.cs index f742ca5..8a2d868 100644 --- a/test/Mime-Detective.Tests/Tests/Analyzers/LinearCountingAnalyzerTests.cs +++ b/test/Mime-Detective.Tests/Tests/Analyzers/LinearCountingAnalyzerTests.cs @@ -13,7 +13,7 @@ public class LinearCountingAnalyzerTests [Fact] public void DefaultConstructor() { - LinearCountingAnalyzer analyzer = new LinearCountingAnalyzer(); + var analyzer = new LinearCountingAnalyzer(); //assertion here just to have Assert.NotNull(analyzer); @@ -24,7 +24,7 @@ public void DefaultConstructor() [Fact] public void EnumerableConstructor() { - LinearCountingAnalyzer analyzer = new LinearCountingAnalyzer(MimeTypes.Types); + var analyzer = new LinearCountingAnalyzer(MimeTypes.Types); //assertion here just to have Assert.NotNull(analyzer); @@ -36,7 +36,7 @@ public void EnumerableConstructor() [Fact] public void Insert() { - LinearCountingAnalyzer analyzer = new LinearCountingAnalyzer(); + var analyzer = new LinearCountingAnalyzer(); Assert.Throws(() => analyzer.Insert(null)); foreach (var fileType in MimeTypes.Types) @@ -56,10 +56,19 @@ public void Insert() [InlineData("./Data/Zip/images.zip", "zip")] [InlineData("./Data/Zip/imagesBy7zip.zip", "zip")] [InlineData("./Data/images/test.gif", "gif")] + [InlineData("./Data/images/test.jpg", "jpg")] + [InlineData("./Data/images/test.ico", "ico")] + [InlineData("./Data/images/test.png", "png")] + [InlineData("./Data/images/test.bmp", "bmp")] [InlineData("./Data/Audio/wavVLC.wav", "wav")] + [InlineData("./Data/Audio/flacVLC.flac", "flac")] + [InlineData("./Data/Audio/mp3ID3Test1.mp3", "mp3")] + [InlineData("./Data/Audio/mp3ID3Test2.mp3", "mp3")] + [InlineData("./Data/Assemblies/ManagedExe.exe", "exe")] + [InlineData("./Data/Assemblies/ManagedDLL.dll", "dll")] public async Task Search(string path, string ext) { - LinearCountingAnalyzer analyzer = new LinearCountingAnalyzer(MimeTypes.Types); + var analyzer = new LinearCountingAnalyzer(MimeTypes.Types); FileInfo file = new FileInfo(path); FileType type = null; @@ -71,5 +80,90 @@ public async Task Search(string path, string ext) Assert.NotNull(type); Assert.Contains(ext, type.Extension); } + + [Fact] + public void InsertZeroOffsetFirstWildCard() + { + var analyzer = new LinearCountingAnalyzer(); + FileType fileType = new FileType(new byte?[1], "ext", "app/ext", 0); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[1], 1); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(0, type.HeaderOffset); + } + + [Fact] + public void InsertLastOffsetWildCard() + { + var analyzer = new LinearCountingAnalyzer(); + FileType fileType = new FileType(new byte?[1], "ext", "app/ext", 559); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[560], 560); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(559, type.HeaderOffset); + } + + [Fact] + public void InsertLastOffsetWildCardFull() + { + var analyzer = new LinearCountingAnalyzer(); + FileType fileType = new FileType(new byte?[560], "ext", "app/ext", 559); + analyzer.Insert(fileType); + ReadResult readResult = new ReadResult(new byte[1120], 1120); + var type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(559, type.HeaderOffset); + } + + [Fact] + public void IncrementalInsertSearchBoundries() + { + var analyzer = new LinearCountingAnalyzer(); + + for (int i = 0; i < 560; i++) + { + var bytes = new byte?[1]; + FileType fileType = new FileType(bytes, "ext" + i, "app/ext" + i, (ushort)i); + analyzer.Insert(fileType); + + var bytes1 = new byte[i + 1]; + ReadResult readResult = new ReadResult(bytes1, bytes1.Length); + FileType type = analyzer.Search(in readResult); + + Assert.NotNull(type); + Assert.Same(fileType, type); + Assert.Equal(i, type.HeaderOffset); + } + } + + [Fact] + public void InsertSearchBoundries() + { + var analyzer = new LinearCountingAnalyzer(); + List fileTypes = new List(); + + for (int i = 0; i < 560; i++) + { + var bytes = new byte?[1]; + FileType fileType = new FileType(bytes, "ext" + i, "app/ext" + i, (ushort)i); + analyzer.Insert(fileType); + fileTypes.Add(fileType); + } + + for (int i = 0; i < 560; i++) + { + var bytes = new byte[i + 1]; + ReadResult readResult = new ReadResult(bytes, bytes.Length); + FileType type = analyzer.Search(in readResult); + Assert.NotNull(type); + Assert.Same(fileTypes[i], type); + Assert.Equal(i, type.HeaderOffset); + } + } } }